Fix `lockmgr: locking against myself' panic by multi union mount of
same directory pair. If we do: mount -t union a b mount -t union a b then, (1) namei tries to lock fs which has been already locked by first union mount and (2) union_root() tries to lock locked fs. To avoid first deadlock condition, unlock vnode if lowerrootvp is union node, and to avoid second case, union_mount returns EDEADLK when multi union mount is detected.
This commit is contained in:
parent
8f2b2dde93
commit
6db918e371
@ -35,7 +35,7 @@
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)union_vfsops.c 8.20 (Berkeley) 5/20/95
|
||||
* $Id$
|
||||
* $Id: union_vfsops.c,v 1.14 1997/02/22 09:40:41 peter Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -99,6 +99,7 @@ union_mount(mp, path, data, ndp, p)
|
||||
char *cp = 0;
|
||||
int len;
|
||||
u_int size;
|
||||
int islowerunlocked = 0;
|
||||
|
||||
#ifdef UNION_DIAGNOSTIC
|
||||
printf("union_mount(mp = %x)\n", mp);
|
||||
@ -127,6 +128,15 @@ union_mount(mp, path, data, ndp, p)
|
||||
lowerrootvp = mp->mnt_vnodecovered;
|
||||
VREF(lowerrootvp);
|
||||
|
||||
/*
|
||||
* Unlock lower node to avoid deadlock.
|
||||
* (XXX) VOP_ISLOCKED is needed?
|
||||
*/
|
||||
if ((lowerrootvp->v_op == union_vnodeop_p) && VOP_ISLOCKED(lowerrootvp)) {
|
||||
VOP_UNLOCK(lowerrootvp, 0, p);
|
||||
islowerunlocked = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find upper node.
|
||||
*/
|
||||
@ -134,6 +144,12 @@ union_mount(mp, path, data, ndp, p)
|
||||
UIO_USERSPACE, args.target, p);
|
||||
|
||||
error = namei(ndp);
|
||||
/*
|
||||
* Re-lock vnode.
|
||||
* (XXX) VOP_ISLOCKED is needed?
|
||||
*/
|
||||
if (islowerunlocked && !VOP_ISLOCKED(lowerrootvp))
|
||||
vn_lock(lowerrootvp, LK_EXCLUSIVE | LK_RETRY, p);
|
||||
if (error)
|
||||
goto bad;
|
||||
|
||||
@ -141,6 +157,14 @@ union_mount(mp, path, data, ndp, p)
|
||||
vrele(ndp->ni_dvp);
|
||||
ndp->ni_dvp = NULL;
|
||||
|
||||
/*
|
||||
* Check multi union mount to avoid `lock myself again' panic.
|
||||
*/
|
||||
if (upperrootvp == VTOUNION(lowerrootvp)->un_uppervp) {
|
||||
error = EDEADLK;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (upperrootvp->v_type != VDIR) {
|
||||
error = EINVAL;
|
||||
goto bad;
|
||||
|
@ -35,7 +35,7 @@
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)union_vfsops.c 8.20 (Berkeley) 5/20/95
|
||||
* $Id$
|
||||
* $Id: union_vfsops.c,v 1.14 1997/02/22 09:40:41 peter Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -99,6 +99,7 @@ union_mount(mp, path, data, ndp, p)
|
||||
char *cp = 0;
|
||||
int len;
|
||||
u_int size;
|
||||
int islowerunlocked = 0;
|
||||
|
||||
#ifdef UNION_DIAGNOSTIC
|
||||
printf("union_mount(mp = %x)\n", mp);
|
||||
@ -127,6 +128,15 @@ union_mount(mp, path, data, ndp, p)
|
||||
lowerrootvp = mp->mnt_vnodecovered;
|
||||
VREF(lowerrootvp);
|
||||
|
||||
/*
|
||||
* Unlock lower node to avoid deadlock.
|
||||
* (XXX) VOP_ISLOCKED is needed?
|
||||
*/
|
||||
if ((lowerrootvp->v_op == union_vnodeop_p) && VOP_ISLOCKED(lowerrootvp)) {
|
||||
VOP_UNLOCK(lowerrootvp, 0, p);
|
||||
islowerunlocked = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find upper node.
|
||||
*/
|
||||
@ -134,6 +144,12 @@ union_mount(mp, path, data, ndp, p)
|
||||
UIO_USERSPACE, args.target, p);
|
||||
|
||||
error = namei(ndp);
|
||||
/*
|
||||
* Re-lock vnode.
|
||||
* (XXX) VOP_ISLOCKED is needed?
|
||||
*/
|
||||
if (islowerunlocked && !VOP_ISLOCKED(lowerrootvp))
|
||||
vn_lock(lowerrootvp, LK_EXCLUSIVE | LK_RETRY, p);
|
||||
if (error)
|
||||
goto bad;
|
||||
|
||||
@ -141,6 +157,14 @@ union_mount(mp, path, data, ndp, p)
|
||||
vrele(ndp->ni_dvp);
|
||||
ndp->ni_dvp = NULL;
|
||||
|
||||
/*
|
||||
* Check multi union mount to avoid `lock myself again' panic.
|
||||
*/
|
||||
if (upperrootvp == VTOUNION(lowerrootvp)->un_uppervp) {
|
||||
error = EDEADLK;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (upperrootvp->v_type != VDIR) {
|
||||
error = EINVAL;
|
||||
goto bad;
|
||||
|
Loading…
Reference in New Issue
Block a user