Subject: kern/4439: incorrect link count of dirs that only exist in upper layer of unionfs
To: None <>
From: Dave Huang <>
List: netbsd-bugs
Date: 11/06/1997 06:39:54
>Number:         4439
>Category:       kern
>Synopsis:       incorrect link count of dirs that only exist in upper layer of unionfs
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    kern-bug-people (Kernel Bug People)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Thu Nov  6 05:20:04 1997
>Originator:     Dave Huang
Name: Dave Huang     |   Mammal, mammal / their names are called /
INet:   |   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-1.3_ALPHA as of November 5, 1997
System: NetBSD 1.3_ALPHA NetBSD 1.3_ALPHA (SPIFF) #156: Thu Nov 6 06:24:34 CST 1997 i386

	The link count of directories that only exist in the upper
layer of a union filesystem is garbage.

union_getattr() in union_vnops.c has the following comment:
 * Some programs walk the filesystem hierarchy by counting
 * links to directories to avoid stat'ing all the time.
 * This means the link count on directories needs to be "correct".
 * The only way to do that is to call getattr on both layers
 * and fix up the link count.  The link count will not necessarily
 * be accurate but will be large enough to defeat the tree walkers.

But if the directory doesn't exist in the lower layer, it uses the
contents of an uninitialized structure for the lower layer's link

dahan /tmp# pwd
dahan /tmp# mkdir top bottom
dahan /tmp# mount -t union /tmp/top /tmp/bottom
dahan /tmp# mkdir bottom/dir
dahan /tmp# ls -l bottom
total 1
drwx------  4028275317 root  wheel  512 Nov  2 04:15 dir/
dahan /tmp# umount /tmp/bottom
dahan /tmp# ls -l top bottom

total 1
drwx------  2 root  wheel  512 Nov  2 04:15 dir/

However, Matthias Drochner tried the above and wasn't able to
duplicate the problem on his system... so I dunno what's going on.
I've done a "sup -o", so my sources should be up-to-date.

Make sure va.va_nlink is initialized before trying to use it. Perhaps
something like this:
--- /usr/src/sys/miscfs/union/union_vnops.c	Fri Oct 10 07:26:34 1997
+++ union_vnops.c	Thu Nov  6 06:24:01 1997
@@ -811,6 +811,8 @@
 		vp = NULLVP;
+	va.va_nlink = 0;
 	if (vp != NULLVP) {
 		error = VOP_GETATTR(vp, vap, ap->a_cred, ap->a_p);
 		if (error)

Or maybe initialize it inside this block... *shrug*
	} else if (vp->v_type == VDIR) {
		vp = un->un_lowervp;
		vap = &va;
	} else {