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:
KATO Takenori 1997-04-14 10:52:25 +00:00
parent 8f2b2dde93
commit 6db918e371
2 changed files with 50 additions and 2 deletions

View File

@ -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;

View File

@ -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;