Subject: kern/3003: Multiple union mount causes dead lock.
To: None <gnats-bugs@gnats.netbsd.org>
From: =?ISO-2022-JP?B?Ik1JTk9VUkEgTWFrb3RvIC8gGyRCTCcxOhsoQiAbJEI/PxsoQiI=?= <minoura@kw.netlaputa.or.jp>
List: netbsd-bugs
Date: 12/07/1996 19:24:33
>Number:         3003
>Category:       kern
>Synopsis:       Multiple union mount causes dead lock.
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people (Kernel Bug People)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sat Dec  7 06:35:00 1996
>Last-Modified:
>Originator:     Naofumi HONDA / MINOURA Makoto
>Organization:
NetBSD/pc98 Core Team
>Release:        Nov. 30, '96
>Environment:
System: NetBSD daisy 1.2B NetBSD 1.2B (DAISY) #1: Sun Dec 1 00:32:28 JST 1996 root@daisy:/usr/src/sys/arch/i386/compile/DAISY i386


>Description:
	Multiple unionfs mount causes deadlock.
	Because namei called from union_mount waits for the target
	unlocked, which never happens.
>How-To-Repeat:
	Perform same union fs mount repeatedly:-
	  # mount -t union /usr/obj /usr/src
	  # mount -t union /usr/obj /usr/src
>Fix:
	A quick hack written by Naofumi HONDA originally for NetBSD/pc98.

*** /sys/miscfs/union/union_vfsops.c.ORIG	Tue Oct 15 01:41:27 1996
--- /sys/miscfs/union/union_vfsops.c	Sat Nov 30 19:31:25 1996
***************
*** 117,135 ****
  	lowerrootvp = mp->mnt_vnodecovered;
  	VREF(lowerrootvp);
  
  	/*
  	 * Find upper node.
  	 */
  	NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT,
  	       UIO_USERSPACE, args.target, p);
  
! 	if ((error = namei(ndp)) != 0)
  		goto bad;
  
  	upperrootvp = ndp->ni_vp;
  	vrele(ndp->ni_dvp);
  	ndp->ni_dvp = NULL;
  
  	if (upperrootvp->v_type != VDIR) {
  		error = EINVAL;
  		goto bad;
--- 117,156 ----
  	lowerrootvp = mp->mnt_vnodecovered;
  	VREF(lowerrootvp);
  
+ 	if (lowerrootvp->v_op == union_vnodeop_p)
+ 		VOP_UNLOCK(lowerrootvp);
+ 
  	/*
  	 * Find upper node.
  	 */
  	NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT,
  	       UIO_USERSPACE, args.target, p);
  
! 	if ((error = namei(ndp)) != 0) {
! 		if (lowerrootvp->v_op == union_vnodeop_p)
! 			VOP_LOCK(lowerrootvp);
  		goto bad;
+ 	}
  
  	upperrootvp = ndp->ni_vp;
  	vrele(ndp->ni_dvp);
  	ndp->ni_dvp = NULL;
  
+ 	/* XXX:
+ 	 * Avoid hang up.
+ 	 * mount -tunion /usr/src.skel /usr/src
+ 	 * mount -tunion /usr/src.skel /usr/src again.
+ 	 * However this method is quite illegal!! Do NOT blame me!
+ 	 */
+ 	if (lowerrootvp->v_op == union_vnodeop_p) {
+ 		VOP_LOCK(lowerrootvp);
+ 		if (upperrootvp == VTOUNION(lowerrootvp)->un_uppervp) {
+ 			/* duplicated union... */
+ 			error = EBUSY;
+ 			goto bad;
+ 		}
+ 	}
+ 
  	if (upperrootvp->v_type != VDIR) {
  		error = EINVAL;
  		goto bad;


>Audit-Trail:
>Unformatted: