summaryrefslogtreecommitdiffstats
path: root/sys/miscfs
diff options
context:
space:
mode:
authorkato <kato@FreeBSD.org>1997-04-14 10:52:25 +0000
committerkato <kato@FreeBSD.org>1997-04-14 10:52:25 +0000
commit69a13fa7d18543170feb73d80f9459a7514f73b1 (patch)
tree38c833a53269ec2314c4fc0b6f969d5f0810364b /sys/miscfs
parentc834ab375e027589e1cd0d6676a752f98100c75f (diff)
downloadFreeBSD-src-69a13fa7d18543170feb73d80f9459a7514f73b1.zip
FreeBSD-src-69a13fa7d18543170feb73d80f9459a7514f73b1.tar.gz
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.
Diffstat (limited to 'sys/miscfs')
-rw-r--r--sys/miscfs/union/union_vfsops.c26
1 files changed, 25 insertions, 1 deletions
diff --git a/sys/miscfs/union/union_vfsops.c b/sys/miscfs/union/union_vfsops.c
index 2f5837d..13e94f2 100644
--- a/sys/miscfs/union/union_vfsops.c
+++ b/sys/miscfs/union/union_vfsops.c
@@ -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);
@@ -128,12 +129,27 @@ union_mount(mp, path, data, ndp, p)
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.
*/
NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT,
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;
OpenPOWER on IntegriCloud