Module Name:    src
Committed By:   hannken
Date:           Mon Feb 16 10:22:00 UTC 2015

Modified Files:
        src/sys/fs/union: union.h union_subr.c union_vfsops.c

Log Message:
Change union to vcache.  Use address of the union node as key.

It would be better to use (uppervp, lowervp) as key, but either
may be NULL and may change any time.


To generate a diff of this commit:
cvs rdiff -u -r1.27 -r1.28 src/sys/fs/union/union.h
cvs rdiff -u -r1.69 -r1.70 src/sys/fs/union/union_subr.c
cvs rdiff -u -r1.73 -r1.74 src/sys/fs/union/union_vfsops.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/fs/union/union.h
diff -u src/sys/fs/union/union.h:1.27 src/sys/fs/union/union.h:1.28
--- src/sys/fs/union/union.h:1.27	Mon Feb 16 10:21:25 2015
+++ src/sys/fs/union/union.h	Mon Feb 16 10:22:00 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: union.h,v 1.27 2015/02/16 10:21:25 hannken Exp $	*/
+/*	$NetBSD: union.h,v 1.28 2015/02/16 10:22:00 hannken Exp $	*/
 
 /*
  * Copyright (c) 1994 The Regents of the University of California.
@@ -121,6 +121,7 @@ struct union_node {
 	kmutex_t		un_lock;
 	LIST_ENTRY(union_node)	un_cache;	/* c: Hash chain */
 	int			un_refs;	/* c: Reference counter */
+	struct mount		*un_mount;	/* c: union mount */
 	struct vnode		*un_vnode;	/* :: Back pointer */
 	struct vnode	        *un_uppervp;	/* m: overlaying object */
 	struct vnode	        *un_lowervp;	/* v: underlying object */
@@ -162,6 +163,8 @@ extern void union_newupper(struct union_
 extern void union_newsize(struct vnode *, off_t, off_t);
 int union_readdirhook(struct vnode **, struct file *, struct lwp *);
 
+VFS_PROTOS(union);
+
 #define	MOUNTTOUNIONMOUNT(mp) ((struct union_mount *)((mp)->mnt_data))
 #define	VTOUNION(vp) ((struct union_node *)(vp)->v_data)
 #define	UNIONTOV(un) ((un)->un_vnode)

Index: src/sys/fs/union/union_subr.c
diff -u src/sys/fs/union/union_subr.c:1.69 src/sys/fs/union/union_subr.c:1.70
--- src/sys/fs/union/union_subr.c:1.69	Mon Feb 16 10:21:25 2015
+++ src/sys/fs/union/union_subr.c	Mon Feb 16 10:22:00 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: union_subr.c,v 1.69 2015/02/16 10:21:25 hannken Exp $	*/
+/*	$NetBSD: union_subr.c,v 1.70 2015/02/16 10:22:00 hannken Exp $	*/
 
 /*
  * Copyright (c) 1994
@@ -72,7 +72,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: union_subr.c,v 1.69 2015/02/16 10:21:25 hannken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: union_subr.c,v 1.70 2015/02/16 10:22:00 hannken Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -344,22 +344,12 @@ union_rele(struct union_node *un)
  * the reference is either maintained in the new union_node
  * object which is allocated, or they are vrele'd.
  *
- * all union_nodes are maintained on a singly-linked
+ * all union_nodes are maintained on a hash
  * list.  new nodes are only allocated when they cannot
  * be found on this list.  entries on the list are
  * removed when the vfs reclaim entry is called.
  *
- * a single lock is kept for the entire list.  this is
- * needed because the getnewvnode() function can block
- * waiting for a vnode to become free, in which case there
- * may be more than one process trying to get the same
- * vnode.  this lock is only taken if we are going to
- * call getnewvnode, since the kernel itself is single-threaded.
- *
- * if an entry is found on the list, then call vget() to
- * take a reference.  this is done because there may be
- * zero references to it and so it needs to removed from
- * the vnode free list.
+ * the vnode gets attached or referenced with vcache_get().
  */
 int
 union_allocvp(
@@ -373,14 +363,9 @@ union_allocvp(
 	int docache)
 {
 	int error;
-	struct vattr va;
 	struct union_node *un = NULL, *un1;
 	struct vnode *vp, *xlowervp = NULLVP;
-	struct union_mount *um = MOUNTTOUNIONMOUNT(mp);
-	voff_t uppersz, lowersz;
-	dev_t rdev;
 	u_long hash[3];
-	int vflag, iflag;
 	int try;
 	bool is_dotdot;
 
@@ -394,20 +379,6 @@ union_allocvp(
 		lowervp = NULLVP;
 	}
 
-	/* detect the root vnode (and aliases) */
-	iflag = VI_LAYER;
-	vflag = 0;
-	if ((uppervp == um->um_uppervp) &&
-	    ((lowervp == NULLVP) || lowervp == um->um_lowervp)) {
-		if (lowervp == NULLVP) {
-			lowervp = um->um_lowervp;
-			if (lowervp != NULLVP)
-				vref(lowervp);
-		}
-		iflag = 0;
-		vflag = VV_ROOT;
-	}
-
 	if (!docache) {
 		un = NULL;
 		goto found;
@@ -434,17 +405,18 @@ loop:
 		LIST_FOREACH(un, &uhashtbl[hash[try]], un_cache) {
 			if ((un->un_lowervp && un->un_lowervp != lowervp) ||
 			    (un->un_uppervp && un->un_uppervp != uppervp) ||
-			    UNIONTOV(un)->v_mount != mp)
+			    un->un_mount != mp)
 				continue;
 
-			vp = UNIONTOV(un);
 			union_ref(un);
-			mutex_enter(vp->v_interlock);
 			mutex_exit(&uhash_lock);
-			error = vget(vp, 0);
+			error = vcache_get(mp, &un, sizeof(un), &vp);
+			KASSERT(error != 0 || UNIONTOV(un) == vp);
 			union_rele(un);
-			if (error)
+			if (error == ENOENT)
 				goto loop;
+			else if (error)
+				goto out;
 			goto found;
 		}
 	}
@@ -492,77 +464,15 @@ found:
 		*vpp = UNIONTOV(un);
 		if (uppervp != dvp)
 			VOP_UNLOCK(*vpp);
-		return (0);
-	}
-
-	uppersz = lowersz = VNOVAL;
-	if (uppervp != NULLVP) {
-		vn_lock(uppervp, LK_SHARED | LK_RETRY);
-		if (VOP_GETATTR(uppervp, &va, FSCRED) == 0)
-			uppersz = va.va_size;
-		VOP_UNLOCK(uppervp);
-	}
-	if (lowervp != NULLVP) {
-		vn_lock(lowervp, LK_SHARED | LK_RETRY);
-		if (VOP_GETATTR(lowervp, &va, FSCRED) == 0)
-			lowersz = va.va_size;
-		VOP_UNLOCK(lowervp);
-	}
-
-	/*
-	 * Get a new vnode and share the lock with upper layer vnode,
-	 * unless layers are inverted.
-	 */
-	vnode_t *svp = (uppervp != NULLVP) ? uppervp : lowervp;
-	error = getnewvnode(VT_UNION, mp, union_vnodeop_p,
-	    svp->v_interlock, vpp);
-	if (error) {
-		if (uppervp)
-			vrele(uppervp);
-		if (lowervp)
-			vrele(lowervp);
-
-		return error;
-	}
-
-	if (docache) {
-		mutex_enter(&uhash_lock);
-		LIST_FOREACH(un1, &uhashtbl[hash[0]], un_cache) {
-			if (un1->un_lowervp == lowervp &&
-			    un1->un_uppervp == uppervp &&
-			    UNIONTOV(un1)->v_mount == mp) {
-				/*
-				 * Another thread beat us, push back freshly
-				 * allocated vnode and retry.
-				 */
-				mutex_exit(&uhash_lock);
-				ungetnewvnode(*vpp);
-				goto loop;
-			}
-		}
-	}
-
-	(*vpp)->v_data = malloc(sizeof(struct union_node), M_TEMP, M_WAITOK);
-
-	(*vpp)->v_vflag |= vflag;
-	(*vpp)->v_iflag |= iflag;
-	rdev = NODEV;
-	if (uppervp) {
-		(*vpp)->v_type = uppervp->v_type;
-		if (uppervp->v_type == VCHR || uppervp->v_type == VBLK)
-			rdev = uppervp->v_rdev;
-	} else {
-		(*vpp)->v_type = lowervp->v_type;
-		if (lowervp->v_type == VCHR || lowervp->v_type == VBLK)
-			rdev = lowervp->v_rdev;
+		error = 0;
+		goto out;
 	}
-	if (rdev != NODEV)
-		spec_node_init(*vpp, rdev);
 
-	un = VTOUNION(*vpp);
+	un = malloc(sizeof(struct union_node), M_TEMP, M_WAITOK);
 	mutex_init(&un->un_lock, MUTEX_DEFAULT, IPL_NONE);
 	un->un_refs = 1;
-	un->un_vnode = *vpp;
+	un->un_mount = mp;
+	un->un_vnode = NULL;
 	un->un_uppervp = uppervp;
 	un->un_lowervp = lowervp;
 	un->un_pvp = undvp;
@@ -572,10 +482,8 @@ found:
 	un->un_openl = 0;
 	un->un_cflags = 0;
 
-	mutex_enter(&un->un_lock);
 	un->un_uppersz = VNOVAL;
 	un->un_lowersz = VNOVAL;
-	union_newsize(*vpp, uppersz, lowersz);
 
 	if (dvp && cnp && (lowervp != NULLVP)) {
 		un->un_path = malloc(cnp->cn_namelen+1, M_TEMP, M_WAITOK);
@@ -589,17 +497,36 @@ found:
 	}
 
 	if (docache) {
+		mutex_enter(&uhash_lock);
+		LIST_FOREACH(un1, &uhashtbl[hash[0]], un_cache) {
+			if (un1->un_lowervp == lowervp &&
+			    un1->un_uppervp == uppervp &&
+			    un1->un_mount == mp) {
+				/*
+				 * Another thread beat us, push back freshly
+				 * allocated node and retry.
+				 */
+				mutex_exit(&uhash_lock);
+				union_rele(un);
+				goto loop;
+			}
+		}
 		LIST_INSERT_HEAD(&uhashtbl[hash[0]], un, un_cache);
 		un->un_cflags |= UN_CACHED;
+		mutex_exit(&uhash_lock);
 	}
 
+	error = vcache_get(mp, &un, sizeof(un), vpp);
+	KASSERT(error != 0 || UNIONTOV(un) == *vpp);
+	union_rele(un);
+	if (error == ENOENT)
+		goto loop;
+
+out:
 	if (xlowervp)
 		vrele(xlowervp);
 
-	if (docache)
-		mutex_exit(&uhash_lock);
-
-	return (error);
+	return error;
 }
 
 int
