Subject: Re: tmpfs memory leak?
To: None <tech-kern@NetBSD.org>
From: Bill Stouder-Studenmund <wrstuden@netbsd.org>
List: tech-kern
Date: 10/29/2007 12:58:19
--sXc4Kmr5FA7axrvy
Content-Type: multipart/mixed; boundary="t0UkRYy7tHLRMCai"
Content-Disposition: inline


--t0UkRYy7tHLRMCai
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

On Sat, Oct 27, 2007 at 05:20:04PM -0700, Bill Stouder-Studenmund wrote:
> On Fri, Oct 26, 2007 at 07:15:04PM -0500, David Young wrote:
> > On Tue, Oct 23, 2007 at 08:47:43PM -0700, Bill Stouder-Studenmund wrote:
>=20
> > > You have no quantification of the performance hit. Also, you are in a=
=20
> > > situation where memory issues are more important for you. We have no=
=20
> > > indication that all layer users are in this situation, and I believe =
a=20
> > > number aren't.
> >=20
> > You're right, I don't care too much about it in my app.  I am not
> > especially interested in measuring filesystem performance at this time.
> > I don't know what benchmarks the user community likes to see.
> >=20
> > > Ok, I have half-done a patch to do this. I'll post what I come up w/=
=20
> > > tomorrow. I see how to fix this and get most of the way done. What I =
don't=20
> > > see is how to handle locking.
> >=20
> > Tomorrow? :-)
>=20
> Yeah, sorry. Real life and the WoW Haloween events got in the way.
>=20
> Also, I was about half-way through the patch and then realized what I had=
=20
> needed some work. The problem is getting a consistent snapshot of all of=
=20
> the vnodes above a node. My first take was to walk the list of vnodes in =
a=20
> "safe" manner (it's a TAILQ, so take TAILQ_NEXT() before fussing with a=
=20
> given node). The problem is that something else could happen and whatever=
=20
> "next" vnode we look at might not be valid by the time we get around to=
=20
> looking at it. Ick!
>=20
> So what I have to do is go back and vget() all of the vnodes into an arra=
y=20
> (either on-stack or malloc'd). Then start walking them for=20
> VOP_UPCALL()ing.

Ok, so it is taking me longer than I wanted.

Since I've been working on fixsa, I haven't followed current much of late.=
=20
So I started coding this for 4.0. I have an untested first cut at it. It=20
compiles on i386.

This diff should show everything I have in mind except for using the count=
=20
upcall in vcount().

Pieces missing are: unionfs (linking into both underlying vnodes) and=20
non-ufs writable file systems (I know of nfs).

Things I disklike: only one, and that's how I lock the vnode uplink list.=
=20
Right now it's locked with the vnode stack's lock. I think the right thing=
=20
to do is just use the lower vnode's interlock.

The problem is what happens if a vop_reclaim happens on an upper vnode at=
=20
the same time an upcall is coming up. Specifically what happens with the=20
vget() and reclaim. The "advantage" of using the vnode stack lock is that=
=20
the vget() and upcall will happen before the reclaim happens. So we never=
=20
upcall the wrong vnode. The disadvantage is that it means we have to lock=
=20
the vnode stack lock in vop_reclaim(), if only for a little bit.

Thoughts?

Take care,

Bill

--t0UkRYy7tHLRMCai
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="vop_upcall-1.diff"
Content-Transfer-Encoding: quoted-printable

? arch/i386/compile/PARALLELS
Index: kern/vfs_subr.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/sys/kern/vfs_subr.c,v
retrieving revision 1.276.2.1.2.1
diff -u -p -r1.276.2.1.2.1 vfs_subr.c
--- kern/vfs_subr.c	3 Sep 2007 07:05:04 -0000	1.276.2.1.2.1
+++ kern/vfs_subr.c	29 Oct 2007 17:45:22 -0000
@@ -2613,6 +2613,109 @@ vfs_timestamp(struct timespec *ts)
 }
