Index: cddl/compat/opensolaris/kern/opensolaris_kobj.c =================================================================== --- cddl/compat/opensolaris/kern/opensolaris_kobj.c (revision 260176) +++ cddl/compat/opensolaris/kern/opensolaris_kobj.c (working copy) @@ -72,7 +72,7 @@ int error, flags, vfslocked; fd = td->td_proc->p_fd; - FILEDESC_XLOCK(fd); + FILEDESC_XLOCK_DIR(fd); if (fd->fd_rdir == NULL) { fd->fd_rdir = rootvnode; vref(fd->fd_rdir); @@ -81,7 +81,7 @@ fd->fd_cdir = rootvnode; vref(fd->fd_cdir); } - FILEDESC_XUNLOCK(fd); + FILEDESC_XUNLOCK_DIR(fd); flags = FREAD | O_NOFOLLOW; NDINIT(&nd, LOOKUP, MPSAFE, UIO_SYSSPACE, file, td); Index: cddl/compat/opensolaris/sys/vnode.h =================================================================== --- cddl/compat/opensolaris/sys/vnode.h (revision 260176) +++ cddl/compat/opensolaris/sys/vnode.h (working copy) @@ -180,7 +180,7 @@ ASSERT(umask == 0); fdc = td->td_proc->p_fd; - FILEDESC_XLOCK(fdc); + FILEDESC_XLOCK_DIR(fdc); if (fdc->fd_rdir == NULL) { fdc->fd_rdir = rootvnode; vref(fdc->fd_rdir); @@ -189,7 +189,7 @@ fdc->fd_cdir = rootvnode; vref(fdc->fd_rdir); } - FILEDESC_XUNLOCK(fdc); + FILEDESC_XUNLOCK_DIR(fdc); if (startvp != NULL) vref(startvp); Index: kern/kern_descrip.c =================================================================== --- kern/kern_descrip.c (revision 260176) +++ kern/kern_descrip.c (working copy) @@ -1758,8 +1758,9 @@ newfdp = malloc(sizeof *newfdp, M_FILEDESC, M_WAITOK | M_ZERO); FILEDESC_LOCK_INIT(&newfdp->fd_fd); + FILEDESC_LOCK_INIT_DIR(&newfdp->fd_fd); if (fdp != NULL) { - FILEDESC_XLOCK(fdp); + FILEDESC_SLOCK_DIR(fdp); newfdp->fd_fd.fd_cdir = fdp->fd_cdir; if (newfdp->fd_fd.fd_cdir) VREF(newfdp->fd_fd.fd_cdir); @@ -1769,7 +1770,7 @@ newfdp->fd_fd.fd_jdir = fdp->fd_jdir; if (newfdp->fd_fd.fd_jdir) VREF(newfdp->fd_fd.fd_jdir); - FILEDESC_XUNLOCK(fdp); + FILEDESC_SUNLOCK_DIR(fdp); } /* Create the file descriptor table. */ @@ -1810,6 +1811,7 @@ if (i > 0) return; + FILEDESC_LOCK_DESTROY_DIR(fdp); FILEDESC_LOCK_DESTROY(fdp); fdp0 = (struct filedesc0 *)fdp; while ((ft = SLIST_FIRST(&fdp0->fd_free)) != NULL) { @@ -2014,6 +2016,7 @@ (void) closef(fp, td); } } + FILEDESC_XLOCK_DIR(fdp); FILEDESC_XLOCK(fdp); /* XXX This should happen earlier. */ @@ -2034,6 +2037,7 @@ fdp->fd_rdir = NULL; jdir = fdp->fd_jdir; fdp->fd_jdir = NULL; + FILEDESC_XUNLOCK_DIR(fdp); FILEDESC_XUNLOCK(fdp); if (cdir) { @@ -2831,7 +2835,7 @@ fdp = fdhold(p); if (fdp == NULL) continue; - FILEDESC_XLOCK(fdp); + FILEDESC_XLOCK_DIR(fdp); if (fdp->fd_cdir == olddp) { vref(newdp); fdp->fd_cdir = newdp; @@ -2847,7 +2851,7 @@ fdp->fd_jdir = newdp; nrele++; } - FILEDESC_XUNLOCK(fdp); + FILEDESC_XUNLOCK_DIR(fdp); fddrop(fdp); } sx_sunlock(&allproc_lock); @@ -3061,6 +3065,7 @@ if (fdp == NULL) return (ENOENT); kif = malloc(sizeof(*kif), M_TEMP, M_WAITOK); + FILEDESC_SLOCK_DIR(fdp); FILEDESC_SLOCK(fdp); if (fdp->fd_cdir != NULL) export_vnode_for_osysctl(fdp->fd_cdir, KF_FD_TYPE_CWD, kif, @@ -3071,6 +3076,7 @@ if (fdp->fd_jdir != NULL) export_vnode_for_osysctl(fdp->fd_jdir, KF_FD_TYPE_JAIL, kif, fdp, req); + FILEDESC_SUNLOCK_DIR(fdp); for (i = 0; i < fdp->fd_nfiles; i++) { if ((fp = fdp->fd_ofiles[i]) == NULL) continue; @@ -3439,6 +3445,7 @@ if (fdp == NULL) goto fail; efbuf->fdp = fdp; + FILEDESC_SLOCK_DIR(fdp); FILEDESC_SLOCK(fdp); /* working directory */ if (fdp->fd_cdir != NULL) { @@ -3461,6 +3468,7 @@ export_fd_to_sb(data, KF_TYPE_VNODE, KF_FD_TYPE_JAIL, FREAD, -1, -1, 0, 0, efbuf); } + FILEDESC_SUNLOCK_DIR(fdp); for (i = 0; i < fdp->fd_nfiles; i++) { if ((fp = fdp->fd_ofiles[i]) == NULL) continue; Index: kern/kern_proc.c =================================================================== --- kern/kern_proc.c (revision 260176) +++ kern/kern_proc.c (working copy) @@ -2582,9 +2582,9 @@ if (error != 0) return (error); - FILEDESC_SLOCK(p->p_fd); + FILEDESC_SLOCK_DIR(p->p_fd); fd_cmask = p->p_fd->fd_cmask; - FILEDESC_SUNLOCK(p->p_fd); + FILEDESC_SUNLOCK_DIR(p->p_fd); PRELE(p); error = SYSCTL_OUT(req, &fd_cmask, sizeof(fd_cmask)); return (error); Index: kern/subr_firmware.c =================================================================== --- kern/subr_firmware.c (revision 260176) +++ kern/subr_firmware.c (working copy) @@ -380,7 +380,7 @@ struct thread *td = curthread; struct proc *p = td->td_proc; - FILEDESC_XLOCK(p->p_fd); + FILEDESC_XLOCK_DIR(p->p_fd); if (p->p_fd->fd_cdir == NULL) { p->p_fd->fd_cdir = rootvnode; VREF(rootvnode); @@ -389,7 +389,7 @@ p->p_fd->fd_rdir = rootvnode; VREF(rootvnode); } - FILEDESC_XUNLOCK(p->p_fd); + FILEDESC_XUNLOCK_DIR(p->p_fd); free(arg, M_TEMP); } Index: kern/vfs_cache.c =================================================================== --- kern/vfs_cache.c (revision 260176) +++ kern/vfs_cache.c (working copy) @@ -1080,12 +1080,12 @@ tmpbuf = malloc(buflen, M_TEMP, M_WAITOK); fdp = td->td_proc->p_fd; - FILEDESC_SLOCK(fdp); + FILEDESC_SLOCK_DIR(fdp); cdir = fdp->fd_cdir; VREF(cdir); rdir = fdp->fd_rdir; VREF(rdir); - FILEDESC_SUNLOCK(fdp); + FILEDESC_SUNLOCK_DIR(fdp); error = vn_fullpath1(td, cdir, rdir, tmpbuf, &bp, buflen); vfslocked = VFS_LOCK_GIANT(rdir->v_mount); vrele(rdir); @@ -1148,10 +1148,10 @@ buf = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); fdp = td->td_proc->p_fd; - FILEDESC_SLOCK(fdp); + FILEDESC_SLOCK_DIR(fdp); rdir = fdp->fd_rdir; VREF(rdir); - FILEDESC_SUNLOCK(fdp); + FILEDESC_SUNLOCK_DIR(fdp); error = vn_fullpath1(td, vn, rdir, buf, retbuf, MAXPATHLEN); vfslocked = VFS_LOCK_GIANT(rdir->v_mount); vrele(rdir); Index: kern/vfs_lookup.c =================================================================== --- kern/vfs_lookup.c (revision 260176) +++ kern/vfs_lookup.c (working copy) @@ -201,7 +201,7 @@ /* * Get starting point for the translation. */ - FILEDESC_SLOCK(fdp); + FILEDESC_SLOCK_DIR(fdp); ndp->ni_rootdir = fdp->fd_rdir; ndp->ni_topdir = fdp->fd_jdir; @@ -239,7 +239,7 @@ #endif } if (error != 0 || dp != NULL) { - FILEDESC_SUNLOCK(fdp); + FILEDESC_SUNLOCK_DIR(fdp); if (error == 0 && dp->v_type != VDIR) { vfslocked = VFS_LOCK_GIANT(dp->v_mount); vrele(dp); @@ -259,7 +259,7 @@ if (dp == NULL) { dp = fdp->fd_cdir; VREF(dp); - FILEDESC_SUNLOCK(fdp); + FILEDESC_SUNLOCK_DIR(fdp); if (ndp->ni_startdir != NULL) { vfslocked = VFS_LOCK_GIANT(ndp->ni_startdir->v_mount); vrele(ndp->ni_startdir); Index: kern/vfs_mountroot.c =================================================================== --- kern/vfs_mountroot.c (revision 260176) +++ kern/vfs_mountroot.c (working copy) @@ -187,7 +187,7 @@ VOP_UNLOCK(rootvnode, 0); p = curthread->td_proc; - FILEDESC_XLOCK(p->p_fd); + FILEDESC_XLOCK_DIR(p->p_fd); if (p->p_fd->fd_cdir != NULL) vrele(p->p_fd->fd_cdir); @@ -199,7 +199,7 @@ p->p_fd->fd_rdir = rootvnode; VREF(rootvnode); - FILEDESC_XUNLOCK(p->p_fd); + FILEDESC_XUNLOCK_DIR(p->p_fd); } static int Index: kern/vfs_syscalls.c =================================================================== --- kern/vfs_syscalls.c (revision 260176) +++ kern/vfs_syscalls.c (working copy) @@ -783,10 +783,10 @@ } VOP_UNLOCK(vp, 0); VFS_UNLOCK_GIANT(vfslocked); - FILEDESC_XLOCK(fdp); + FILEDESC_XLOCK_DIR(fdp); vpold = fdp->fd_cdir; fdp->fd_cdir = vp; - FILEDESC_XUNLOCK(fdp); + FILEDESC_XUNLOCK_DIR(fdp); vfslocked = VFS_LOCK_GIANT(vpold->v_mount); vrele(vpold); VFS_UNLOCK_GIANT(vfslocked); @@ -835,10 +835,10 @@ VOP_UNLOCK(nd.ni_vp, 0); VFS_UNLOCK_GIANT(vfslocked); NDFREE(&nd, NDF_ONLY_PNBUF); - FILEDESC_XLOCK(fdp); + FILEDESC_XLOCK_DIR(fdp); vp = fdp->fd_cdir; fdp->fd_cdir = nd.ni_vp; - FILEDESC_XUNLOCK(fdp); + FILEDESC_XUNLOCK_DIR(fdp); vfslocked = VFS_LOCK_GIANT(vp->v_mount); vrele(vp); VFS_UNLOCK_GIANT(vfslocked); @@ -973,11 +973,13 @@ VFS_ASSERT_GIANT(vp->v_mount); fdp = td->td_proc->p_fd; + FILEDESC_XLOCK_DIR(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_XUNLOCK_DIR(fdp); FILEDESC_XUNLOCK(fdp); return (error); } @@ -989,6 +991,7 @@ fdp->fd_jdir = vp; VREF(fdp->fd_jdir); } + FILEDESC_XUNLOCK_DIR(fdp); FILEDESC_XUNLOCK(fdp); vfslocked = VFS_LOCK_GIANT(oldvp->v_mount); vrele(oldvp); @@ -4269,11 +4272,11 @@ { register struct filedesc *fdp; - FILEDESC_XLOCK(td->td_proc->p_fd); + FILEDESC_XLOCK_DIR(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_XUNLOCK(td->td_proc->p_fd); + FILEDESC_XUNLOCK_DIR(td->td_proc->p_fd); return (0); } Index: security/audit/audit_bsm_klib.c =================================================================== --- security/audit/audit_bsm_klib.c (revision 260176) +++ security/audit/audit_bsm_klib.c (working copy) @@ -475,7 +475,7 @@ copy = path; rvnp = cvnp = NULL; fdp = td->td_proc->p_fd; - FILEDESC_SLOCK(fdp); + FILEDESC_SLOCK_DIR(fdp); /* * Make sure that we handle the chroot(2) case. If there is an * alternate root directory, prepend it to the audited pathname. @@ -511,7 +511,7 @@ } else { needslash = 1; } - FILEDESC_SUNLOCK(fdp); + FILEDESC_SUNLOCK_DIR(fdp); /* * NB: We require that the supplied array be at least MAXPATHLEN bytes * long. If this is not the case, then we can run into serious trouble. Index: sys/filedesc.h =================================================================== --- sys/filedesc.h (revision 260176) +++ sys/filedesc.h (working copy) @@ -48,6 +48,7 @@ #define NDSLOTTYPE u_long struct filedesc { + struct sx fd_dirlock; struct file **fd_ofiles; /* file structures for open files */ char *fd_ofileflags; /* per-process open file flags */ struct vnode *fd_cdir; /* current directory */ @@ -60,7 +61,7 @@ u_short fd_cmask; /* mask for file creation */ u_short fd_refcnt; /* thread reference count */ u_short fd_holdcnt; /* hold count on structure + mutex */ - struct sx fd_sx; /* protects members of this struct */ + struct sx fd_fdlock; /* protects members of this struct */ struct kqlist fd_kqlist; /* list of kqueues on this filedesc */ int fd_holdleaderscount; /* block fdfree() for shared close() */ int fd_holdleaderswakeup; /* fdfree() needs wakeup */ @@ -93,13 +94,6 @@ #ifdef _KERNEL /* Lock a file descriptor table. */ -#define FILEDESC_LOCK_INIT(fdp) sx_init(&(fdp)->fd_sx, "filedesc structure") -#define FILEDESC_LOCK_DESTROY(fdp) sx_destroy(&(fdp)->fd_sx) -#define FILEDESC_LOCK(fdp) (&(fdp)->fd_sx) -#define FILEDESC_XLOCK(fdp) sx_xlock(&(fdp)->fd_sx) -#define FILEDESC_XUNLOCK(fdp) sx_xunlock(&(fdp)->fd_sx) -#define FILEDESC_SLOCK(fdp) sx_slock(&(fdp)->fd_sx) -#define FILEDESC_SUNLOCK(fdp) sx_sunlock(&(fdp)->fd_sx) #define FILEDESC_LOCK_ASSERT(fdp) sx_assert(&(fdp)->fd_sx, SX_LOCKED | \ SX_NOTRECURSED) @@ -106,6 +100,29 @@ #define FILEDESC_XLOCK_ASSERT(fdp) sx_assert(&(fdp)->fd_sx, SX_XLOCKED | \ SX_NOTRECURSED) +#define FILEDESC_LOCK_INIT(fdp) sx_init(&(fdp)->fd_fdlock, "filedesc fd lock") +#define FILEDESC_LOCK_DESTROY(fdp) sx_destroy(&(fdp)->fd_fdlock) +#define FILEDESC_LOCK(fdp) (&(fdp)->fd_fdlock) +#define FILEDESC_XLOCK(fdp) sx_xlock(&(fdp)->fd_fdlock) +#define FILEDESC_XUNLOCK(fdp) sx_xunlock(&(fdp)->fd_fdlock) +#define FILEDESC_SLOCK(fdp) sx_slock(&(fdp)->fd_fdlock) +#define FILEDESC_SUNLOCK(fdp) sx_sunlock(&(fdp)->fd_fdlock) + +#define FILEDESC_LOCK_INIT_DIR(fdp) sx_init(&(fdp)->fd_dirlock, "filedesc dir lock") +#define FILEDESC_LOCK_DESTROY_DIR(fdp) sx_destroy(&(fdp)->fd_dirlock) +#define FILEDESC_LOCK_DIR(fdp) (&(fdp)->fd_dirlock) +#define FILEDESC_XLOCK_DIR(fdp) sx_xlock(&(fdp)->fd_dirlock) +#define FILEDESC_XUNLOCK_DIR(fdp) sx_xunlock(&(fdp)->fd_dirlock) +#define FILEDESC_SLOCK_DIR(fdp) sx_slock(&(fdp)->fd_dirlock) +#define FILEDESC_SUNLOCK_DIR(fdp) sx_sunlock(&(fdp)->fd_dirlock) + +#define FILEDESC_LOCK_ASSERT(fdp) sx_assert(&(fdp)->fd_fdlock, SX_LOCKED | \ + SX_NOTRECURSED) +#define FILEDESC_XLOCK_ASSERT(fdp) sx_assert(&(fdp)->fd_fdlock, SX_XLOCKED | \ + SX_NOTRECURSED) +#define FILEDESC_UNLOCK_ASSERT(fdp) sx_assert(&(fdp)->fd_fdlock, SX_UNLOCKED) + + struct thread; int closef(struct file *fp, struct thread *td); Index: ufs/ffs/ffs_alloc.c =================================================================== --- ufs/ffs/ffs_alloc.c (revision 260176) +++ ufs/ffs/ffs_alloc.c (working copy) @@ -2929,10 +2929,10 @@ VOP_UNLOCK(vp, 0); VFS_UNLOCK_GIANT(vfslocked); fdp = td->td_proc->p_fd; - FILEDESC_XLOCK(fdp); + FILEDESC_XLOCK_DIR(fdp); vpold = fdp->fd_cdir; fdp->fd_cdir = vp; - FILEDESC_XUNLOCK(fdp); + FILEDESC_XUNLOCK_DIR(fdp); vfslocked = VFS_LOCK_GIANT(vpold->v_mount); vrele(vpold); VFS_UNLOCK_GIANT(vfslocked); @@ -2956,9 +2956,9 @@ /* * Now we get and lock the child directory containing "..". */ - FILEDESC_SLOCK(td->td_proc->p_fd); + FILEDESC_SLOCK_DIR(td->td_proc->p_fd); dvp = td->td_proc->p_fd->fd_cdir; - FILEDESC_SUNLOCK(td->td_proc->p_fd); + FILEDESC_SUNLOCK_DIR(td->td_proc->p_fd); if ((error = vget(dvp, LK_EXCLUSIVE, td)) != 0) { vput(fdvp); break; @@ -3116,10 +3116,10 @@ if (!vn_isdisk(devvp, NULL)) return (EINVAL); fdp = td->td_proc->p_fd; - FILEDESC_SLOCK(fdp); + FILEDESC_SLOCK_DIR(fdp); vp = fdp->fd_cdir; vref(vp); - FILEDESC_SUNLOCK(fdp); + FILEDESC_SUNLOCK_DIR(fdp); vfslocked = VFS_LOCK_GIANT(vp->v_mount); vn_lock(vp, LK_SHARED | LK_RETRY); /*