Subject: kern/5200: hard links on unionfs kernel
To: None <gnats-bugs@gnats.netbsd.org>
From: Dave Huang <khym@bga.com>
List: netbsd-bugs
Date: 03/25/1998 05:02:54
>Number:         5200
>Category:       kern
>Synopsis:       hard links on unionfs crash kernel
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    kern-bug-people (Kernel Bug People)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Wed Mar 25 03:05:01 1998
>Last-Modified:
>Originator:     Dave Huang
>Organization:
Name: Dave Huang     |   Mammal, mammal / their names are called /
INet: khym@bga.com   |   they raise a paw / the bat, the cat /
FurryMUCK: Dahan     |   dolphin and dog / koala bear and hog -- TMBG
Dahan: Hani G Y+C 22 Y++ L+++ W- C++ T++ A+ E+ S++ V++ F- Q+++ P+ B+ PA+ PL++
>Release:        NetBSD-current as of March 24, 1998
>Environment:
	
System: NetBSD dahan.metonymy.com 1.3E NetBSD 1.3E (SPIFF) #201: Wed Mar 25 04:38:32 CST 1998 khym@dahan.metonymy.com:/usr/src.local/sys/arch/i386/compile/SPIFF i386
(UVM, if it matters)

>Description:
	Attempting to create a link from a file in the lower layer of
a unionfs to the upper layer crashes the kernel with a uvm_fault (I
suppose it'd be a vm_fault in a Mach VM kernel)... it's trying to
dereference a null pointer.

>How-To-Repeat:
	I have /usr/src.local as the upper layer, and /usr/src as the lower layer:

/dev/ccd0d /usr ffs rw 1 2
/usr/src /usr/src.local union rw,-b

I have a file named "bla" that only exists in /usr/src (but it shows
through to /usr/src.local). Now, I "ln /usr/src.local/bla
/usr/src.local/foo"

The kernel crashes at _union_link+0xac, which apparently is the
VOP_UNLOCK in this section of union_link around line 1152:

                if (un->un_uppervp == NULLVP) {
                        /*
                         * Needs to be copied before we can link it.
                         */
                        vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY);
                        if (dun->un_uppervp == un->un_dirvp) {
                                dun->un_flags &= ~UN_ULOCK;
                                VOP_UNLOCK(un->un_uppervp, 0);
                        }

Probably not good to unlock un->un_uppervp if it's NULLVP...

>Fix:
	I dunno... I checked NetBSD 1.3, and it does a VOP_UNLOCK on
ap->a_dvp. When I tried that, I got a "lockmgr: locking against
myself" panic (I think). I also tried dun->un_uppervp, but that gave
me a "union: locking against myself" panic. So, I give up :)
>Audit-Trail:
>Unformatted: