summaryrefslogtreecommitdiffstats
path: root/sys/kern/vfs_cache.c
diff options
context:
space:
mode:
authorpjd <pjd@FreeBSD.org>2007-05-25 22:23:38 +0000
committerpjd <pjd@FreeBSD.org>2007-05-25 22:23:38 +0000
commitf9fef47d890708fdf9c930956ec9957d1eb3431e (patch)
tree771377b46816c640072b1234d5d63b6c3b5f65bd /sys/kern/vfs_cache.c
parent29aee808dff1626ff8e4f4cf47d359c598b53403 (diff)
downloadFreeBSD-src-f9fef47d890708fdf9c930956ec9957d1eb3431e.zip
FreeBSD-src-f9fef47d890708fdf9c930956ec9957d1eb3431e.tar.gz
To avoid a deadlock when handling .. directory during a lookup, we unlock
parent vnode and relock it after locking child vnode. The problem was that we always relock it exclusively, even when it was share-locked. Discussed with: jeff
Diffstat (limited to 'sys/kern/vfs_cache.c')
-rw-r--r--sys/kern/vfs_cache.c9
1 files changed, 6 insertions, 3 deletions
diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c
index 088425e..a174c45 100644
--- a/sys/kern/vfs_cache.c
+++ b/sys/kern/vfs_cache.c
@@ -315,7 +315,7 @@ cache_lookup(dvp, vpp, cnp)
{
struct namecache *ncp;
u_int32_t hash;
- int error;
+ int error, ltype;
if (!doingcache) {
cnp->cn_flags &= ~MAKEENTRY;
@@ -421,13 +421,16 @@ success:
CACHE_UNLOCK();
return (-1);
}
- if (cnp->cn_flags & ISDOTDOT)
+ ltype = 0; /* silence gcc warning */
+ if (cnp->cn_flags & ISDOTDOT) {
+ ltype = VOP_ISLOCKED(dvp, cnp->cn_thread);
VOP_UNLOCK(dvp, 0, cnp->cn_thread);
+ }
VI_LOCK(*vpp);
CACHE_UNLOCK();
error = vget(*vpp, cnp->cn_lkflags | LK_INTERLOCK, cnp->cn_thread);
if (cnp->cn_flags & ISDOTDOT)
- vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, cnp->cn_thread);
+ vn_lock(dvp, ltype | LK_RETRY, cnp->cn_thread);
if (error) {
*vpp = NULL;
goto retry;
OpenPOWER on IntegriCloud