summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjeff <jeff@FreeBSD.org>2006-02-01 09:34:32 +0000
committerjeff <jeff@FreeBSD.org>2006-02-01 09:34:32 +0000
commitb2e03708cb3aa9bcb59e865233cd80c8f6c0eb64 (patch)
tree31148bcc2771afc3b68a4e8012573dcabc717e68
parent3f7fc03f58b6d7e710661232b87d5932117c195d (diff)
downloadFreeBSD-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.c18
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);
OpenPOWER on IntegriCloud