diff options
author | Pawel Jakub Dawidek <pjd@FreeBSD.org> | 2007-09-21 10:16:56 +0000 |
---|---|---|
committer | Pawel Jakub Dawidek <pjd@FreeBSD.org> | 2007-09-21 10:16:56 +0000 |
commit | b4d7e2983c2f40139f151f1e0fa38581337d6aa0 (patch) | |
tree | a5b1aba6df8555ac8e6d2f48e313aecb9a042293 /sys/kern/vfs_cache.c | |
parent | e84091cb52120dd6c88d0570581c4563f4f80fbb (diff) | |
download | src-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.c | 21 |
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; |