=20
 /*
+ * VOP_UPCALL() helpers
+ */
+
+/* Called w/ the vnode stack locked */
+void
+vn_up_link(struct vnuplink *vu, struct vnode *vp)
+{
+	TAILQ_INSERT_TAIL(&vp->v_uplinks, vu, vup_next);
+	vp->v_upcount++;
+	vu->vup_lower =3D vp;
+}
+
+/* Called w/ the vnode stack locked */
+void
+vn_up_unlink(struct vnuplink *vu, struct vnode *vp)
+{
+	TAILQ_REMOVE(&vp->v_uplinks, vu, vup_next);
+	vp->v_upcount--;
+}
+
+/*
+ * vn_up_doupcall - actually do an upcall to all nodes above vp. Should be
+ * called with the vnode stack locked. Will unlock the stack then re-lock
+ * it.
+ *
+ * This is somewhat complicated as the lock we have is v_interlock, which
+ * is a spin lock. So we have to do a lot of work so that we do only
+ * what we have to do while holding it. We really need a=20
+ */
+#define VN_UP_ONSTACK	8
+int
+vn_up_doupcall(struct vnode *vp, int op, void *cookie)
+{
+	struct vnuplink 	 *vu, *vu_next;
+	struct vnode		 *v;
+	int			  rv =3D 0;
+	int			  i, j;
+	struct vnode		**vnodes;
+	struct vnode		 *v_stack[VN_UP_ONSTACK];
+
+	i =3D vp->v_upcount;
+	j =3D 0;
+
+	if (i <=3D VN_UP_ONSTACK) {
+		/* Use stack storage */
+		vnodes =3D v_stack;
+	} else {
+		vnodes =3D malloc(i * sizeof(struct vnode), M_TEMP, M_WAITOK);
+		if (vnodes =3D=3D NULL) {
+			return ENOMEM;
+		}
+	}
+
+	/* Now make a list of the vnodes we want and vget() them */
+	j =3D 0;
+	for(vu =3D TAILQ_FIRST(&vp->v_uplinks); vu; vu =3D vu_next) {
+		vu_next =3D TAILQ_NEXT(vu, vup_next);
+		v =3D vu->vup_upper;
+		vget(v, 0);
+		vnodes[j++] =3D v;
+	}
+
+	/*
+	 * Now do the calls, which may trigger calls into this routine if
+	 * there are vnodes above these layered vnodes
+	 */
+	for(i =3D 0; (i < j) && (rv =3D=3D 0); i++)
+		rv =3D VOP_UPCALL(v, vp, op, cookie, curlwp);
+
+	VOP_UNLOCK(vp, 0);
+
+	/*
+	 * If we are the last reference to the upper vnodes, we will
+	 * inactivate them. If they were "removed", we could well be
+	 * vgone()ing them now.
+	 */
+	for(i =3D 0; i < j; i++)
+		vrele(vnodes[i]);
+
+	vn_lock(vp, LK_EXCLUSIVE);
+
+	if (vnodes !=3D v_stack)
+		free(vnodes, M_TEMP);
+
+	return rv;
+}
+
+void
+vn_up_remove(struct vnode *vp)
+{
+	vn_up_doupcall(vp, VUPCALL_REMOVE, NULL);
+}
+
+int
+vn_up_count(struct vnode *vp, int *counter)
+{
+	simple_lock(&vp->v_interlock);
+	*counter +=3D vp->v_usecount - vp->v_upcount;
+	simple_unlock(&vp->v_interlock);
+	return vn_up_doupcall(vp, VUPCALL_COUNT, (void *)counter);
+}
+
+/*
  * mount_specific_key_create --
  *	Create a key for subsystem mount-specific data.
  */
Index: kern/vnode_if.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/sys/kern/vnode_if.c,v
retrieving revision 1.67
diff -u -p -r1.67 vnode_if.c
--- kern/vnode_if.c	30 Nov 2006 21:07:36 -0000	1.67
+++ kern/vnode_if.c	29 Oct 2007 17:45:23 -0000
@@ -1,11 +1,11 @@
-/*	$NetBSD: vnode_if.c,v 1.67 2006/11/30 21:07:36 pooka Exp $	*/
+/*	$NetBSD$	*/
=20
 /*
  * Warning: DO NOT EDIT! This file is automatically generated!
  * (Modifications made here may easily be lost!)
  *
  * Created from the file:
- *	NetBSD: vnode_if.src,v 1.50 2006/05/14 21:15:12 elad Exp
+ *	NetBSD: vnode_if.src,v 1.50.12.1 2007/02/17 23:27:48 tron Exp
  * by the script:
  *	NetBSD: vnode_if.sh,v 1.43 2006/11/30 21:06:29 pooka Exp
  */
@@ -40,7 +40,7 @@
  */
