aboutsummaryrefslogtreecommitdiff
path: root/sys/kern/vfs_cache.c
diff options
context:
space:
mode:
authorPawel Jakub Dawidek <pjd@FreeBSD.org>2007-09-21 10:16:56 +0000
committerPawel Jakub Dawidek <pjd@FreeBSD.org>2007-09-21 10:16:56 +0000
commitb4d7e2983c2f40139f151f1e0fa38581337d6aa0 (patch)
treea5b1aba6df8555ac8e6d2f48e313aecb9a042293 /sys/kern/vfs_cache.c
parente84091cb52120dd6c88d0570581c4563f4f80fbb (diff)
downloadsrc-b4d7e2983c2f40139f151f1e0fa38581337d6aa0.tar.gz
src-b4d7e2983c2f40139f151f1e0fa38581337d6aa0.zip
Fix some locking cases where we ask for exclusively locked vnode, but we get
shared locked vnode in instead when vfs.lookup_shared is set to 1. Discussed with: kib, kris Tested by: kris Approved by: re (kensmith)
Notes
Notes: svn path=/head/; revision=172274
Diffstat (limited to 'sys/kern/vfs_cache.c')
-rw-r--r--sys/kern/vfs_cache.c21
1 files changed, 17 insertions, 4 deletions
diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c
index 43428b3bee5c..7c1e42836396 100644
--- a/sys/kern/vfs_cache.c
+++ b/sys/kern/vfs_cache.c
@@ -314,6 +314,7 @@ cache_lookup(dvp, vpp, cnp)
struct componentname *cnp;
{
struct namecache *ncp;
+ struct thread *td;
u_int32_t hash;
int error, ltype;
@@ -321,6 +322,7 @@ cache_lookup(dvp, vpp, cnp)
cnp->cn_flags &= ~MAKEENTRY;
return (0);
}
+ td = cnp->cn_thread;
retry:
CACHE_LOCK();
numcalls++;
@@ -419,18 +421,29 @@ success:
if (dvp == *vpp) { /* lookup on "." */
VREF(*vpp);
CACHE_UNLOCK();
+ /*
+ * When we lookup "." we still can be asked to lock it
+ * differently...
+ */
+ ltype = cnp->cn_lkflags & (LK_SHARED | LK_EXCLUSIVE);
+ if (ltype == VOP_ISLOCKED(*vpp, td))
+ return (-1);
+ else if (ltype == LK_EXCLUSIVE)
+ vn_lock(*vpp, LK_UPGRADE | LK_RETRY, td);
return (-1);
}
ltype = 0; /* silence gcc warning */
if (cnp->cn_flags & ISDOTDOT) {
- ltype = VOP_ISLOCKED(dvp, cnp->cn_thread);
- VOP_UNLOCK(dvp, 0, cnp->cn_thread);
+ ltype = VOP_ISLOCKED(dvp, td);
+ VOP_UNLOCK(dvp, 0, td);
}
VI_LOCK(*vpp);
CACHE_UNLOCK();
- error = vget(*vpp, cnp->cn_lkflags | LK_INTERLOCK, cnp->cn_thread);
+ error = vget(*vpp, cnp->cn_lkflags | LK_INTERLOCK, td);
if (cnp->cn_flags & ISDOTDOT)
- vn_lock(dvp, ltype | LK_RETRY, cnp->cn_thread);
+ vn_lock(dvp, ltype | LK_RETRY, td);
+ if ((cnp->cn_flags & ISLASTCN) && (cnp->cn_lkflags & LK_EXCLUSIVE))
+ ASSERT_VOP_ELOCKED(*vpp, "cache_lookup");
if (error) {
*vpp = NULL;
goto retry;