@@ -607,9 +534,83 @@ union_freevp(struct vnode *vp)
 {
 	struct union_node *un = VTOUNION(vp);
 
-	union_rele(un);
+	vcache_remove(vp->v_mount, &un, sizeof(un));
 
+	mutex_enter(vp->v_interlock);
 	vp->v_data = NULL;
+	mutex_exit(vp->v_interlock);
+
+	union_rele(un);
+
+	return 0;
+}
+
+int
+union_loadvnode(struct mount *mp, struct vnode *vp,
+    const void *key, size_t key_len, const void **new_key)
+{
+	struct vattr va;
+	struct vnode *svp;
+	struct union_node *un;
+	struct union_mount *um;
+	voff_t uppersz, lowersz;
+
+	KASSERT(key_len == sizeof(un));
+	memcpy(&un, key, key_len);
+
+	um = MOUNTTOUNIONMOUNT(mp);
+	svp = (un->un_uppervp != NULLVP) ? un->un_uppervp : un->un_lowervp;
+
+	vp->v_tag = VT_UNION;
+	vp->v_op = union_vnodeop_p;
+	vp->v_data = un;
+	un->un_vnode = vp;
+
+	vp->v_type = svp->v_type;
+	if (svp->v_type == VCHR || svp->v_type == VBLK)
+		spec_node_init(vp, svp->v_rdev);
+
+	mutex_obj_hold(svp->v_interlock);
+	uvm_obj_setlock(&vp->v_uobj, svp->v_interlock);
+	vp->v_iflag |= VI_LOCKSHARE;
+
+	/* detect the root vnode (and aliases) */
+	if ((un->un_uppervp == um->um_uppervp) &&
+	    ((un->un_lowervp == NULLVP) || un->un_lowervp == um->um_lowervp)) {
+		if (un->un_lowervp == NULLVP) {
+			un->un_lowervp = um->um_lowervp;
+			if (un->un_lowervp != NULLVP) 
+				vref(un->un_lowervp);
+		}
+		vp->v_vflag |= VV_ROOT;
+	} else {
+		vp->v_iflag |= VI_LAYER;
+	}
+
+	uppersz = lowersz = VNOVAL;
+	if (un->un_uppervp != NULLVP) {
+		if (vn_lock(un->un_uppervp, LK_SHARED) == 0) {
+			if (VOP_GETATTR(un->un_uppervp, &va, FSCRED) == 0)
+				uppersz = va.va_size;
+			VOP_UNLOCK(un->un_uppervp);
+		}
+	}
+	if (un->un_lowervp != NULLVP) {
+		if (vn_lock(un->un_lowervp, LK_SHARED) == 0) {
+			if (VOP_GETATTR(un->un_lowervp, &va, FSCRED) == 0)
+				lowersz = va.va_size;
+			VOP_UNLOCK(un->un_lowervp);
+		}
+	}
+
+	mutex_enter(&un->un_lock);
+	union_newsize(vp, uppersz, lowersz);
+
+	mutex_enter(&uhash_lock);
+	union_ref(un);
+	mutex_exit(&uhash_lock);
+
+	*new_key = &vp->v_data;
 
 	return 0;
 }