=20
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vnode_if.c,v 1.67 2006/11/30 21:07:36 pooka Ex=
p $");
+__KERNEL_RCSID(0, "$NetBSD$");
=20
=20
 /*
@@ -1834,6 +1834,53 @@ VOP_SETEXTATTR(struct vnode *vp,
 	return (VCALL(vp, VOFFSET(vop_setextattr), &a));
 }
=20
+const int vop_upcall_vp_offsets[] =3D {
+	VOPARG_OFFSETOF(struct vop_upcall_args,a_uvp),
+	VOPARG_OFFSETOF(struct vop_upcall_args,a_lvp),
+	VDESC_NO_OFFSET
+};
+const struct vnodeop_desc vop_upcall_desc =3D {
+	VOP_UPCALL_DESCOFFSET,
+	"vop_upcall",
+	0,
+	vop_upcall_vp_offsets,
+	VDESC_NO_OFFSET,
+	VDESC_NO_OFFSET,
+	VOPARG_OFFSETOF(struct vop_upcall_args, a_l),
+	VDESC_NO_OFFSET,
+	NULL,
+};
+int
+VOP_UPCALL(struct vnode *uvp,
+    struct vnode *lvp,
+    int op,
+    void *cookie,
+    struct lwp *l)
+{
+	struct vop_upcall_args a;
+#ifdef VNODE_LOCKDEBUG
+	int islocked_uvp;
+	int islocked_lvp;
+#endif
+	a.a_desc =3D VDESC(vop_upcall);
+	a.a_uvp =3D uvp;
+#ifdef VNODE_LOCKDEBUG
+	islocked_uvp =3D (uvp->v_flag & VLOCKSWORK) ? (VOP_ISLOCKED(uvp) =3D=3D L=
K_EXCLUSIVE) : 1;
+	if (islocked_uvp !=3D 1)
+		panic("vop_upcall: uvp: locked %d, expected %d", islocked_uvp, 1);
+#endif
+	a.a_lvp =3D lvp;
+#ifdef VNODE_LOCKDEBUG
+	islocked_lvp =3D (lvp->v_flag & VLOCKSWORK) ? (VOP_ISLOCKED(lvp) =3D=3D L=
K_EXCLUSIVE) : 1;
+	if (islocked_lvp !=3D 1)
+		panic("vop_upcall: lvp: locked %d, expected %d", islocked_lvp, 1);
+#endif
+	a.a_op =3D op;
+	a.a_cookie =3D cookie;
+	a.a_l =3D l;
+	return (VCALL(uvp, VOFFSET(vop_upcall), &a));
+}
+
 /* End of special cases. */
=20
 const struct vnodeop_desc * const vfs_op_descs[] =3D {
@@ -1887,6 +1934,7 @@ const struct vnodeop_desc * const vfs_op
 	&vop_openextattr_desc,
 	&vop_deleteextattr_desc,
 	&vop_setextattr_desc,
+	&vop_upcall_desc,
 	NULL
 };
=20
Index: kern/vnode_if.src
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/sys/kern/vnode_if.src,v
retrieving revision 1.50.12.1
diff -u -p -r1.50.12.1 vnode_if.src
--- kern/vnode_if.src	17 Feb 2007 23:27:48 -0000	1.50.12.1
+++ kern/vnode_if.src	29 Oct 2007 17:45:23 -0000
@@ -584,3 +584,15 @@ vop_setextattr {
 	IN kauth_cred_t cred;
 	IN struct lwp *l;
 };
+
+#
+#% upcall           uvp     L L L
+#% upcall           lvp     L L L
+#
+vop_upcall {
+	IN LOCKED=3DYES struct vnode *uvp;
+	IN LOCKED=3DYES struct vnode *lvp;
+	IN int op;
+	INOUT void *cookie;
+	IN struct lwp *l;
+};
Index: miscfs/genfs/layer.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/sys/miscfs/genfs/layer.h,v
retrieving revision 1.11
diff -u -p -r1.11 layer.h
--- miscfs/genfs/layer.h	11 Dec 2005 12:24:50 -0000	1.11
+++ miscfs/genfs/layer.h	29 Oct 2007 17:45:34 -0000
@@ -112,6 +112,7 @@ struct layer_node {
 	struct vnode	        *layer_lowervp;	/* VREFed once */
 	struct vnode		*layer_vnode;	/* Back pointer */
 	unsigned int		layer_flags;	/* locking, etc. */
+	struct vnuplink 	layer_uplink;	/* uplink from lower vnode */
 };
