diff options
author | jeff <jeff@FreeBSD.org> | 2006-02-01 09:34:32 +0000 |
---|---|---|
committer | jeff <jeff@FreeBSD.org> | 2006-02-01 09:34:32 +0000 |
commit | b2e03708cb3aa9bcb59e865233cd80c8f6c0eb64 (patch) | |
tree | 31148bcc2771afc3b68a4e8012573dcabc717e68 | |
parent | 3f7fc03f58b6d7e710661232b87d5932117c195d (diff) | |
download | FreeBSD-src-b2e03708cb3aa9bcb59e865233cd80c8f6c0eb64.zip FreeBSD-src-b2e03708cb3aa9bcb59e865233cd80c8f6c0eb64.tar.gz |
- Solve a problem where a vput could be called on an outgoing directory
without Giant held. Do this by tracking the vfslocked state for
the directory seperate from the child. This is only important
in the case where we cross a mountpoint.
Sponsored by: Isilon Systems, Inc.
MFC After: 3 days
-rw-r--r-- | sys/kern/vfs_lookup.c | 18 |
1 files changed, 13 insertions, 5 deletions
diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c index 8ad90bb..42327ca 100644 --- a/sys/kern/vfs_lookup.c +++ b/sys/kern/vfs_lookup.c @@ -60,7 +60,7 @@ __FBSDID("$FreeBSD$"); #include <vm/uma.h> -#define NAMEI_DIAGNOSTIC 1 +#define NAMEI_DIAGNOSTIC 1 #undef NAMEI_DIAGNOSTIC /* @@ -352,11 +352,13 @@ lookup(ndp) struct thread *td = cnp->cn_thread; int vfslocked; int tvfslocked; + int dvfslocked; /* * Setup: break out flag bits into variables. */ vfslocked = (ndp->ni_cnd.cn_flags & GIANTHELD) != 0; + dvfslocked = 0; ndp->ni_cnd.cn_flags &= ~GIANTHELD; wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT); KASSERT(cnp->cn_nameiop == LOOKUP || wantparent, @@ -623,9 +625,8 @@ unionlookup: if (vfs_busy(mp, 0, 0, td)) continue; vput(dp); - tvfslocked = VFS_LOCK_GIANT(mp); - VFS_UNLOCK_GIANT(vfslocked); - vfslocked = tvfslocked; + dvfslocked = vfslocked; + vfslocked = VFS_LOCK_GIANT(mp); VOP_UNLOCK(ndp->ni_dvp, 0, td); error = VFS_ROOT(mp, cnp->cn_lkflags, &tdp, td); VOP_LOCK(ndp->ni_dvp, cnp->cn_lkflags | LK_RETRY, td); @@ -687,6 +688,8 @@ nextname: vput(ndp->ni_dvp); else vrele(ndp->ni_dvp); + VFS_UNLOCK_GIANT(dvfslocked); + dvfslocked = 0; goto dirloop; } /* @@ -706,13 +709,17 @@ nextname: vput(ndp->ni_dvp); else vrele(ndp->ni_dvp); + VFS_UNLOCK_GIANT(dvfslocked); + dvfslocked = 0; } else if ((cnp->cn_flags & LOCKPARENT) == 0 && ndp->ni_dvp != dp) VOP_UNLOCK(ndp->ni_dvp, 0, td); if ((cnp->cn_flags & LOCKLEAF) == 0) VOP_UNLOCK(dp, 0, td); success: - if (vfslocked) + if (vfslocked && dvfslocked) + VFS_UNLOCK_GIANT(dvfslocked); /* Only need one */ + if (vfslocked || dvfslocked) ndp->ni_cnd.cn_flags |= GIANTHELD; return (0); @@ -725,6 +732,7 @@ bad: if (!dpunlocked) vput(dp); VFS_UNLOCK_GIANT(vfslocked); + VFS_UNLOCK_GIANT(dvfslocked); ndp->ni_cnd.cn_flags &= ~GIANTHELD; ndp->ni_vp = NULL; return (error); |