Index: src/sys/fs/union/union_vfsops.c
diff -u src/sys/fs/union/union_vfsops.c:1.73 src/sys/fs/union/union_vfsops.c:1.74
--- src/sys/fs/union/union_vfsops.c:1.73	Sat Oct 18 08:33:29 2014
+++ src/sys/fs/union/union_vfsops.c	Mon Feb 16 10:22:00 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: union_vfsops.c,v 1.73 2014/10/18 08:33:29 snj Exp $	*/
+/*	$NetBSD: union_vfsops.c,v 1.74 2015/02/16 10:22:00 hannken Exp $	*/
 
 /*
  * Copyright (c) 1994 The Regents of the University of California.
@@ -77,7 +77,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: union_vfsops.c,v 1.73 2014/10/18 08:33:29 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: union_vfsops.c,v 1.74 2015/02/16 10:22:00 hannken Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -98,8 +98,6 @@ __KERNEL_RCSID(0, "$NetBSD: union_vfsops
 
 MODULE(MODULE_CLASS_VFS, union, NULL);
 
-VFS_PROTOS(union);
-
 static struct sysctllog *union_sysctl_log;
 
 /*
@@ -518,6 +516,7 @@ struct vfsops union_vfsops = {
 	.vfs_statvfs = union_statvfs,
 	.vfs_sync = union_sync,
 	.vfs_vget = union_vget,
+	.vfs_loadvnode = union_loadvnode,
 	.vfs_fhtovp = (void *)eopnotsupp,
 	.vfs_vptofh = (void *)eopnotsupp,
 	.vfs_init = union_init,

Reply via email to