=20
 #define	LAYERFS_RESFLAGS	0x00000fff	/* flags reserved for layerfs */
Index: miscfs/genfs/layer_extern.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/sys/miscfs/genfs/layer_extern.h,v
retrieving revision 1.22
diff -u -p -r1.22 layer_extern.h
--- miscfs/genfs/layer_extern.h	13 Jul 2006 12:00:25 -0000	1.22
+++ miscfs/genfs/layer_extern.h	29 Oct 2007 17:45:34 -0000
@@ -115,3 +115,4 @@ int	layer_rename(void *);
 int	layer_rmdir(void *);
 int	layer_getpages(void *);
 int	layer_putpages(void *);
+int	layer_upcall(void *);
Index: miscfs/genfs/layer_subr.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/sys/miscfs/genfs/layer_subr.c,v
retrieving revision 1.20.2.1
diff -u -p -r1.20.2.1 layer_subr.c
--- miscfs/genfs/layer_subr.c	17 Feb 2007 23:27:49 -0000	1.20.2.1
+++ miscfs/genfs/layer_subr.c	29 Oct 2007 17:45:34 -0000
@@ -254,6 +254,8 @@ layer_node_alloc(mp, lowervp, vpp)
 	LIST_INSERT_HEAD(hd, xp, layer_hash);
 	uvm_vnp_setsize(vp, 0);
 	simple_unlock(&lmp->layerm_hashlock);
+	xp->layer_uplink.vup_upper =3D vp;
+	vn_up_link(&xp->layer_uplink, lowervp);
 	return (0);
 }
=20
Index: miscfs/genfs/layer_vnops.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/sys/miscfs/genfs/layer_vnops.c,v
retrieving revision 1.28.2.2
diff -u -p -r1.28.2.2 layer_vnops.c
--- miscfs/genfs/layer_vnops.c	16 Apr 2007 20:01:13 -0000	1.28.2.2
+++ miscfs/genfs/layer_vnops.c	29 Oct 2007 17:45:34 -0000
@@ -780,11 +780,7 @@ layer_remove(v)
 	int		error;
 	struct vnode	*vp =3D ap->a_vp;
=20
-	vref(vp);
-	if ((error =3D LAYERFS_DO_BYPASS(vp, ap)) =3D=3D 0)
-		VTOLAYER(vp)->layer_flags |=3D LAYERFS_REMOVED;
-
-	vrele(vp);
+	error =3D LAYERFS_DO_BYPASS(vp, ap);
=20
 	return (error);
 }
@@ -874,6 +870,9 @@ layer_reclaim(v)
 		 */
 		lmp->layerm_rootvp =3D NULL;
 	}
+	VOP_LOCK(lowervp, LK_EXCLUSIVE);
+	vn_up_unlink(&xp->layer_uplink, lowervp);
+	VOP_UNLOCK(lowervp, LK_EXCLUSIVE);
 	xp->layer_lowervp =3D NULL;
 	simple_lock(&lmp->layerm_hashlock);
 	LIST_REMOVE(xp, layer_hash);
@@ -1002,3 +1001,30 @@ layer_putpages(v)
 	error =3D VCALL(ap->a_vp, VOFFSET(vop_putpages), ap);
 	return error;
 }
+
+int
+layer_upcall(v)
+	void *v;
+{
+	struct vop_upcall_args /* {
+		struct vnode *a_uvp;=20
+		struct vnode *a_lvp;
+		int a_op;
+		void *a_cookie;
+		struct lwp *a_l;
+	} */ *ap =3D v;
+	struct vnode *uvp =3D ap->a_uvp;
+
+	switch (ap->a_op) {
+	case VUPCALL_REMOVE:
+		VTOLAYER(uvp)->layer_flags |=3D LAYERFS_REMOVED;
+		vn_up_remove(uvp);
+		return 0;
+
+	case VUPCALL_COUNT:
+		return vn_up_count(uvp, ap->a_cookie);
+
+	default:
+		return EINVAL;
+	}
+}
Index: miscfs/nullfs/null_vnops.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/sys/miscfs/nullfs/null_vnops.c,v
retrieving revision 1.34
diff -u -p -r1.34 null_vnops.c
--- miscfs/nullfs/null_vnops.c	11 Dec 2005 12:24:51 -0000	1.34
+++ miscfs/nullfs/null_vnops.c	29 Oct 2007 17:45:35 -0000
@@ -247,6 +247,8 @@ const struct vnodeopv_entry_desc null_vn
 	{ &vop_getpages_desc, layer_getpages },
 	{ &vop_putpages_desc, layer_putpages },
