diff options
author | kan <kan@FreeBSD.org> | 2005-09-15 19:21:26 +0000 |
---|---|---|
committer | kan <kan@FreeBSD.org> | 2005-09-15 19:21:26 +0000 |
commit | b4bff5a977cedb926687495a528a0d6a2c7c872b (patch) | |
tree | 5d61712c08cd91fd141dbbde7a675238b9c094d5 /sys/fs/nullfs | |
parent | 00aec4049358a50ebf9722344e26dac31cb64c76 (diff) | |
download | FreeBSD-src-b4bff5a977cedb926687495a528a0d6a2c7c872b.zip FreeBSD-src-b4bff5a977cedb926687495a528a0d6a2c7c872b.tar.gz |
Handle a race condition where NULLFS vnode can be cleaned while threads
can still be asleep waiting for lowervp lock.
Tested by: kkenn
Discussed with: ssouhlal, jeffr
Diffstat (limited to 'sys/fs/nullfs')
-rw-r--r-- | sys/fs/nullfs/null_vnops.c | 32 |
1 files changed, 28 insertions, 4 deletions
diff --git a/sys/fs/nullfs/null_vnops.c b/sys/fs/nullfs/null_vnops.c index 0f404dd..8515c7e 100644 --- a/sys/fs/nullfs/null_vnops.c +++ b/sys/fs/nullfs/null_vnops.c @@ -180,6 +180,7 @@ #include <sys/namei.h> #include <sys/sysctl.h> #include <sys/vnode.h> +#include <sys/kdb.h> #include <fs/nullfs/null.h> @@ -545,6 +546,30 @@ null_lock(struct vop_lock_args *ap) */ vholdl(lvp); error = VOP_LOCK(lvp, flags, td); + + /* + * We might have slept to get the lock and someone might have + * clean our vnode already, switching vnode lock from one in + * lowervp to v_lock in our own vnode structure. Handle this + * case by reacquiring correct lock in requested mode. + */ + if (VTONULL(vp) == NULL && error == 0) { + ap->a_flags &= ~(LK_TYPE_MASK | LK_INTERLOCK); + switch (flags & LK_TYPE_MASK) { + case LK_SHARED: + ap->a_flags |= LK_SHARED; + break; + case LK_UPGRADE: + case LK_EXCLUSIVE: + ap->a_flags |= LK_EXCLUSIVE; + break; + default: + panic("Unsupported lock request %d\n", + ap->a_flags); + } + VOP_LOCK(lvp, LK_RELEASE, td); + error = vop_stdlock(ap); + } vdrop(lvp); } else error = vop_stdlock(ap); @@ -633,14 +658,13 @@ null_reclaim(struct vop_reclaim_args *ap) */ VI_LOCK(vp); vp->v_data = NULL; - VI_UNLOCK(vp); + vnlock = vp->v_vnlock; + vp->v_vnlock = &vp->v_lock; + lockmgr(vp->v_vnlock, LK_EXCLUSIVE|LK_INTERLOCK, VI_MTX(vp), curthread); if (lowervp) null_hashrem(xp); vp->v_object = NULL; - vnlock = vp->v_vnlock; - vp->v_vnlock = &vp->v_lock; - lockmgr(vp->v_vnlock, LK_EXCLUSIVE, NULL, curthread); if (lowervp) { vput(lowervp); } else |