Deleted Added
full compact
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 ---