=20
+	{ &vop_upcall_desc,   layer_upcall },
+
 	{ NULL, NULL }
 };
 const struct vnodeopv_desc null_vnodeop_opv_desc =3D
Index: miscfs/overlay/overlay_vnops.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/sys/miscfs/overlay/overlay_vnops.c,v
retrieving revision 1.16
diff -u -p -r1.16 overlay_vnops.c
--- miscfs/overlay/overlay_vnops.c	11 Dec 2005 12:24:51 -0000	1.16
+++ miscfs/overlay/overlay_vnops.c	29 Oct 2007 17:45:35 -0000
@@ -170,6 +170,8 @@ const struct vnodeopv_entry_desc overlay
 	{ &vop_getpages_desc, layer_getpages },
 	{ &vop_putpages_desc, layer_putpages },
=20
+	{ &vop_upcall_desc,   layer_upcall },
+
 	{ NULL, NULL }
 };
 const struct vnodeopv_desc overlay_vnodeop_opv_desc =3D
Index: miscfs/umapfs/umap_vnops.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/sys/miscfs/umapfs/umap_vnops.c,v
retrieving revision 1.42.2.1
diff -u -p -r1.42.2.1 umap_vnops.c
--- miscfs/umapfs/umap_vnops.c	17 Feb 2007 23:27:50 -0000	1.42.2.1
+++ miscfs/umapfs/umap_vnops.c	29 Oct 2007 17:45:37 -0000
@@ -94,6 +94,8 @@ const struct vnodeopv_entry_desc umap_vn
 	{ &vop_getpages_desc,	layer_getpages },
 	{ &vop_putpages_desc,	layer_putpages },
=20
+	{ &vop_upcall_desc,   layer_upcall },
+
 	{ NULL, NULL }
 };
 const struct vnodeopv_desc umapfs_vnodeop_opv_desc =3D
Index: sys/vnode.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/sys/sys/vnode.h,v
retrieving revision 1.162
diff -u -p -r1.162 vnode.h
--- sys/vnode.h	21 Nov 2006 02:37:20 -0000	1.162
+++ sys/vnode.h	29 Oct 2007 17:46:52 -0000
@@ -83,6 +83,9 @@ enum vtagtype	{
=20
 LIST_HEAD(buflists, buf);
=20
+struct vnuplink;
+TAILQ_HEAD(vnuplink_head, vnuplink);
+
 /*
  * Reading or writing any of these items requires holding the appropriate =
lock.
  * v_freelist is locked by the global vnode_free_list simple lock.
@@ -126,6 +129,8 @@ struct vnode {
 	struct lock	*v_vnlock;		/* pointer to lock */
 	void 		*v_data;		/* private data for fs */
 	struct klist	v_klist;		/* knotes attached to vnode */
+	struct vnuplink_head v_uplinks; 	/* vnodes above us */
+	int		v_upcount;		/* # vnodes on ^^ */
 };
 #define	v_mountedhere	v_un.vu_mountedhere
 #define	v_socket	v_un.vu_socket
