kern_descrip.c (191113) | kern_descrip.c (192080) |
---|---|
1/*- 2 * Copyright (c) 1982, 1986, 1989, 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * (c) UNIX System Laboratories, Inc. 5 * All or some portions of this file are derived from material licensed 6 * to the University of California by American Telephone and Telegraph 7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8 * the permission of UNIX System Laboratories, Inc. --- 21 unchanged lines hidden (view full) --- 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * @(#)kern_descrip.c 8.6 (Berkeley) 4/19/94 35 */ 36 37#include <sys/cdefs.h> | 1/*- 2 * Copyright (c) 1982, 1986, 1989, 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * (c) UNIX System Laboratories, Inc. 5 * All or some portions of this file are derived from material licensed 6 * to the University of California by American Telephone and Telegraph 7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8 * the permission of UNIX System Laboratories, Inc. --- 21 unchanged lines hidden (view full) --- 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * @(#)kern_descrip.c 8.6 (Berkeley) 4/19/94 35 */ 36 37#include <sys/cdefs.h> |
38__FBSDID("$FreeBSD: head/sys/kern/kern_descrip.c 191113 2009-04-15 19:10:37Z jhb $"); | 38__FBSDID("$FreeBSD: head/sys/kern/kern_descrip.c 192080 2009-05-14 03:24:22Z jeff $"); |
39 40#include "opt_compat.h" 41#include "opt_ddb.h" 42#include "opt_ktrace.h" 43 44#include <sys/param.h> 45#include <sys/systm.h> 46 --- 73 unchanged lines hidden (view full) --- 120#define NDSLOTS(x) (((x) + NDENTRIES - 1) / NDENTRIES) 121 122/* 123 * Storage required per open file descriptor. 124 */ 125#define OFILESIZE (sizeof(struct file *) + sizeof(char)) 126 127/* | 39 40#include "opt_compat.h" 41#include "opt_ddb.h" 42#include "opt_ktrace.h" 43 44#include <sys/param.h> 45#include <sys/systm.h> 46 --- 73 unchanged lines hidden (view full) --- 120#define NDSLOTS(x) (((x) + NDENTRIES - 1) / NDENTRIES) 121 122/* 123 * Storage required per open file descriptor. 124 */ 125#define OFILESIZE (sizeof(struct file *) + sizeof(char)) 126 127/* |
128 * Storage to hold unused ofiles that need to be reclaimed. 129 */ 130struct freetable { 131 struct file **ft_table; 132 SLIST_ENTRY(freetable) ft_next; 133}; 134 135/* |
|
128 * Basic allocation of descriptors: 129 * one of the above, plus arrays for NDFILE descriptors. 130 */ 131struct filedesc0 { 132 struct filedesc fd_fd; 133 /* | 136 * Basic allocation of descriptors: 137 * one of the above, plus arrays for NDFILE descriptors. 138 */ 139struct filedesc0 { 140 struct filedesc fd_fd; 141 /* |
142 * ofiles which need to be reclaimed on free. 143 */ 144 SLIST_HEAD(,freetable) fd_free; 145 /* |
|
134 * These arrays are used when the number of open files is 135 * <= NDFILE, and are then pointed to by the pointers above. 136 */ 137 struct file *fd_dfiles[NDFILE]; 138 char fd_dfileflags[NDFILE]; 139 NDSLOTTYPE fd_dmap[NDSLOTS(NDFILE)]; 140}; 141 --- 1121 unchanged lines hidden (view full) --- 1263/* 1264 * Grow the file table to accomodate (at least) nfd descriptors. This may 1265 * block and drop the filedesc lock, but it will reacquire it before 1266 * returning. 1267 */ 1268static void 1269fdgrowtable(struct filedesc *fdp, int nfd) 1270{ | 146 * These arrays are used when the number of open files is 147 * <= NDFILE, and are then pointed to by the pointers above. 148 */ 149 struct file *fd_dfiles[NDFILE]; 150 char fd_dfileflags[NDFILE]; 151 NDSLOTTYPE fd_dmap[NDSLOTS(NDFILE)]; 152}; 153 --- 1121 unchanged lines hidden (view full) --- 1275/* 1276 * Grow the file table to accomodate (at least) nfd descriptors. This may 1277 * block and drop the filedesc lock, but it will reacquire it before 1278 * returning. 1279 */ 1280static void 1281fdgrowtable(struct filedesc *fdp, int nfd) 1282{ |
1283 struct filedesc0 *fdp0; 1284 struct freetable *fo; |
|
1271 struct file **ntable; | 1285 struct file **ntable; |
1286 struct file **otable; |
|
1272 char *nfileflags; 1273 int nnfiles, onfiles; 1274 NDSLOTTYPE *nmap; 1275 1276 FILEDESC_XLOCK_ASSERT(fdp); 1277 1278 KASSERT(fdp->fd_nfiles > 0, 1279 ("zero-length file table")); 1280 1281 /* compute the size of the new table */ 1282 onfiles = fdp->fd_nfiles; 1283 nnfiles = NDSLOTS(nfd) * NDENTRIES; /* round up */ 1284 if (nnfiles <= onfiles) 1285 /* the table is already large enough */ 1286 return; 1287 1288 /* allocate a new table and (if required) new bitmaps */ 1289 FILEDESC_XUNLOCK(fdp); | 1287 char *nfileflags; 1288 int nnfiles, onfiles; 1289 NDSLOTTYPE *nmap; 1290 1291 FILEDESC_XLOCK_ASSERT(fdp); 1292 1293 KASSERT(fdp->fd_nfiles > 0, 1294 ("zero-length file table")); 1295 1296 /* compute the size of the new table */ 1297 onfiles = fdp->fd_nfiles; 1298 nnfiles = NDSLOTS(nfd) * NDENTRIES; /* round up */ 1299 if (nnfiles <= onfiles) 1300 /* the table is already large enough */ 1301 return; 1302 1303 /* allocate a new table and (if required) new bitmaps */ 1304 FILEDESC_XUNLOCK(fdp); |
1290 ntable = malloc(nnfiles * OFILESIZE, | 1305 ntable = malloc((nnfiles * OFILESIZE) + sizeof(struct freetable), |
1291 M_FILEDESC, M_ZERO | M_WAITOK); 1292 nfileflags = (char *)&ntable[nnfiles]; 1293 if (NDSLOTS(nnfiles) > NDSLOTS(onfiles)) 1294 nmap = malloc(NDSLOTS(nnfiles) * NDSLOTSIZE, 1295 M_FILEDESC, M_ZERO | M_WAITOK); 1296 else 1297 nmap = NULL; 1298 FILEDESC_XLOCK(fdp); --- 7 unchanged lines hidden (view full) --- 1306 /* we lost the race, but that's OK */ 1307 free(ntable, M_FILEDESC); 1308 if (nmap != NULL) 1309 free(nmap, M_FILEDESC); 1310 return; 1311 } 1312 bcopy(fdp->fd_ofiles, ntable, onfiles * sizeof(*ntable)); 1313 bcopy(fdp->fd_ofileflags, nfileflags, onfiles); | 1306 M_FILEDESC, M_ZERO | M_WAITOK); 1307 nfileflags = (char *)&ntable[nnfiles]; 1308 if (NDSLOTS(nnfiles) > NDSLOTS(onfiles)) 1309 nmap = malloc(NDSLOTS(nnfiles) * NDSLOTSIZE, 1310 M_FILEDESC, M_ZERO | M_WAITOK); 1311 else 1312 nmap = NULL; 1313 FILEDESC_XLOCK(fdp); --- 7 unchanged lines hidden (view full) --- 1321 /* we lost the race, but that's OK */ 1322 free(ntable, M_FILEDESC); 1323 if (nmap != NULL) 1324 free(nmap, M_FILEDESC); 1325 return; 1326 } 1327 bcopy(fdp->fd_ofiles, ntable, onfiles * sizeof(*ntable)); 1328 bcopy(fdp->fd_ofileflags, nfileflags, onfiles); |
1314 if (onfiles > NDFILE) 1315 free(fdp->fd_ofiles, M_FILEDESC); 1316 fdp->fd_ofiles = ntable; | 1329 otable = fdp->fd_ofiles; |
1317 fdp->fd_ofileflags = nfileflags; | 1330 fdp->fd_ofileflags = nfileflags; |
1331 fdp->fd_ofiles = ntable; 1332 /* 1333 * We must preserve ofiles until the process exits because we can't 1334 * be certain that no threads have references to the old table via 1335 * _fget(). 1336 */ 1337 if (onfiles > NDFILE) { 1338 fo = (struct freetable *)&otable[onfiles]; 1339 fdp0 = (struct filedesc0 *)fdp; 1340 fo->ft_table = otable; 1341 SLIST_INSERT_HEAD(&fdp0->fd_free, fo, ft_next); 1342 } |
|
1318 if (NDSLOTS(nnfiles) > NDSLOTS(onfiles)) { 1319 bcopy(fdp->fd_map, nmap, NDSLOTS(onfiles) * sizeof(*nmap)); 1320 if (NDSLOTS(onfiles) > NDSLOTS(NDFILE)) 1321 free(fdp->fd_map, M_FILEDESC); 1322 fdp->fd_map = nmap; 1323 } 1324 fdp->fd_nfiles = nnfiles; 1325} --- 181 unchanged lines hidden (view full) --- 1507 fdp->fd_holdcnt++; 1508 mtx_unlock(&fdesc_mtx); 1509 return (fdp); 1510} 1511 1512static void 1513fddrop(struct filedesc *fdp) 1514{ | 1343 if (NDSLOTS(nnfiles) > NDSLOTS(onfiles)) { 1344 bcopy(fdp->fd_map, nmap, NDSLOTS(onfiles) * sizeof(*nmap)); 1345 if (NDSLOTS(onfiles) > NDSLOTS(NDFILE)) 1346 free(fdp->fd_map, M_FILEDESC); 1347 fdp->fd_map = nmap; 1348 } 1349 fdp->fd_nfiles = nnfiles; 1350} --- 181 unchanged lines hidden (view full) --- 1532 fdp->fd_holdcnt++; 1533 mtx_unlock(&fdesc_mtx); 1534 return (fdp); 1535} 1536 1537static void 1538fddrop(struct filedesc *fdp) 1539{ |
1540 struct filedesc0 *fdp0; 1541 struct freetable *ft; |
|
1515 int i; 1516 1517 mtx_lock(&fdesc_mtx); 1518 i = --fdp->fd_holdcnt; 1519 mtx_unlock(&fdesc_mtx); 1520 if (i > 0) 1521 return; 1522 1523 FILEDESC_LOCK_DESTROY(fdp); | 1542 int i; 1543 1544 mtx_lock(&fdesc_mtx); 1545 i = --fdp->fd_holdcnt; 1546 mtx_unlock(&fdesc_mtx); 1547 if (i > 0) 1548 return; 1549 1550 FILEDESC_LOCK_DESTROY(fdp); |
1551 fdp0 = (struct filedesc0 *)fdp; 1552 while ((ft = SLIST_FIRST(&fdp0->fd_free)) != NULL) { 1553 SLIST_REMOVE_HEAD(&fdp0->fd_free, ft_next); 1554 free(ft->ft_table, M_FILEDESC); 1555 } |
|
1524 free(fdp, M_FILEDESC); 1525} 1526 1527/* 1528 * Share a filedesc structure. 1529 */ 1530struct filedesc * 1531fdshare(struct filedesc *fdp) --- 485 unchanged lines hidden (view full) --- 2017finit(struct file *fp, u_int flag, short type, void *data, struct fileops *ops) 2018{ 2019 fp->f_data = data; 2020 fp->f_flag = flag; 2021 fp->f_type = type; 2022 atomic_store_rel_ptr((volatile uintptr_t *)&fp->f_ops, (uintptr_t)ops); 2023} 2024 | 1556 free(fdp, M_FILEDESC); 1557} 1558 1559/* 1560 * Share a filedesc structure. 1561 */ 1562struct filedesc * 1563fdshare(struct filedesc *fdp) --- 485 unchanged lines hidden (view full) --- 2049finit(struct file *fp, u_int flag, short type, void *data, struct fileops *ops) 2050{ 2051 fp->f_data = data; 2052 fp->f_flag = flag; 2053 fp->f_type = type; 2054 atomic_store_rel_ptr((volatile uintptr_t *)&fp->f_ops, (uintptr_t)ops); 2055} 2056 |
2057struct file * 2058fget_unlocked(struct filedesc *fdp, int fd) 2059{ 2060 struct file *fp; 2061 u_int count; |
|
2025 | 2062 |
2063 if (fd < 0 || fd >= fdp->fd_nfiles) 2064 return (NULL); 2065 /* 2066 * Fetch the descriptor locklessly. We avoid fdrop() races by 2067 * never raising a refcount above 0. To accomplish this we have 2068 * to use a cmpset loop rather than an atomic_add. The descriptor 2069 * must be re-verified once we acquire a reference to be certain 2070 * that the identity is still correct and we did not lose a race 2071 * due to preemption. 2072 */ 2073 for (;;) { 2074 fp = fdp->fd_ofiles[fd]; 2075 if (fp == NULL) 2076 break; 2077 count = fp->f_count; 2078 if (count == 0) 2079 continue; 2080 if (atomic_cmpset_int(&fp->f_count, count, count + 1) != 1) 2081 continue; 2082 if (fp == ((struct file *volatile*)fdp->fd_ofiles)[fd]) 2083 break; 2084 fdrop(fp, curthread); 2085 } 2086 2087 return (fp); 2088} 2089 |
|
2026/* 2027 * Extract the file pointer associated with the specified descriptor for the 2028 * current user process. 2029 * 2030 * If the descriptor doesn't exist or doesn't match 'flags', EBADF is 2031 * returned. 2032 * | 2090/* 2091 * Extract the file pointer associated with the specified descriptor for the 2092 * current user process. 2093 * 2094 * If the descriptor doesn't exist or doesn't match 'flags', EBADF is 2095 * returned. 2096 * |
2033 * If 'hold' is set (non-zero) the file's refcount will be bumped on return. 2034 * It should be dropped with fdrop(). If it is not set, then the refcount 2035 * will not be bumped however the thread's filedesc struct will be returned 2036 * locked (for fgetsock). 2037 * | |
2038 * If an error occured the non-zero error is returned and *fpp is set to | 2097 * If an error occured the non-zero error is returned and *fpp is set to |
2039 * NULL. Otherwise *fpp is set and zero is returned. | 2098 * NULL. Otherwise *fpp is held and set and zero is returned. Caller is 2099 * responsible for fdrop(). |
2040 */ 2041static __inline int | 2100 */ 2101static __inline int |
2042_fget(struct thread *td, int fd, struct file **fpp, int flags, int hold) | 2102_fget(struct thread *td, int fd, struct file **fpp, int flags) |
2043{ 2044 struct filedesc *fdp; 2045 struct file *fp; 2046 2047 *fpp = NULL; 2048 if (td == NULL || (fdp = td->td_proc->p_fd) == NULL) 2049 return (EBADF); | 2103{ 2104 struct filedesc *fdp; 2105 struct file *fp; 2106 2107 *fpp = NULL; 2108 if (td == NULL || (fdp = td->td_proc->p_fd) == NULL) 2109 return (EBADF); |
2050 FILEDESC_SLOCK(fdp); 2051 if ((fp = fget_locked(fdp, fd)) == NULL || fp->f_ops == &badfileops) { 2052 FILEDESC_SUNLOCK(fdp); | 2110 if ((fp = fget_unlocked(fdp, fd)) == NULL) |
2053 return (EBADF); | 2111 return (EBADF); |
2112 if (fp->f_ops == &badfileops) { 2113 fdrop(fp, td); 2114 return (EBADF); |
|
2054 } | 2115 } |
2055 | |
2056 /* 2057 * FREAD and FWRITE failure return EBADF as per POSIX. 2058 * 2059 * Only one flag, or 0, may be specified. 2060 */ | 2116 /* 2117 * FREAD and FWRITE failure return EBADF as per POSIX. 2118 * 2119 * Only one flag, or 0, may be specified. 2120 */ |
2061 if (flags == FREAD && (fp->f_flag & FREAD) == 0) { 2062 FILEDESC_SUNLOCK(fdp); | 2121 if ((flags == FREAD && (fp->f_flag & FREAD) == 0) || 2122 (flags == FWRITE && (fp->f_flag & FWRITE) == 0)) { 2123 fdrop(fp, td); |
2063 return (EBADF); 2064 } | 2124 return (EBADF); 2125 } |
2065 if (flags == FWRITE && (fp->f_flag & FWRITE) == 0) { 2066 FILEDESC_SUNLOCK(fdp); 2067 return (EBADF); 2068 } 2069 if (hold) { 2070 fhold(fp); 2071 FILEDESC_SUNLOCK(fdp); 2072 } | |
2073 *fpp = fp; 2074 return (0); 2075} 2076 2077int 2078fget(struct thread *td, int fd, struct file **fpp) 2079{ 2080 | 2126 *fpp = fp; 2127 return (0); 2128} 2129 2130int 2131fget(struct thread *td, int fd, struct file **fpp) 2132{ 2133 |
2081 return(_fget(td, fd, fpp, 0, 1)); | 2134 return(_fget(td, fd, fpp, 0)); |
2082} 2083 2084int 2085fget_read(struct thread *td, int fd, struct file **fpp) 2086{ 2087 | 2135} 2136 2137int 2138fget_read(struct thread *td, int fd, struct file **fpp) 2139{ 2140 |
2088 return(_fget(td, fd, fpp, FREAD, 1)); | 2141 return(_fget(td, fd, fpp, FREAD)); |
2089} 2090 2091int 2092fget_write(struct thread *td, int fd, struct file **fpp) 2093{ 2094 | 2142} 2143 2144int 2145fget_write(struct thread *td, int fd, struct file **fpp) 2146{ 2147 |
2095 return(_fget(td, fd, fpp, FWRITE, 1)); | 2148 return(_fget(td, fd, fpp, FWRITE)); |
2096} 2097 2098/* 2099 * Like fget() but loads the underlying vnode, or returns an error if the 2100 * descriptor does not represent a vnode. Note that pipes use vnodes but 2101 * never have VM objects. The returned vnode will be vref()'d. 2102 * 2103 * XXX: what about the unused flags ? 2104 */ 2105static __inline int 2106_fgetvp(struct thread *td, int fd, struct vnode **vpp, int flags) 2107{ 2108 struct file *fp; 2109 int error; 2110 2111 *vpp = NULL; | 2149} 2150 2151/* 2152 * Like fget() but loads the underlying vnode, or returns an error if the 2153 * descriptor does not represent a vnode. Note that pipes use vnodes but 2154 * never have VM objects. The returned vnode will be vref()'d. 2155 * 2156 * XXX: what about the unused flags ? 2157 */ 2158static __inline int 2159_fgetvp(struct thread *td, int fd, struct vnode **vpp, int flags) 2160{ 2161 struct file *fp; 2162 int error; 2163 2164 *vpp = NULL; |
2112 if ((error = _fget(td, fd, &fp, flags, 0)) != 0) | 2165 if ((error = _fget(td, fd, &fp, flags)) != 0) |
2113 return (error); 2114 if (fp->f_vnode == NULL) { 2115 error = EINVAL; 2116 } else { 2117 *vpp = fp->f_vnode; 2118 vref(*vpp); 2119 } | 2166 return (error); 2167 if (fp->f_vnode == NULL) { 2168 error = EINVAL; 2169 } else { 2170 *vpp = fp->f_vnode; 2171 vref(*vpp); 2172 } |
2120 FILEDESC_SUNLOCK(td->td_proc->p_fd); | 2173 fdrop(fp, td); 2174 |
2121 return (error); 2122} 2123 2124int 2125fgetvp(struct thread *td, int fd, struct vnode **vpp) 2126{ 2127 2128 return (_fgetvp(td, fd, vpp, 0)); --- 30 unchanged lines hidden (view full) --- 2159fgetsock(struct thread *td, int fd, struct socket **spp, u_int *fflagp) 2160{ 2161 struct file *fp; 2162 int error; 2163 2164 *spp = NULL; 2165 if (fflagp != NULL) 2166 *fflagp = 0; | 2175 return (error); 2176} 2177 2178int 2179fgetvp(struct thread *td, int fd, struct vnode **vpp) 2180{ 2181 2182 return (_fgetvp(td, fd, vpp, 0)); --- 30 unchanged lines hidden (view full) --- 2213fgetsock(struct thread *td, int fd, struct socket **spp, u_int *fflagp) 2214{ 2215 struct file *fp; 2216 int error; 2217 2218 *spp = NULL; 2219 if (fflagp != NULL) 2220 *fflagp = 0; |
2167 if ((error = _fget(td, fd, &fp, 0, 0)) != 0) | 2221 if ((error = _fget(td, fd, &fp, 0)) != 0) |
2168 return (error); 2169 if (fp->f_type != DTYPE_SOCKET) { 2170 error = ENOTSOCK; 2171 } else { 2172 *spp = fp->f_data; 2173 if (fflagp) 2174 *fflagp = fp->f_flag; 2175 SOCK_LOCK(*spp); 2176 soref(*spp); 2177 SOCK_UNLOCK(*spp); 2178 } | 2222 return (error); 2223 if (fp->f_type != DTYPE_SOCKET) { 2224 error = ENOTSOCK; 2225 } else { 2226 *spp = fp->f_data; 2227 if (fflagp) 2228 *fflagp = fp->f_flag; 2229 SOCK_LOCK(*spp); 2230 soref(*spp); 2231 SOCK_UNLOCK(*spp); 2232 } |
2179 FILEDESC_SUNLOCK(td->td_proc->p_fd); | 2233 fdrop(fp, td); 2234 |
2180 return (error); 2181} 2182 2183/* 2184 * Drop the reference count on the socket and XXX release the SX lock in the 2185 * future. The last reference closes the socket. 2186 * 2187 * Note: fputsock() is deprecated, see comment for fgetsock(). --- 954 unchanged lines hidden (view full) --- 3142 __DEVOLATILE(int *, &openfiles), 0, "System-wide number of open files"); 3143 3144/* ARGSUSED*/ 3145static void 3146filelistinit(void *dummy) 3147{ 3148 3149 file_zone = uma_zcreate("Files", sizeof(struct file), NULL, NULL, | 2235 return (error); 2236} 2237 2238/* 2239 * Drop the reference count on the socket and XXX release the SX lock in the 2240 * future. The last reference closes the socket. 2241 * 2242 * Note: fputsock() is deprecated, see comment for fgetsock(). --- 954 unchanged lines hidden (view full) --- 3197 __DEVOLATILE(int *, &openfiles), 0, "System-wide number of open files"); 3198 3199/* ARGSUSED*/ 3200static void 3201filelistinit(void *dummy) 3202{ 3203 3204 file_zone = uma_zcreate("Files", sizeof(struct file), NULL, NULL, |
3150 NULL, NULL, UMA_ALIGN_PTR, 0); | 3205 NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE); |
3151 mtx_init(&sigio_lock, "sigio lock", NULL, MTX_DEF); 3152 mtx_init(&fdesc_mtx, "fdesc", NULL, MTX_DEF); 3153} 3154SYSINIT(select, SI_SUB_LOCK, SI_ORDER_FIRST, filelistinit, NULL); 3155 3156/*-------------------------------------------------------------------*/ 3157 3158static int --- 110 unchanged lines hidden --- | 3206 mtx_init(&sigio_lock, "sigio lock", NULL, MTX_DEF); 3207 mtx_init(&fdesc_mtx, "fdesc", NULL, MTX_DEF); 3208} 3209SYSINIT(select, SI_SUB_LOCK, SI_ORDER_FIRST, filelistinit, NULL); 3210 3211/*-------------------------------------------------------------------*/ 3212 3213static int --- 110 unchanged lines hidden --- |