diff options
author | rwatson <rwatson@FreeBSD.org> | 2007-04-04 09:11:34 +0000 |
---|---|---|
committer | rwatson <rwatson@FreeBSD.org> | 2007-04-04 09:11:34 +0000 |
commit | 765a83fd795f79d2911ebf3b158ddc368ea0a0f6 (patch) | |
tree | 8805b4674ed3429ddf05f19fd5eb0813fb7884aa /sys/kern | |
parent | 37016d3a5dbecc7b8ef5733b5f47471e3418f9ea (diff) | |
download | FreeBSD-src-765a83fd795f79d2911ebf3b158ddc368ea0a0f6.zip FreeBSD-src-765a83fd795f79d2911ebf3b158ddc368ea0a0f6.tar.gz |
Replace custom file descriptor array sleep lock constructed using a mutex
and flags with an sxlock. This leads to a significant and measurable
performance improvement as a result of access to shared locking for
frequent lookup operations, reduced general overhead, and reduced overhead
in the event of contention. All of these are imported for threaded
applications where simultaneous access to a shared file descriptor array
occurs frequently. Kris has reported 2x-4x transaction rate improvements
on 8-core MySQL benchmarks; smaller improvements can be expected for many
workloads as a result of reduced overhead.
- Generally eliminate the distinction between "fast" and regular
acquisisition of the filedesc lock; the plan is that they will now all
be fast. Change all locking instances to either shared or exclusive
locks.
- Correct a bug (pointed out by kib) in fdfree() where previously msleep()
was called without the mutex held; sx_sleep() is now always called with
the sxlock held exclusively.
- Universally hold the struct file lock over changes to struct file,
rather than the filedesc lock or no lock. Always update the f_ops
field last. A further memory barrier is required here in the future
(discussed with jhb).
- Improve locking and reference management in linux_at(), which fails to
properly acquire vnode references before using vnode pointers. Annotate
improper use of vn_fullpath(), which will be replaced at a future date.
In fcntl(), we conservatively acquire an exclusive lock, even though in
some cases a shared lock may be sufficient, which should be revisited.
The dropping of the filedesc lock in fdgrowtable() is no longer required
as the sxlock can be held over the sleep operation; we should consider
removing that (pointed out by attilio).
Tested by: kris
Discussed with: jhb, kris, attilio, jeff
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/kern_descrip.c | 344 | ||||
-rw-r--r-- | sys/kern/kern_event.c | 18 | ||||
-rw-r--r-- | sys/kern/kern_fork.c | 4 | ||||
-rw-r--r-- | sys/kern/subr_witness.c | 2 | ||||
-rw-r--r-- | sys/kern/sys_generic.c | 23 | ||||
-rw-r--r-- | sys/kern/uipc_mqueue.c | 21 | ||||
-rw-r--r-- | sys/kern/uipc_syscalls.c | 23 | ||||
-rw-r--r-- | sys/kern/uipc_usrreq.c | 19 | ||||
-rw-r--r-- | sys/kern/vfs_cache.c | 8 | ||||
-rw-r--r-- | sys/kern/vfs_lookup.c | 4 | ||||
-rw-r--r-- | sys/kern/vfs_mount.c | 4 | ||||
-rw-r--r-- | sys/kern/vfs_syscalls.c | 51 |
12 files changed, 264 insertions, 257 deletions
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index b4e9e4c..2b91db7 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -211,9 +211,11 @@ fdisused(struct filedesc *fdp, int fd) static void fdused(struct filedesc *fdp, int fd) { - FILEDESC_LOCK_ASSERT(fdp, MA_OWNED); + + FILEDESC_XLOCK_ASSERT(fdp); KASSERT(!fdisused(fdp, fd), ("fd already used")); + fdp->fd_map[NDSLOT(fd)] |= NDBIT(fd); if (fd > fdp->fd_lastfile) fdp->fd_lastfile = fd; @@ -227,11 +229,13 @@ fdused(struct filedesc *fdp, int fd) static void fdunused(struct filedesc *fdp, int fd) { - FILEDESC_LOCK_ASSERT(fdp, MA_OWNED); + + FILEDESC_XLOCK_ASSERT(fdp); KASSERT(fdisused(fdp, fd), ("fd is already unused")); KASSERT(fdp->fd_ofiles[fd] == NULL, ("fd is still in use")); + fdp->fd_map[NDSLOT(fd)] &= ~NDBIT(fd); if (fd < fdp->fd_freefile) fdp->fd_freefile = fd; @@ -371,10 +375,14 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) flg = F_POSIX; p = td->td_proc; fdp = p->p_fd; - FILEDESC_LOCK(fdp); + + /* + * XXXRW: It could be an exclusive lock is not [always] needed here. + */ + FILEDESC_XLOCK(fdp); if ((unsigned)fd >= fdp->fd_nfiles || (fp = fdp->fd_ofiles[fd]) == NULL) { - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); error = EBADF; goto done2; } @@ -383,7 +391,7 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) switch (cmd) { case F_DUPFD: /* mtx_assert(&Giant, MA_NOTOWNED); */ - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); newmin = arg; PROC_LOCK(p); if (newmin >= lim_cur(p, RLIMIT_NOFILE) || @@ -399,14 +407,14 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) case F_GETFD: /* mtx_assert(&Giant, MA_NOTOWNED); */ td->td_retval[0] = (*pop & UF_EXCLOSE) ? FD_CLOEXEC : 0; - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); break; case F_SETFD: /* mtx_assert(&Giant, MA_NOTOWNED); */ *pop = (*pop &~ UF_EXCLOSE) | (arg & FD_CLOEXEC ? UF_EXCLOSE : 0); - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); break; case F_GETFL: @@ -414,7 +422,7 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) FILE_LOCK(fp); td->td_retval[0] = OFLAGS(fp->f_flag); FILE_UNLOCK(fp); - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); break; case F_SETFL: @@ -424,7 +432,7 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) fp->f_flag &= ~FCNTLFLAGS; fp->f_flag |= FFLAGS(arg & ~O_ACCMODE) & FCNTLFLAGS; FILE_UNLOCK(fp); - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); tmp = fp->f_flag & FNONBLOCK; error = fo_ioctl(fp, FIONBIO, &tmp, td->td_ucred, td); if (error) { @@ -448,7 +456,7 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) case F_GETOWN: mtx_assert(&Giant, MA_OWNED); fhold(fp); - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); error = fo_ioctl(fp, FIOGETOWN, &tmp, td->td_ucred, td); if (error == 0) td->td_retval[0] = tmp; @@ -458,7 +466,7 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) case F_SETOWN: mtx_assert(&Giant, MA_OWNED); fhold(fp); - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); tmp = arg; error = fo_ioctl(fp, FIOSETOWN, &tmp, td->td_ucred, td); fdrop(fp, td); @@ -472,7 +480,7 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) case F_SETLK: mtx_assert(&Giant, MA_OWNED); if (fp->f_type != DTYPE_VNODE) { - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); error = EBADF; break; } @@ -482,7 +490,7 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) if (fp->f_offset < 0 || (flp->l_start > 0 && fp->f_offset > OFF_MAX - flp->l_start)) { - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); error = EOVERFLOW; break; } @@ -493,7 +501,7 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) * VOP_ADVLOCK() may block. */ fhold(fp); - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); vp = fp->f_vnode; switch (flp->l_type) { @@ -528,10 +536,10 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) break; } /* Check for race with close */ - FILEDESC_LOCK_FAST(fdp); + FILEDESC_XLOCK(fdp); if ((unsigned) fd >= fdp->fd_nfiles || fp != fdp->fd_ofiles[fd]) { - FILEDESC_UNLOCK_FAST(fdp); + FILEDESC_XUNLOCK(fdp); flp->l_whence = SEEK_SET; flp->l_start = 0; flp->l_len = 0; @@ -539,21 +547,21 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) (void) VOP_ADVLOCK(vp, (caddr_t)p->p_leader, F_UNLCK, flp, F_POSIX); } else - FILEDESC_UNLOCK_FAST(fdp); + FILEDESC_XUNLOCK(fdp); fdrop(fp, td); break; case F_GETLK: mtx_assert(&Giant, MA_OWNED); if (fp->f_type != DTYPE_VNODE) { - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); error = EBADF; break; } flp = (struct flock *)arg; if (flp->l_type != F_RDLCK && flp->l_type != F_WRLCK && flp->l_type != F_UNLCK) { - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); error = EINVAL; break; } @@ -562,7 +570,7 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) fp->f_offset > OFF_MAX - flp->l_start) || (flp->l_start < 0 && fp->f_offset < OFF_MIN - flp->l_start)) { - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); error = EOVERFLOW; break; } @@ -572,14 +580,14 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) * VOP_ADVLOCK() may block. */ fhold(fp); - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); vp = fp->f_vnode; error = VOP_ADVLOCK(vp, (caddr_t)p->p_leader, F_GETLK, flp, F_POSIX); fdrop(fp, td); break; default: - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); error = EINVAL; break; } @@ -593,7 +601,8 @@ done2: * Common code for dup, dup2, and fcntl(F_DUPFD). */ static int -do_dup(struct thread *td, enum dup_type type, int old, int new, register_t *retval) +do_dup(struct thread *td, enum dup_type type, int old, int new, + register_t *retval) { struct filedesc *fdp; struct proc *p; @@ -619,14 +628,14 @@ do_dup(struct thread *td, enum dup_type type, int old, int new, register_t *retv if (new >= maxfd) return (EMFILE); - FILEDESC_LOCK(fdp); + FILEDESC_XLOCK(fdp); if (old >= fdp->fd_nfiles || fdp->fd_ofiles[old] == NULL) { - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); return (EBADF); } if (type == DUP_FIXED && old == new) { *retval = new; - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); return (0); } fp = fdp->fd_ofiles[old]; @@ -646,7 +655,7 @@ do_dup(struct thread *td, enum dup_type type, int old, int new, register_t *retv fdused(fdp, new); } else { if ((error = fdalloc(td, new, &new)) != 0) { - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); fdrop(fp, td); return (error); } @@ -661,7 +670,7 @@ do_dup(struct thread *td, enum dup_type type, int old, int new, register_t *retv /* we've allocated a descriptor which we won't use */ if (fdp->fd_ofiles[new] == NULL) fdunused(fdp, new); - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); fdrop(fp, td); return (EBADF); } @@ -708,20 +717,20 @@ do_dup(struct thread *td, enum dup_type type, int old, int new, register_t *retv knote_fdclose(td, new); if (delfp->f_type == DTYPE_MQUEUE) mq_fdclose(td, new, delfp); - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); (void) closef(delfp, td); if (holdleaders) { - FILEDESC_LOCK_FAST(fdp); + FILEDESC_XLOCK(fdp); fdp->fd_holdleaderscount--; if (fdp->fd_holdleaderscount == 0 && fdp->fd_holdleaderswakeup != 0) { fdp->fd_holdleaderswakeup = 0; wakeup(&fdp->fd_holdleaderscount); } - FILEDESC_UNLOCK_FAST(fdp); + FILEDESC_XUNLOCK(fdp); } } else { - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); } return (0); } @@ -979,10 +988,10 @@ kern_close(td, fd) AUDIT_SYSCLOSE(td, fd); - FILEDESC_LOCK(fdp); + FILEDESC_XLOCK(fdp); if ((unsigned)fd >= fdp->fd_nfiles || (fp = fdp->fd_ofiles[fd]) == NULL) { - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); return (EBADF); } fdp->fd_ofiles[fd] = NULL; @@ -998,27 +1007,26 @@ kern_close(td, fd) } /* - * We now hold the fp reference that used to be owned by the descriptor - * array. - * We have to unlock the FILEDESC *AFTER* knote_fdclose to prevent a - * race of the fd getting opened, a knote added, and deleteing a knote - * for the new fd. + * We now hold the fp reference that used to be owned by the + * descriptor array. We have to unlock the FILEDESC *AFTER* + * knote_fdclose to prevent a race of the fd getting opened, a knote + * added, and deleteing a knote for the new fd. */ knote_fdclose(td, fd); if (fp->f_type == DTYPE_MQUEUE) mq_fdclose(td, fd, fp); - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); error = closef(fp, td); if (holdleaders) { - FILEDESC_LOCK_FAST(fdp); + FILEDESC_XLOCK(fdp); fdp->fd_holdleaderscount--; if (fdp->fd_holdleaderscount == 0 && fdp->fd_holdleaderswakeup != 0) { fdp->fd_holdleaderswakeup = 0; wakeup(&fdp->fd_holdleaderscount); } - FILEDESC_UNLOCK_FAST(fdp); + FILEDESC_XUNLOCK(fdp); } return (error); } @@ -1176,7 +1184,7 @@ fdgrowtable(struct filedesc *fdp, int nfd) int nnfiles, onfiles; NDSLOTTYPE *nmap; - FILEDESC_LOCK_ASSERT(fdp, MA_OWNED); + FILEDESC_XLOCK_ASSERT(fdp); KASSERT(fdp->fd_nfiles > 0, ("zero-length file table")); @@ -1189,7 +1197,7 @@ fdgrowtable(struct filedesc *fdp, int nfd) return; /* allocate a new table and (if required) new bitmaps */ - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); MALLOC(ntable, struct file **, nnfiles * OFILESIZE, M_FILEDESC, M_ZERO | M_WAITOK); nfileflags = (char *)&ntable[nnfiles]; @@ -1198,7 +1206,7 @@ fdgrowtable(struct filedesc *fdp, int nfd) M_FILEDESC, M_ZERO | M_WAITOK); else nmap = NULL; - FILEDESC_LOCK(fdp); + FILEDESC_XLOCK(fdp); /* * We now have new tables ready to go. Since we dropped the @@ -1237,7 +1245,7 @@ fdalloc(struct thread *td, int minfd, int *result) struct filedesc *fdp = p->p_fd; int fd = -1, maxfd; - FILEDESC_LOCK_ASSERT(fdp, MA_OWNED); + FILEDESC_XLOCK_ASSERT(fdp); if (fdp->fd_freefile > minfd) minfd = fdp->fd_freefile; @@ -1276,8 +1284,8 @@ fdalloc(struct thread *td, int minfd, int *result) } /* - * Check to see whether n user file descriptors - * are available to the process p. + * Check to see whether n user file descriptors are available to the process + * p. */ int fdavail(struct thread *td, int n) @@ -1287,7 +1295,7 @@ fdavail(struct thread *td, int n) struct file **fpp; int i, lim, last; - FILEDESC_LOCK_ASSERT(fdp, MA_OWNED); + FILEDESC_LOCK_ASSERT(fdp); PROC_LOCK(p); lim = min((int)lim_cur(p, RLIMIT_NOFILE), maxfilesperproc); @@ -1304,12 +1312,11 @@ fdavail(struct thread *td, int n) } /* - * Create a new open file structure and allocate - * a file decriptor for the process that refers to it. - * We add one reference to the file for the descriptor table - * and one reference for resultfp. This is to prevent us being - * preempted and the entry in the descriptor table closed after - * we release the FILEDESC lock. + * Create a new open file structure and allocate a file decriptor for the + * process that refers to it. We add one reference to the file for the + * descriptor table and one reference for resultfp. This is to prevent us + * being preempted and the entry in the descriptor table closed after we + * release the FILEDESC lock. */ int falloc(struct thread *td, struct file **resultfp, int *resultfd) @@ -1350,7 +1357,7 @@ falloc(struct thread *td, struct file **resultfp, int *resultfd) fp->f_ops = &badfileops; fp->f_data = NULL; fp->f_vnode = NULL; - FILEDESC_LOCK(p->p_fd); + FILEDESC_XLOCK(p->p_fd); if ((fq = p->p_fd->fd_ofiles[0])) { LIST_INSERT_AFTER(fq, fp, f_list); } else { @@ -1358,14 +1365,14 @@ falloc(struct thread *td, struct file **resultfp, int *resultfd) } sx_xunlock(&filelist_lock); if ((error = fdalloc(td, 0, &i))) { - FILEDESC_UNLOCK(p->p_fd); + FILEDESC_XUNLOCK(p->p_fd); fdrop(fp, td); if (resultfp) fdrop(fp, td); return (error); } p->p_fd->fd_ofiles[i] = fp; - FILEDESC_UNLOCK(p->p_fd); + FILEDESC_XUNLOCK(p->p_fd); if (resultfp) *resultfp = fp; if (resultfd) @@ -1383,9 +1390,9 @@ fdinit(struct filedesc *fdp) struct filedesc0 *newfdp; newfdp = malloc(sizeof *newfdp, M_FILEDESC, M_WAITOK | M_ZERO); - mtx_init(&newfdp->fd_fd.fd_mtx, FILEDESC_LOCK_DESC, NULL, MTX_DEF); + FILEDESC_LOCK_INIT(&newfdp->fd_fd); if (fdp != NULL) { - FILEDESC_LOCK(fdp); + FILEDESC_XLOCK(fdp); newfdp->fd_fd.fd_cdir = fdp->fd_cdir; if (newfdp->fd_fd.fd_cdir) VREF(newfdp->fd_fd.fd_cdir); @@ -1395,7 +1402,7 @@ fdinit(struct filedesc *fdp) newfdp->fd_fd.fd_jdir = fdp->fd_jdir; if (newfdp->fd_fd.fd_jdir) VREF(newfdp->fd_fd.fd_jdir); - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); } /* Create the file descriptor table. */ @@ -1434,7 +1441,7 @@ fddrop(struct filedesc *fdp) if (i > 0) return; - mtx_destroy(&fdp->fd_mtx); + FILEDESC_LOCK_DESTROY(fdp); FREE(fdp, M_FILEDESC); } @@ -1444,9 +1451,10 @@ fddrop(struct filedesc *fdp) struct filedesc * fdshare(struct filedesc *fdp) { - FILEDESC_LOCK_FAST(fdp); + + FILEDESC_XLOCK(fdp); fdp->fd_refcnt++; - FILEDESC_UNLOCK_FAST(fdp); + FILEDESC_XUNLOCK(fdp); return (fdp); } @@ -1457,22 +1465,21 @@ void fdunshare(struct proc *p, struct thread *td) { - FILEDESC_LOCK_FAST(p->p_fd); + FILEDESC_XLOCK(p->p_fd); if (p->p_fd->fd_refcnt > 1) { struct filedesc *tmp; - FILEDESC_UNLOCK_FAST(p->p_fd); + FILEDESC_XUNLOCK(p->p_fd); tmp = fdcopy(p->p_fd); fdfree(td); p->p_fd = tmp; } else - FILEDESC_UNLOCK_FAST(p->p_fd); + FILEDESC_XUNLOCK(p->p_fd); } /* - * Copy a filedesc structure. - * A NULL pointer in returns a NULL reference, this is to ease callers, - * not catch errors. + * Copy a filedesc structure. A NULL pointer in returns a NULL reference, + * this is to ease callers, not catch errors. */ struct filedesc * fdcopy(struct filedesc *fdp) @@ -1485,13 +1492,13 @@ fdcopy(struct filedesc *fdp) return (NULL); newfdp = fdinit(fdp); - FILEDESC_LOCK_FAST(fdp); + FILEDESC_SLOCK(fdp); while (fdp->fd_lastfile >= newfdp->fd_nfiles) { - FILEDESC_UNLOCK_FAST(fdp); - FILEDESC_LOCK(newfdp); + FILEDESC_SUNLOCK(fdp); + FILEDESC_XLOCK(newfdp); fdgrowtable(newfdp, fdp->fd_lastfile + 1); - FILEDESC_UNLOCK(newfdp); - FILEDESC_LOCK_FAST(fdp); + FILEDESC_XUNLOCK(newfdp); + FILEDESC_SLOCK(fdp); } /* copy everything except kqueue descriptors */ newfdp->fd_freefile = -1; @@ -1507,17 +1514,17 @@ fdcopy(struct filedesc *fdp) newfdp->fd_freefile = i; } } - FILEDESC_UNLOCK_FAST(fdp); - FILEDESC_LOCK(newfdp); + FILEDESC_SUNLOCK(fdp); + FILEDESC_XLOCK(newfdp); for (i = 0; i <= newfdp->fd_lastfile; ++i) if (newfdp->fd_ofiles[i] != NULL) fdused(newfdp, i); - FILEDESC_UNLOCK(newfdp); - FILEDESC_LOCK_FAST(fdp); + FILEDESC_XUNLOCK(newfdp); + FILEDESC_SLOCK(fdp); if (newfdp->fd_freefile == -1) newfdp->fd_freefile = i; newfdp->fd_cmask = fdp->fd_cmask; - FILEDESC_UNLOCK_FAST(fdp); + FILEDESC_SUNLOCK(fdp); return (newfdp); } @@ -1543,7 +1550,7 @@ fdfree(struct thread *td) /* Check for special need to clear POSIX style locks */ fdtol = td->td_proc->p_fdtol; if (fdtol != NULL) { - FILEDESC_LOCK(fdp); + FILEDESC_XLOCK(fdp); KASSERT(fdtol->fdl_refcount > 0, ("filedesc_to_refcount botch: fdl_refcount=%d", fdtol->fdl_refcount)); @@ -1557,7 +1564,7 @@ fdfree(struct thread *td) continue; fp = *fpp; fhold(fp); - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); lf.l_whence = SEEK_SET; lf.l_start = 0; lf.l_len = 0; @@ -1571,7 +1578,7 @@ fdfree(struct thread *td) &lf, F_POSIX); VFS_UNLOCK_GIANT(locked); - FILEDESC_LOCK(fdp); + FILEDESC_XLOCK(fdp); fdrop(fp, td); fpp = fdp->fd_ofiles + i; } @@ -1585,18 +1592,18 @@ fdfree(struct thread *td) * in a shared file descriptor table. */ fdp->fd_holdleaderswakeup = 1; - msleep(&fdp->fd_holdleaderscount, &fdp->fd_mtx, - PLOCK, "fdlhold", 0); + sx_sleep(&fdp->fd_holdleaderscount, + FILEDESC_LOCK(fdp), PLOCK, "fdlhold", 0); goto retry; } if (fdtol->fdl_holdcount > 0) { /* - * Ensure that fdtol->fdl_leader - * remains valid in closef(). + * Ensure that fdtol->fdl_leader remains + * valid in closef(). */ fdtol->fdl_wakeup = 1; - msleep(fdtol, &fdp->fd_mtx, - PLOCK, "fdlhold", 0); + sx_sleep(fdtol, FILEDESC_LOCK(fdp), PLOCK, + "fdlhold", 0); goto retry; } } @@ -1608,13 +1615,13 @@ fdfree(struct thread *td) } else fdtol = NULL; td->td_proc->p_fdtol = NULL; - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); if (fdtol != NULL) FREE(fdtol, M_FILEDESC_TO_LEADER); } - FILEDESC_LOCK_FAST(fdp); + FILEDESC_XLOCK(fdp); i = --fdp->fd_refcnt; - FILEDESC_UNLOCK_FAST(fdp); + FILEDESC_XUNLOCK(fdp); if (i > 0) return; /* @@ -1626,7 +1633,7 @@ fdfree(struct thread *td) if (*fpp) (void) closef(*fpp, td); } - FILEDESC_LOCK(fdp); + FILEDESC_XLOCK(fdp); /* XXX This should happen earlier. */ mtx_lock(&fdesc_mtx); @@ -1646,7 +1653,7 @@ fdfree(struct thread *td) fdp->fd_rdir = NULL; jdir = fdp->fd_jdir; fdp->fd_jdir = NULL; - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); if (cdir) { locked = VFS_LOCK_GIANT(cdir->v_mount); @@ -1706,7 +1713,7 @@ setugidsafety(struct thread *td) * Note: fdp->fd_ofiles may be reallocated out from under us while * we are blocked in a close. Be careful! */ - FILEDESC_LOCK(fdp); + FILEDESC_XLOCK(fdp); for (i = 0; i <= fdp->fd_lastfile; i++) { if (i > 2) break; @@ -1722,35 +1729,33 @@ setugidsafety(struct thread *td) fdp->fd_ofiles[i] = NULL; fdp->fd_ofileflags[i] = 0; fdunused(fdp, i); - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); (void) closef(fp, td); - FILEDESC_LOCK(fdp); + FILEDESC_XLOCK(fdp); } } - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); } /* - * If a specific file object occupies a specific file descriptor, - * close the file descriptor entry and drop a reference on the file - * object. This is a convenience function to handle a subsequent - * error in a function that calls falloc() that handles the race that - * another thread might have closed the file descriptor out from under - * the thread creating the file object. + * If a specific file object occupies a specific file descriptor, close the + * file descriptor entry and drop a reference on the file object. This is a + * convenience function to handle a subsequent error in a function that calls + * falloc() that handles the race that another thread might have closed the + * file descriptor out from under the thread creating the file object. */ void fdclose(struct filedesc *fdp, struct file *fp, int idx, struct thread *td) { - FILEDESC_LOCK(fdp); + FILEDESC_XLOCK(fdp); if (fdp->fd_ofiles[idx] == fp) { fdp->fd_ofiles[idx] = NULL; fdunused(fdp, idx); - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); fdrop(fp, td); - } else { - FILEDESC_UNLOCK(fdp); - } + } else + FILEDESC_XUNLOCK(fdp); } /* @@ -1767,7 +1772,7 @@ fdcloseexec(struct thread *td) if (fdp == NULL) return; - FILEDESC_LOCK(fdp); + FILEDESC_XLOCK(fdp); /* * We cannot cache fd_ofiles or fd_ofileflags since operations @@ -1790,12 +1795,12 @@ fdcloseexec(struct thread *td) fdunused(fdp, i); if (fp->f_type == DTYPE_MQUEUE) mq_fdclose(td, i, fp); - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); (void) closef(fp, td); - FILEDESC_LOCK(fdp); + FILEDESC_XLOCK(fdp); } } - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); } /* @@ -1838,27 +1843,30 @@ fdcheckstd(struct thread *td) /* * Someone may have closed the entry in the * file descriptor table, so check it hasn't - * changed before dropping the reference count. + * changed before dropping the reference + * count. */ - FILEDESC_LOCK(fdp); + FILEDESC_XLOCK(fdp); KASSERT(fdp->fd_ofiles[fd] == fp, ("table not shared, how did it change?")); fdp->fd_ofiles[fd] = NULL; fdunused(fdp, fd); - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); fdrop(fp, td); fdrop(fp, td); break; } vfslocked = NDHASGIANT(&nd); NDFREE(&nd, NDF_ONLY_PNBUF); + FILE_LOCK(fp); fp->f_flag = flags; fp->f_vnode = nd.ni_vp; if (fp->f_data == NULL) fp->f_data = nd.ni_vp; + fp->f_type = DTYPE_VNODE; if (fp->f_ops == &badfileops) fp->f_ops = &vnops; - fp->f_type = DTYPE_VNODE; + FILE_UNLOCK(fp); VOP_UNLOCK(nd.ni_vp, 0, td); VFS_UNLOCK_GIANT(vfslocked); devnull = fd; @@ -1873,8 +1881,7 @@ fdcheckstd(struct thread *td) } /* - * Internal form of close. - * Decrement reference count on file structure. + * Internal form of close. Decrement reference count on file structure. * Note: td may be NULL when closing a file that was being passed in a * message. * @@ -1917,11 +1924,11 @@ closef(struct file *fp, struct thread *td) fdtol = td->td_proc->p_fdtol; if (fdtol != NULL) { /* - * Handle special case where file descriptor table - * is shared between multiple process leaders. + * Handle special case where file descriptor table is + * shared between multiple process leaders. */ fdp = td->td_proc->p_fd; - FILEDESC_LOCK(fdp); + FILEDESC_XLOCK(fdp); for (fdtol = fdtol->fdl_next; fdtol != td->td_proc->p_fdtol; fdtol = fdtol->fdl_next) { @@ -1929,7 +1936,7 @@ closef(struct file *fp, struct thread *td) P_ADVLOCK) == 0) continue; fdtol->fdl_holdcount++; - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); lf.l_whence = SEEK_SET; lf.l_start = 0; lf.l_len = 0; @@ -1938,7 +1945,7 @@ closef(struct file *fp, struct thread *td) (void) VOP_ADVLOCK(vp, (caddr_t)fdtol->fdl_leader, F_UNLCK, &lf, F_POSIX); - FILEDESC_LOCK(fdp); + FILEDESC_XLOCK(fdp); fdtol->fdl_holdcount--; if (fdtol->fdl_holdcount == 0 && fdtol->fdl_wakeup != 0) { @@ -1946,7 +1953,7 @@ closef(struct file *fp, struct thread *td) wakeup(fdtol); } } - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); } VFS_UNLOCK_GIANT(vfslocked); } @@ -1954,21 +1961,21 @@ closef(struct file *fp, struct thread *td) } /* - * Extract the file pointer associated with the specified descriptor for - * the current user process. + * Extract the file pointer associated with the specified descriptor for the + * current user process. * * If the descriptor doesn't exist, EBADF is returned. * - * If the descriptor exists but doesn't match 'flags' then - * return EBADF for read attempts and EINVAL for write attempts. + * If the descriptor exists but doesn't match 'flags' then return EBADF for + * read attempts and EINVAL for write attempts. * * If 'hold' is set (non-zero) the file's refcount will be bumped on return. - * It should be dropped with fdrop(). - * If it is not set, then the refcount will not be bumped however the - * thread's filedesc struct will be returned locked (for fgetsock). + * It should be dropped with fdrop(). If it is not set, then the refcount + * will not be bumped however the thread's filedesc struct will be returned + * locked (for fgetsock). * - * If an error occured the non-zero error is returned and *fpp is set to NULL. - * Otherwise *fpp is set and zero is returned. + * If an error occured the non-zero error is returned and *fpp is set to + * NULL. Otherwise *fpp is set and zero is returned. */ static __inline int _fget(struct thread *td, int fd, struct file **fpp, int flags, int hold) @@ -1979,9 +1986,9 @@ _fget(struct thread *td, int fd, struct file **fpp, int flags, int hold) *fpp = NULL; if (td == NULL || (fdp = td->td_proc->p_fd) == NULL) return (EBADF); - FILEDESC_LOCK(fdp); + FILEDESC_SLOCK(fdp); if ((fp = fget_locked(fdp, fd)) == NULL || fp->f_ops == &badfileops) { - FILEDESC_UNLOCK(fdp); + FILEDESC_SUNLOCK(fdp); return (EBADF); } @@ -1991,16 +1998,16 @@ _fget(struct thread *td, int fd, struct file **fpp, int flags, int hold) * Only one flag, or 0, may be specified. */ if (flags == FREAD && (fp->f_flag & FREAD) == 0) { - FILEDESC_UNLOCK(fdp); + FILEDESC_SUNLOCK(fdp); return (EBADF); } if (flags == FWRITE && (fp->f_flag & FWRITE) == 0) { - FILEDESC_UNLOCK(fdp); + FILEDESC_SUNLOCK(fdp); return (EBADF); } if (hold) { fhold(fp); - FILEDESC_UNLOCK(fdp); + FILEDESC_SUNLOCK(fdp); } *fpp = fp; return (0); @@ -2028,9 +2035,9 @@ fget_write(struct thread *td, int fd, struct file **fpp) } /* - * Like fget() but loads the underlying vnode, or returns an error if - * the descriptor does not represent a vnode. Note that pipes use vnodes - * but never have VM objects. The returned vnode will be vref()d. + * Like fget() but loads the underlying vnode, or returns an error if the + * descriptor does not represent a vnode. Note that pipes use vnodes but + * never have VM objects. The returned vnode will be vref()'d. * * XXX: what about the unused flags ? */ @@ -2049,7 +2056,7 @@ _fgetvp(struct thread *td, int fd, struct vnode **vpp, int flags) *vpp = fp->f_vnode; vref(*vpp); } - FILEDESC_UNLOCK(td->td_proc->p_fd); + FILEDESC_SUNLOCK(td->td_proc->p_fd); return (error); } @@ -2077,15 +2084,15 @@ fgetvp_write(struct thread *td, int fd, struct vnode **vpp) #endif /* - * Like fget() but loads the underlying socket, or returns an error if - * the descriptor does not represent a socket. + * Like fget() but loads the underlying socket, or returns an error if the + * descriptor does not represent a socket. * - * We bump the ref count on the returned socket. XXX Also obtain the SX - * lock in the future. + * We bump the ref count on the returned socket. XXX Also obtain the SX lock + * in the future. * * XXXRW: fgetsock() and fputsock() are deprecated, as consumers should rely - * on their file descriptor reference to prevent the socket from being - * freed during use. + * on their file descriptor reference to prevent the socket from being free'd + * during use. */ int fgetsock(struct thread *td, int fd, struct socket **spp, u_int *fflagp) @@ -2110,7 +2117,7 @@ fgetsock(struct thread *td, int fd, struct socket **spp, u_int *fflagp) soref(*spp); SOCK_UNLOCK(*spp); } - FILEDESC_UNLOCK(td->td_proc->p_fd); + FILEDESC_SUNLOCK(td->td_proc->p_fd); return (error); } @@ -2257,22 +2264,20 @@ dupfdopen(struct thread *td, struct filedesc *fdp, int indx, int dfd, int mode, * of file descriptors, or the fd to be dup'd has already been * closed, then reject. */ - FILEDESC_LOCK(fdp); + FILEDESC_XLOCK(fdp); if (dfd < 0 || dfd >= fdp->fd_nfiles || (wfp = fdp->fd_ofiles[dfd]) == NULL) { - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); return (EBADF); } /* * There are two cases of interest here. * - * For ENODEV simply dup (dfd) to file descriptor - * (indx) and return. + * For ENODEV simply dup (dfd) to file descriptor (indx) and return. * - * For ENXIO steal away the file structure from (dfd) and - * store it in (indx). (dfd) is effectively closed by - * this operation. + * For ENXIO steal away the file structure from (dfd) and store it in + * (indx). (dfd) is effectively closed by this operation. * * Any other error code is just returned. */ @@ -2285,7 +2290,7 @@ dupfdopen(struct thread *td, struct filedesc *fdp, int indx, int dfd, int mode, FILE_LOCK(wfp); if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag) { FILE_UNLOCK(wfp); - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); return (EACCES); } fp = fdp->fd_ofiles[indx]; @@ -2295,7 +2300,7 @@ dupfdopen(struct thread *td, struct filedesc *fdp, int indx, int dfd, int mode, fdused(fdp, indx); fhold_locked(wfp); FILE_UNLOCK(wfp); - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); if (fp != NULL) /* * We now own the reference to fp that the ofiles[] @@ -2316,7 +2321,7 @@ dupfdopen(struct thread *td, struct filedesc *fdp, int indx, int dfd, int mode, fdunused(fdp, dfd); if (fp == NULL) fdused(fdp, indx); - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); /* * We now own the reference to fp that the ofiles[] array @@ -2327,16 +2332,15 @@ dupfdopen(struct thread *td, struct filedesc *fdp, int indx, int dfd, int mode, return (0); default: - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); return (error); } /* NOTREACHED */ } /* - * Scan all active processes to see if any of them have a current - * or root directory of `olddp'. If so, replace them with the new - * mount point. + * Scan all active processes to see if any of them have a current or root + * directory of `olddp'. If so, replace them with the new mount point. */ void mountcheckdirs(struct vnode *olddp, struct vnode *newdp) @@ -2353,7 +2357,7 @@ mountcheckdirs(struct vnode *olddp, struct vnode *newdp) if (fdp == NULL) continue; nrele = 0; - FILEDESC_LOCK_FAST(fdp); + FILEDESC_XLOCK(fdp); if (fdp->fd_cdir == olddp) { vref(newdp); fdp->fd_cdir = newdp; @@ -2364,7 +2368,7 @@ mountcheckdirs(struct vnode *olddp, struct vnode *newdp) fdp->fd_rdir = newdp; nrele++; } - FILEDESC_UNLOCK_FAST(fdp); + FILEDESC_XUNLOCK(fdp); fddrop(fdp); while (nrele--) vrele(olddp); @@ -2391,12 +2395,12 @@ filedesc_to_leader_alloc(struct filedesc_to_leader *old, struct filedesc *fdp, s fdtol->fdl_wakeup = 0; fdtol->fdl_leader = leader; if (old != NULL) { - FILEDESC_LOCK(fdp); + FILEDESC_XLOCK(fdp); fdtol->fdl_next = old->fdl_next; fdtol->fdl_prev = old; old->fdl_next = fdtol; fdtol->fdl_next->fdl_prev = fdtol; - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); } else { fdtol->fdl_next = fdtol; fdtol->fdl_prev = fdtol; @@ -2459,7 +2463,7 @@ sysctl_kern_file(SYSCTL_HANDLER_ARGS) fdp = fdhold(p); if (fdp == NULL) continue; - FILEDESC_LOCK_FAST(fdp); + FILEDESC_SLOCK(fdp); for (n = 0; fdp->fd_refcnt > 0 && n < fdp->fd_nfiles; ++n) { if ((fp = fdp->fd_ofiles[n]) == NULL) continue; @@ -2476,7 +2480,7 @@ sysctl_kern_file(SYSCTL_HANDLER_ARGS) if (error) break; } - FILEDESC_UNLOCK_FAST(fdp); + FILEDESC_SUNLOCK(fdp); fddrop(fdp); if (error) break; diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c index 8e2a10d..87706a1 100644 --- a/sys/kern/kern_event.c +++ b/sys/kern/kern_event.c @@ -527,15 +527,15 @@ kqueue(struct thread *td, struct kqueue_args *uap) knlist_init(&kq->kq_sel.si_note, &kq->kq_lock, NULL, NULL, NULL); TASK_INIT(&kq->kq_task, 0, kqueue_task, kq); - FILEDESC_LOCK_FAST(fdp); + FILEDESC_XLOCK(fdp); SLIST_INSERT_HEAD(&fdp->fd_kqlist, kq, kq_list); - FILEDESC_UNLOCK_FAST(fdp); + FILEDESC_XUNLOCK(fdp); FILE_LOCK(fp); fp->f_flag = FREAD | FWRITE; fp->f_type = DTYPE_KQUEUE; - fp->f_ops = &kqueueops; fp->f_data = kq; + fp->f_ops = &kqueueops; FILE_UNLOCK(fp); fdrop(fp, td); @@ -1493,9 +1493,9 @@ kqueue_close(struct file *fp, struct thread *td) KQ_UNLOCK(kq); - FILEDESC_LOCK_FAST(fdp); + FILEDESC_XLOCK(fdp); SLIST_REMOVE(&fdp->fd_kqlist, kq, kqueue, kq_list); - FILEDESC_UNLOCK_FAST(fdp); + FILEDESC_XUNLOCK(fdp); knlist_destroy(&kq->kq_sel.si_note); mtx_destroy(&kq->kq_lock); @@ -1781,9 +1781,9 @@ again: /* need to reaquire lock since we have dropped it */ } /* - * remove all knotes referencing a specified fd - * must be called with FILEDESC lock. This prevents a race where a new fd - * comes along and occupies the entry and we attach a knote to the fd. + * Remove all knotes referencing a specified fd must be called with FILEDESC + * lock. This prevents a race where a new fd comes along and occupies the + * entry and we attach a knote to the fd. */ void knote_fdclose(struct thread *td, int fd) @@ -1793,7 +1793,7 @@ knote_fdclose(struct thread *td, int fd) struct knote *kn; int influx; - FILEDESC_LOCK_ASSERT(fdp, MA_OWNED); + FILEDESC_XLOCK_ASSERT(fdp); /* * We shouldn't have to worry about new kevents appearing on fd diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index c783ea9..990f003 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -458,9 +458,9 @@ again: * shared process leaders. */ fdtol = p1->p_fdtol; - FILEDESC_LOCK_FAST(p1->p_fd); + FILEDESC_XLOCK(p1->p_fd); fdtol->fdl_refcount++; - FILEDESC_UNLOCK_FAST(p1->p_fd); + FILEDESC_XUNLOCK(p1->p_fd); } else { /* * Shared file descriptor table, and diff --git a/sys/kern/subr_witness.c b/sys/kern/subr_witness.c index 069804e..8f0ee0f 100644 --- a/sys/kern/subr_witness.c +++ b/sys/kern/subr_witness.c @@ -281,7 +281,6 @@ static struct witness_order_list_entry order_lists[] = { * Various mutexes */ { "Giant", &lock_class_mtx_sleep }, - { "filedesc structure", &lock_class_mtx_sleep }, { "pipe mutex", &lock_class_mtx_sleep }, { "sigio lock", &lock_class_mtx_sleep }, { "process group", &lock_class_mtx_sleep }, @@ -294,7 +293,6 @@ static struct witness_order_list_entry order_lists[] = { /* * Sockets */ - { "filedesc structure", &lock_class_mtx_sleep }, { "accept", &lock_class_mtx_sleep }, { "so_snd", &lock_class_mtx_sleep }, { "so_rcv", &lock_class_mtx_sleep }, diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c index 268224a..f7d6ade 100644 --- a/sys/kern/sys_generic.c +++ b/sys/kern/sys_generic.c @@ -568,14 +568,14 @@ kern_ioctl(struct thread *td, int fd, u_long com, caddr_t data) fdp = td->td_proc->p_fd; switch (com) { case FIONCLEX: - FILEDESC_LOCK_FAST(fdp); + FILEDESC_XLOCK(fdp); fdp->fd_ofileflags[fd] &= ~UF_EXCLOSE; - FILEDESC_UNLOCK_FAST(fdp); + FILEDESC_XUNLOCK(fdp); goto out; case FIOCLEX: - FILEDESC_LOCK_FAST(fdp); + FILEDESC_XLOCK(fdp); fdp->fd_ofileflags[fd] |= UF_EXCLOSE; - FILEDESC_UNLOCK_FAST(fdp); + FILEDESC_XUNLOCK(fdp); goto out; case FIONBIO: FILE_LOCK(fp); @@ -658,11 +658,10 @@ kern_select(struct thread *td, int nd, fd_set *fd_in, fd_set *fd_ou, return (EINVAL); fdp = td->td_proc->p_fd; - FILEDESC_LOCK_FAST(fdp); - + FILEDESC_SLOCK(fdp); if (nd > td->td_proc->p_fd->fd_nfiles) nd = td->td_proc->p_fd->fd_nfiles; /* forgiving; slightly wrong */ - FILEDESC_UNLOCK_FAST(fdp); + FILEDESC_SUNLOCK(fdp); /* * Allocate just enough bits for the non-null fd_sets. Use the @@ -809,7 +808,7 @@ selscan(td, ibits, obits, nfd) static int flag[3] = { POLLRDNORM, POLLWRNORM, POLLRDBAND }; struct filedesc *fdp = td->td_proc->p_fd; - FILEDESC_LOCK(fdp); + FILEDESC_SLOCK(fdp); for (msk = 0; msk < 3; msk++) { if (ibits[msk] == NULL) continue; @@ -820,7 +819,7 @@ selscan(td, ibits, obits, nfd) if (!(bits & 1)) continue; if ((fp = fget_locked(fdp, fd)) == NULL) { - FILEDESC_UNLOCK(fdp); + FILEDESC_SUNLOCK(fdp); return (EBADF); } if (fo_poll(fp, flag[msk], td->td_ucred, @@ -832,7 +831,7 @@ selscan(td, ibits, obits, nfd) } } } - FILEDESC_UNLOCK(fdp); + FILEDESC_SUNLOCK(fdp); td->td_retval[0] = n; return (0); } @@ -973,7 +972,7 @@ pollscan(td, fds, nfd) struct file *fp; int n = 0; - FILEDESC_LOCK(fdp); + FILEDESC_SLOCK(fdp); for (i = 0; i < nfd; i++, fds++) { if (fds->fd >= fdp->fd_nfiles) { fds->revents = POLLNVAL; @@ -997,7 +996,7 @@ pollscan(td, fds, nfd) } } } - FILEDESC_UNLOCK(fdp); + FILEDESC_SUNLOCK(fdp); td->td_retval[0] = n; return (0); } diff --git a/sys/kern/uipc_mqueue.c b/sys/kern/uipc_mqueue.c index 4516212..f23c621 100644 --- a/sys/kern/uipc_mqueue.c +++ b/sys/kern/uipc_mqueue.c @@ -2009,14 +2009,14 @@ kmq_open(struct thread *td, struct kmq_open_args *uap) FILE_LOCK(fp); fp->f_flag = (flags & (FREAD | FWRITE | O_NONBLOCK)); fp->f_type = DTYPE_MQUEUE; - fp->f_ops = &mqueueops; fp->f_data = pn; + fp->f_ops = &mqueueops; FILE_UNLOCK(fp); - FILEDESC_LOCK_FAST(fdp); + FILEDESC_XLOCK(fdp); if (fdp->fd_ofiles[fd] == fp) fdp->fd_ofileflags[fd] |= UF_EXCLOSE; - FILEDESC_UNLOCK_FAST(fdp); + FILEDESC_XUNLOCK(fdp); td->td_retval[0] = fd; fdrop(fp, td); return (0); @@ -2197,14 +2197,14 @@ kmq_notify(struct thread *td, struct kmq_notify_args *uap) if (error) return (error); again: - FILEDESC_LOCK_FAST(fdp); + FILEDESC_SLOCK(fdp); if (fget_locked(fdp, uap->mqd) != fp) { - FILEDESC_UNLOCK_FAST(fdp); + FILEDESC_SUNLOCK(fdp); error = EBADF; goto out; } mtx_lock(&mq->mq_mutex); - FILEDESC_UNLOCK_FAST(fdp); + FILEDESC_SUNLOCK(fdp); if (uap->sigev != NULL) { if (mq->mq_notifier != NULL) { error = EBUSY; @@ -2267,7 +2267,8 @@ mqueue_fdclose(struct thread *td, int fd, struct file *fp) struct mqueue *mq; fdp = td->td_proc->p_fd; - FILEDESC_LOCK_ASSERT(fdp, MA_OWNED); + FILEDESC_LOCK_ASSERT(fdp); + if (fp->f_ops == &mqueueops) { mq = FPTOMQ(fp); mtx_lock(&mq->mq_mutex); @@ -2295,7 +2296,7 @@ mq_proc_exit(void *arg __unused, struct proc *p) int i; fdp = p->p_fd; - FILEDESC_LOCK_FAST(fdp); + FILEDESC_SLOCK(fdp); for (i = 0; i < fdp->fd_nfiles; ++i) { fp = fget_locked(fdp, i); if (fp != NULL && fp->f_ops == &mqueueops) { @@ -2305,7 +2306,7 @@ mq_proc_exit(void *arg __unused, struct proc *p) mtx_unlock(&mq->mq_mutex); } } - FILEDESC_UNLOCK_FAST(fdp); + FILEDESC_SUNLOCK(fdp); KASSERT(LIST_EMPTY(&p->p_mqnotifier), ("mq notifiers left")); } @@ -2363,9 +2364,7 @@ mqf_close(struct file *fp, struct thread *td) { struct mqfs_node *pn; - FILE_LOCK(fp); fp->f_ops = &badfileops; - FILE_UNLOCK(fp); pn = fp->f_data; fp->f_data = NULL; sx_xlock(&mqfs_data.mi_lock); diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c index fd2a208..0c4efbf 100644 --- a/sys/kern/uipc_syscalls.c +++ b/sys/kern/uipc_syscalls.c @@ -124,7 +124,7 @@ getsock(struct filedesc *fdp, int fd, struct file **fpp, u_int *fflagp) if (fdp == NULL) error = EBADF; else { - FILEDESC_LOCK_FAST(fdp); + FILEDESC_SLOCK(fdp); fp = fget_locked(fdp, fd); if (fp == NULL) error = EBADF; @@ -137,7 +137,7 @@ getsock(struct filedesc *fdp, int fd, struct file **fpp, u_int *fflagp) *fflagp = fp->f_flag; error = 0; } - FILEDESC_UNLOCK_FAST(fdp); + FILEDESC_SUNLOCK(fdp); } *fpp = fp; return (error); @@ -182,12 +182,17 @@ socket(td, uap) if (error) { fdclose(fdp, fp, fd, td); } else { - FILEDESC_LOCK_FAST(fdp); + /* + * XXXRW: The logic here seems wrong -- shouldn't it be + * locking the file, not the filedesc? Other threads could + * already have a reference to the socket by now. + */ + FILE_LOCK(fp); fp->f_data = so; /* already has ref count */ fp->f_flag = FREAD|FWRITE; - fp->f_ops = &socketops; fp->f_type = DTYPE_SOCKET; - FILEDESC_UNLOCK_FAST(fdp); + fp->f_ops = &socketops; + FILE_UNLOCK(fp); td->td_retval[0] = fd; } fdrop(fp, td); @@ -434,8 +439,8 @@ kern_accept(struct thread *td, int s, struct sockaddr **name, FILE_LOCK(nfp); nfp->f_data = so; /* nfp has ref count from falloc */ nfp->f_flag = fflag; - nfp->f_ops = &socketops; nfp->f_type = DTYPE_SOCKET; + nfp->f_ops = &socketops; FILE_UNLOCK(nfp); /* Sync socket nonblocking/async state with file flags */ tmp = fflag & FNONBLOCK; @@ -656,13 +661,13 @@ socketpair(td, uap) } FILE_LOCK(fp1); fp1->f_flag = FREAD|FWRITE; - fp1->f_ops = &socketops; fp1->f_type = DTYPE_SOCKET; + fp1->f_ops = &socketops; FILE_UNLOCK(fp1); FILE_LOCK(fp2); fp2->f_flag = FREAD|FWRITE; - fp2->f_ops = &socketops; fp2->f_type = DTYPE_SOCKET; + fp2->f_ops = &socketops; FILE_UNLOCK(fp2); so1 = so2 = NULL; error = copyout(sv, uap->rsv, 2 * sizeof (int)); @@ -2322,8 +2327,8 @@ sctp_peeloff(td, uap) FILE_LOCK(nfp); nfp->f_data = so; nfp->f_flag = fflag; - nfp->f_ops = &socketops; nfp->f_type = DTYPE_SOCKET; + nfp->f_ops = &socketops; FILE_UNLOCK(nfp); noconnection: diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c index 79da63b..2895346 100644 --- a/sys/kern/uipc_usrreq.c +++ b/sys/kern/uipc_usrreq.c @@ -1579,10 +1579,10 @@ unp_externalize(struct mbuf *control, struct mbuf **controlp) unp_freerights(rp, newfds); goto next; } - FILEDESC_LOCK(td->td_proc->p_fd); + FILEDESC_XLOCK(td->td_proc->p_fd); /* if the new FD's will not fit free them. */ if (!fdavail(td, newfds)) { - FILEDESC_UNLOCK(td->td_proc->p_fd); + FILEDESC_XUNLOCK(td->td_proc->p_fd); error = EMSGSIZE; unp_freerights(rp, newfds); goto next; @@ -1597,7 +1597,7 @@ unp_externalize(struct mbuf *control, struct mbuf **controlp) *controlp = sbcreatecontrol(NULL, newlen, SCM_RIGHTS, SOL_SOCKET); if (*controlp == NULL) { - FILEDESC_UNLOCK(td->td_proc->p_fd); + FILEDESC_XUNLOCK(td->td_proc->p_fd); error = E2BIG; unp_freerights(rp, newfds); goto next; @@ -1616,7 +1616,7 @@ unp_externalize(struct mbuf *control, struct mbuf **controlp) unp_rights--; *fdp++ = f; } - FILEDESC_UNLOCK(td->td_proc->p_fd); + FILEDESC_XUNLOCK(td->td_proc->p_fd); } else { /* We can just copy anything else across. */ if (error || controlp == NULL) @@ -1738,23 +1738,24 @@ unp_internalize(struct mbuf **controlp, struct thread *td) * files. If not, reject the entire operation. */ fdp = data; - FILEDESC_LOCK(fdescp); + FILEDESC_SLOCK(fdescp); for (i = 0; i < oldfds; i++) { fd = *fdp++; if ((unsigned)fd >= fdescp->fd_nfiles || fdescp->fd_ofiles[fd] == NULL) { - FILEDESC_UNLOCK(fdescp); + FILEDESC_SUNLOCK(fdescp); error = EBADF; goto out; } fp = fdescp->fd_ofiles[fd]; if (!(fp->f_ops->fo_flags & DFLAG_PASSABLE)) { - FILEDESC_UNLOCK(fdescp); + FILEDESC_SUNLOCK(fdescp); error = EOPNOTSUPP; goto out; } } + /* * Now replace the integer FDs with pointers to * the associated global file table entry.. @@ -1763,7 +1764,7 @@ unp_internalize(struct mbuf **controlp, struct thread *td) *controlp = sbcreatecontrol(NULL, newlen, SCM_RIGHTS, SOL_SOCKET); if (*controlp == NULL) { - FILEDESC_UNLOCK(fdescp); + FILEDESC_SUNLOCK(fdescp); error = E2BIG; goto out; } @@ -1780,7 +1781,7 @@ unp_internalize(struct mbuf **controlp, struct thread *td) FILE_UNLOCK(fp); unp_rights++; } - FILEDESC_UNLOCK(fdescp); + FILEDESC_SUNLOCK(fdescp); break; case SCM_TIMESTAMP: diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c index 44005b0..9980803 100644 --- a/sys/kern/vfs_cache.c +++ b/sys/kern/vfs_cache.c @@ -717,10 +717,10 @@ kern___getcwd(struct thread *td, u_char *buf, enum uio_seg bufseg, u_int buflen) tmpbuf = malloc(buflen, M_TEMP, M_WAITOK); fdp = td->td_proc->p_fd; mtx_lock(&Giant); - FILEDESC_LOCK(fdp); + FILEDESC_SLOCK(fdp); error = vn_fullpath1(td, fdp->fd_cdir, fdp->fd_rdir, tmpbuf, &bp, buflen); - FILEDESC_UNLOCK(fdp); + FILEDESC_SUNLOCK(fdp); mtx_unlock(&Giant); if (!error) { @@ -771,9 +771,9 @@ vn_fullpath(struct thread *td, struct vnode *vn, char **retbuf, char **freebuf) buf = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); fdp = td->td_proc->p_fd; - FILEDESC_LOCK(fdp); + FILEDESC_SLOCK(fdp); error = vn_fullpath1(td, vn, fdp->fd_rdir, buf, retbuf, MAXPATHLEN); - FILEDESC_UNLOCK(fdp); + FILEDESC_SUNLOCK(fdp); if (!error) *freebuf = buf; diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c index e38ac71..ad801f6 100644 --- a/sys/kern/vfs_lookup.c +++ b/sys/kern/vfs_lookup.c @@ -188,14 +188,14 @@ namei(struct nameidata *ndp) /* * Get starting point for the translation. */ - FILEDESC_LOCK(fdp); + FILEDESC_SLOCK(fdp); ndp->ni_rootdir = fdp->fd_rdir; ndp->ni_topdir = fdp->fd_jdir; dp = fdp->fd_cdir; vfslocked = VFS_LOCK_GIANT(dp->v_mount); VREF(dp); - FILEDESC_UNLOCK(fdp); + FILEDESC_SUNLOCK(fdp); for (;;) { /* * Check if root directory should replace current directory. diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c index d4a2f10..08879fd 100644 --- a/sys/kern/vfs_mount.c +++ b/sys/kern/vfs_mount.c @@ -1406,7 +1406,7 @@ set_rootvnode(struct thread *td) panic("Cannot find root vnode"); p = td->td_proc; - FILEDESC_LOCK(p->p_fd); + FILEDESC_SLOCK(p->p_fd); if (p->p_fd->fd_cdir != NULL) vrele(p->p_fd->fd_cdir); @@ -1418,7 +1418,7 @@ set_rootvnode(struct thread *td) p->p_fd->fd_rdir = rootvnode; VREF(rootvnode); - FILEDESC_UNLOCK(p->p_fd); + FILEDESC_SUNLOCK(p->p_fd); VOP_UNLOCK(rootvnode, 0, td); } diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index d380943..c7b278e 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -715,10 +715,10 @@ fchdir(td, uap) } VOP_UNLOCK(vp, 0, td); VFS_UNLOCK_GIANT(vfslocked); - FILEDESC_LOCK_FAST(fdp); + FILEDESC_XLOCK(fdp); vpold = fdp->fd_cdir; fdp->fd_cdir = vp; - FILEDESC_UNLOCK_FAST(fdp); + FILEDESC_XUNLOCK(fdp); vfslocked = VFS_LOCK_GIANT(vpold->v_mount); vrele(vpold); VFS_UNLOCK_GIANT(vfslocked); @@ -767,10 +767,10 @@ kern_chdir(struct thread *td, char *path, enum uio_seg pathseg) VOP_UNLOCK(nd.ni_vp, 0, td); VFS_UNLOCK_GIANT(vfslocked); NDFREE(&nd, NDF_ONLY_PNBUF); - FILEDESC_LOCK_FAST(fdp); + FILEDESC_XLOCK(fdp); vp = fdp->fd_cdir; fdp->fd_cdir = nd.ni_vp; - FILEDESC_UNLOCK_FAST(fdp); + FILEDESC_XUNLOCK(fdp); vfslocked = VFS_LOCK_GIANT(vp->v_mount); vrele(vp); VFS_UNLOCK_GIANT(vfslocked); @@ -789,7 +789,8 @@ chroot_refuse_vdir_fds(fdp) struct file *fp; int fd; - FILEDESC_LOCK_ASSERT(fdp, MA_OWNED); + FILEDESC_LOCK_ASSERT(fdp); + for (fd = 0; fd < fdp->fd_nfiles ; fd++) { fp = fget_locked(fdp, fd); if (fp == NULL) @@ -905,12 +906,12 @@ change_root(vp, td) VFS_ASSERT_GIANT(vp->v_mount); fdp = td->td_proc->p_fd; - FILEDESC_LOCK(fdp); + FILEDESC_XLOCK(fdp); if (chroot_allow_open_directories == 0 || (chroot_allow_open_directories == 1 && fdp->fd_rdir != rootvnode)) { error = chroot_refuse_vdir_fds(fdp); if (error) { - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); return (error); } } @@ -921,7 +922,7 @@ change_root(vp, td) fdp->fd_jdir = vp; VREF(fdp->fd_jdir); } - FILEDESC_UNLOCK(fdp); + FILEDESC_XUNLOCK(fdp); vfslocked = VFS_LOCK_GIANT(oldvp->v_mount); vrele(oldvp); VFS_UNLOCK_GIANT(vfslocked); @@ -1024,18 +1025,16 @@ kern_open(struct thread *td, char *path, enum uio_seg pathseg, int flags, NDFREE(&nd, NDF_ONLY_PNBUF); vp = nd.ni_vp; - FILEDESC_LOCK_FAST(fdp); FILE_LOCK(fp); fp->f_vnode = vp; if (fp->f_data == NULL) fp->f_data = vp; fp->f_flag = flags & FMASK; - if (fp->f_ops == &badfileops) - fp->f_ops = &vnops; fp->f_seqcount = 1; fp->f_type = (vp->v_type == VFIFO ? DTYPE_FIFO : DTYPE_VNODE); + if (fp->f_ops == &badfileops) + fp->f_ops = &vnops; FILE_UNLOCK(fp); - FILEDESC_UNLOCK_FAST(fdp); VOP_UNLOCK(vp, 0, td); if (flags & (O_EXLOCK | O_SHLOCK)) { @@ -1183,10 +1182,10 @@ restart: return (EEXIST); } else { VATTR_NULL(&vattr); - FILEDESC_LOCK_FAST(td->td_proc->p_fd); + FILEDESC_SLOCK(td->td_proc->p_fd); vattr.va_mode = (mode & ALLPERMS) & ~td->td_proc->p_fd->fd_cmask; - FILEDESC_UNLOCK_FAST(td->td_proc->p_fd); + FILEDESC_SUNLOCK(td->td_proc->p_fd); vattr.va_rdev = dev; whiteout = 0; @@ -1296,9 +1295,9 @@ restart: } VATTR_NULL(&vattr); vattr.va_type = VFIFO; - FILEDESC_LOCK_FAST(td->td_proc->p_fd); + FILEDESC_SLOCK(td->td_proc->p_fd); vattr.va_mode = (mode & ALLPERMS) & ~td->td_proc->p_fd->fd_cmask; - FILEDESC_UNLOCK_FAST(td->td_proc->p_fd); + FILEDESC_SUNLOCK(td->td_proc->p_fd); #ifdef MAC error = mac_check_vnode_create(td->td_ucred, nd.ni_dvp, &nd.ni_cnd, &vattr); @@ -1511,9 +1510,9 @@ restart: goto restart; } VATTR_NULL(&vattr); - FILEDESC_LOCK_FAST(td->td_proc->p_fd); + FILEDESC_SLOCK(td->td_proc->p_fd); vattr.va_mode = ACCESSPERMS &~ td->td_proc->p_fd->fd_cmask; - FILEDESC_UNLOCK_FAST(td->td_proc->p_fd); + FILEDESC_SUNLOCK(td->td_proc->p_fd); #ifdef MAC vattr.va_type = VLNK; error = mac_check_vnode_create(td->td_ucred, nd.ni_dvp, &nd.ni_cnd, @@ -3395,9 +3394,9 @@ restart: } VATTR_NULL(&vattr); vattr.va_type = VDIR; - FILEDESC_LOCK_FAST(td->td_proc->p_fd); + FILEDESC_SLOCK(td->td_proc->p_fd); vattr.va_mode = (mode & ACCESSPERMS) &~ td->td_proc->p_fd->fd_cmask; - FILEDESC_UNLOCK_FAST(td->td_proc->p_fd); + FILEDESC_SUNLOCK(td->td_proc->p_fd); #ifdef MAC error = mac_check_vnode_create(td->td_ucred, nd.ni_dvp, &nd.ni_cnd, &vattr); @@ -3784,11 +3783,11 @@ umask(td, uap) { register struct filedesc *fdp; - FILEDESC_LOCK_FAST(td->td_proc->p_fd); + FILEDESC_XLOCK(td->td_proc->p_fd); fdp = td->td_proc->p_fd; td->td_retval[0] = fdp->fd_cmask; fdp->fd_cmask = uap->newmask & ALLPERMS; - FILEDESC_UNLOCK_FAST(td->td_proc->p_fd); + FILEDESC_XUNLOCK(td->td_proc->p_fd); return (0); } @@ -3864,7 +3863,7 @@ getvnode(fdp, fd, fpp) if (fdp == NULL) error = EBADF; else { - FILEDESC_LOCK(fdp); + FILEDESC_SLOCK(fdp); if ((u_int)fd >= fdp->fd_nfiles || (fp = fdp->fd_ofiles[fd]) == NULL) error = EBADF; @@ -3875,7 +3874,7 @@ getvnode(fdp, fd, fpp) fhold(fp); error = 0; } - FILEDESC_UNLOCK(fdp); + FILEDESC_SUNLOCK(fdp); } *fpp = fp; return (error); @@ -4104,11 +4103,13 @@ fhopen(td, uap) /* An extra reference on `nfp' has been held for us by falloc(). */ fp = nfp; + FILE_LOCK(nfp); nfp->f_vnode = vp; nfp->f_data = vp; nfp->f_flag = fmode & FMASK; - nfp->f_ops = &vnops; nfp->f_type = DTYPE_VNODE; + nfp->f_ops = &vnops; + FILE_UNLOCK(nfp); if (fmode & (O_EXLOCK | O_SHLOCK)) { lf.l_whence = SEEK_SET; lf.l_start = 0; |