@@ -209,6 +214,18 @@ struct vattr {
 #define	VA_UTIMES_NULL	0x01		/* utimes argument was NULL */
 #define	VA_EXCLUSIVE	0x02		/* exclusive create request */
=20
+/*
+ * supoprt VOP_UPCALL()
+ * Each vnode has a list (TAILQ) of vnuplinks. Each vnuplink points
+ * to the next one above the lower node, and also points to the upper
+ * and lower nodes.
+ */
+struct vnuplink {
+	TAILQ_ENTRY(vnuplink)	vup_next;
+	struct vnode		*vup_upper;
+	struct vnode		*vup_lower;
+};
+
 #ifdef _KERNEL
=20
 /*
@@ -255,6 +272,12 @@ extern struct simplelock global_v_numout
 #define	VNOVAL	(-1)
=20
 /*
+ * Defines for VOP_UPCALL
+ */
+#define VUPCALL_REMOVE		1	/* lower vnode has been removed */
+#define VUPCALL_COUNT		2	/* Itteratively count # external refs */
+
+/*
  * Convert between vnode types and inode formats (since POSIX.1
  * defines mode word of stat structure in terms of inode formats).
  */
@@ -579,6 +602,15 @@ void	vn_ra_allocctx(struct vnode *);
 /* initialise global vnode management */
 void	vntblinit(void);
=20
+/* tell vnode stack we removed the vnode */
+void	vn_up_remove(struct vnode *);
+int	vn_up_count(struct vnode *, int *);
+
+/* Helpers for layer file systems */
+int	vn_up_doupcall(struct vnode *, int, void *);
+void	vn_up_link(struct vnuplink *, struct vnode *);
+void	vn_up_unlink(struct vnuplink *, struct vnode *);
+
 /* misc stuff */
 void	vn_syncer_add_to_worklist(struct vnode *, int);
 void	vn_syncer_remove_from_worklist(struct vnode *);
Index: sys/vnode_if.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/sys/sys/vnode_if.h,v
retrieving revision 1.63
diff -u -p -r1.63 vnode_if.h
--- sys/vnode_if.h	30 Nov 2006 21:07:36 -0000	1.63
+++ sys/vnode_if.h	29 Oct 2007 17:46:52 -0000
@@ -1,11 +1,11 @@
-/*	$NetBSD: vnode_if.h,v 1.63 2006/11/30 21:07:36 pooka Exp $	*/
+/*	$NetBSD$	*/
=20
 /*
  * Warning: DO NOT EDIT! This file is automatically generated!
  * (Modifications made here may easily be lost!)
  *
  * Created from the file:
- *	NetBSD: vnode_if.src,v 1.50 2006/05/14 21:15:12 elad Exp
+ *	NetBSD: vnode_if.src,v 1.50.12.1 2007/02/17 23:27:48 tron Exp
  * by the script:
  *	NetBSD: vnode_if.sh,v 1.43 2006/11/30 21:06:29 pooka Exp
  */
@@ -583,7 +583,19 @@ extern const struct vnodeop_desc vop_set
 int VOP_SETEXTATTR(struct vnode *, int, const char *, struct uio *,=20
     kauth_cred_t, struct lwp *);
=20
-#define VNODE_OPS_COUNT	49
+#define VOP_UPCALL_DESCOFFSET 49
+struct vop_upcall_args {
+	const struct vnodeop_desc *a_desc;
+	struct vnode *a_uvp;
+	struct vnode *a_lvp;
+	int a_op;
+	void *a_cookie;
+	struct lwp *a_l;
+};
+extern const struct vnodeop_desc vop_upcall_desc;
+int VOP_UPCALL(struct vnode *, struct vnode *, int, void *, struct lwp *);
+
+#define VNODE_OPS_COUNT	50
=20
 /* End of special cases. */
=20
Index: ufs/ufs/ufs_vnops.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/sys/ufs/ufs/ufs_vnops.c,v
retrieving revision 1.143.2.3
diff -u -p -r1.143.2.3 ufs_vnops.c
--- ufs/ufs/ufs_vnops.c	10 Mar 2007 18:40:49 -0000	1.143.2.3
+++ ufs/ufs/ufs_vnops.c	29 Oct 2007 17:47:04 -0000
@@ -656,6 +656,7 @@ ufs_remove(void *v)
 		error =3D ufs_dirremove(dvp, ip, ap->a_cnp->cn_flags, 0);
 	VN_KNOTE(vp, NOTE_DELETE);
 	VN_KNOTE(dvp, NOTE_WRITE);
+	vn_up_remove(vp);
 	if (dvp =3D=3D vp)
 		vrele(vp);
 	else
@@ -1150,6 +1151,7 @@ ufs_rename(void *v)
 		VN_KNOTE(tdvp, NOTE_WRITE);
 		vput(tdvp);
 		VN_KNOTE(tvp, NOTE_DELETE);
+		vn_up_remove(tvp);
 		vput(tvp);
 		xp =3D NULL;
 	}

--t0UkRYy7tHLRMCai--

--sXc4Kmr5FA7axrvy
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.7 (NetBSD)

iD8DBQFHJjtbWz+3JHUci9cRAixaAJ0fOGr81LZu/jrHUDNW8B4WCld23gCdHDGu
WKbwkE4hhaP3Fmsu+pLl5qA=
=HXLB
-----END PGP SIGNATURE-----

--sXc4Kmr5FA7axrvy--