[PATCH]

Alexandr Kovalenko never at wnet.ua.spammers.must.d.ie
Sun Jul 27 14:25:21 PDT 2003


I have found it AFAIR in -stable@, please, take a look at it.
Works pretty stable on heavyly loaded system.
But I'm not a programmer, so I don't sure what this patch
exactly fixes...

Index: sys/miscfs/union/union.h
===================================================================
RCS file: /cvs/src/sys/miscfs/union/Attic/union.h,v
retrieving revision 1.17
diff -u -r1.17 union.h
--- sys/miscfs/union/union.h	29 Dec 1999 04:54:48 -0000	1.17
+++ sys/miscfs/union/union.h	31 May 2003 20:16:02 -0000
@@ -119,7 +119,8 @@
 				struct componentname *, struct vnode *,
 				struct vnode *, int));
 extern int union_freevp __P((struct vnode *));
-extern struct vnode *union_dircache __P((struct vnode *, struct proc *));
+extern struct vnode *union_dircache_get(struct vnode *, struct proc *);
+extern void union_dircache_free(struct union_node *);
 extern int union_copyup __P((struct union_node *, int, struct ucred *,
 				struct proc *));
 extern int union_dowhiteout __P((struct union_node *, struct ucred *,
@@ -144,6 +145,9 @@
 #define	LOWERVP(vp) (VTOUNION(vp)->un_lowervp)
 #define	UPPERVP(vp) (VTOUNION(vp)->un_uppervp)
 #define OTHERVP(vp) (UPPERVP(vp) ? UPPERVP(vp) : LOWERVP(vp))
+
+MALLOC_DECLARE(M_UNPATH);
+MALLOC_DECLARE(M_UNDCACHE);
 
 #define UDEBUG(x)	if (uniondebug) printf x
 #define UDEBUG_ENABLED	1
Index: sys/miscfs/union/union_subr.c
===================================================================
RCS file: /cvs/src/sys/miscfs/union/Attic/union_subr.c,v
retrieving revision 1.43.2.2
diff -u -r1.43.2.2 union_subr.c
--- sys/miscfs/union/union_subr.c	25 Dec 2001 01:44:45 -0000	1.43.2.2
+++ sys/miscfs/union/union_subr.c	31 May 2003 23:34:07 -0000
@@ -183,7 +183,7 @@
 		if (un->un_lowervp) {
 			vrele(un->un_lowervp);
 			if (un->un_path) {
-				free(un->un_path, M_TEMP);
+				free(un->un_path, M_UNPATH);
 				un->un_path = 0;
 			}
 		}
@@ -500,7 +500,7 @@
 			union_newlower(un, lowervp);
 			if (cnp && (lowervp != NULLVP)) {
 				un->un_path = malloc(cnp->cn_namelen+1,
-						M_TEMP, M_WAITOK);
+						M_UNPATH, M_WAITOK);
 				bcopy(cnp->cn_nameptr, un->un_path,
 						cnp->cn_namelen);
 				un->un_path[cnp->cn_namelen] = '\0';
@@ -578,11 +578,11 @@
 	un->un_pvp = dvp;		/* only parent dir in new allocation */
 	if (dvp != NULLVP)
 		VREF(dvp);
-	un->un_dircache = 0;
+	un->un_dircache = NULL;
 	un->un_openl = 0;
 
 	if (cnp && (lowervp != NULLVP)) {
-		un->un_path = malloc(cnp->cn_namelen+1, M_TEMP, M_WAITOK);
+		un->un_path = malloc(cnp->cn_namelen+1, M_UNPATH, M_WAITOK);
 		bcopy(cnp->cn_nameptr, un->un_path, cnp->cn_namelen);
 		un->un_path[cnp->cn_namelen] = '\0';
 	} else {
@@ -630,7 +630,7 @@
 		un->un_dirvp = NULL;
 	}
 	if (un->un_path) {
-		free(un->un_path, M_TEMP);
+		free(un->un_path, M_UNPATH);
 		un->un_path = NULL;
 	}
 
@@ -1143,12 +1143,8 @@
 	 * the union node from cache, so that it will not be referrenced.
 	 */
 	union_newupper(un, NULLVP);
-	if (un->un_dircache != 0) {
-		for (vpp = un->un_dircache; *vpp != NULLVP; vpp++)
-			vrele(*vpp);
-		free(un->un_dircache, M_TEMP);
-		un->un_dircache = 0;
-	}
+	if (un->un_dircache != NULL)
+		union_dircache_free(un);
 
 	if (un->un_flags & UN_CACHED) {
 		un->un_flags &= ~UN_CACHED;
@@ -1180,6 +1176,19 @@
 	return (0);
 }
 
+/*
+ * union_dircache_r -	construct a directory cache
+ *
+ * This function has two modes of operation.  If vppp is NULL, it increments
+ * *cntp by the number of elements that the directory cache would contain.
+ * Otherwise, it recursively populates the array of pointers pointed to by
+ * *vppp with references to vp's upper and lower vnodes, leaving *vpp pointing
+ * just beyond the last position filled.  In the latter mode of operation,
+ * *cntp should be set to one greater than the number of elements in the *vpp
+ * array.
+ *
+ * Yes, this is all very ugly and ought to be replaced with something better.
+ */
 static void
 union_dircache_r(vp, vppp, cntp)
 	struct vnode *vp;
@@ -1197,31 +1206,31 @@
 		} else {
 			(*cntp)++;
 		}
-
-		return;
+	} else {
+		un = VTOUNION(vp);
+		if (un->un_uppervp != NULLVP)
+			union_dircache_r(un->un_uppervp, vppp, cntp);
+		if (un->un_lowervp != NULLVP)
+			union_dircache_r(un->un_lowervp, vppp, cntp);
 	}
-
-	un = VTOUNION(vp);
-	if (un->un_uppervp != NULLVP)
-		union_dircache_r(un->un_uppervp, vppp, cntp);
-	if (un->un_lowervp != NULLVP)
-		union_dircache_r(un->un_lowervp, vppp, cntp);
 }
 
 struct vnode *
-union_dircache(vp, p)
+union_dircache_get(vp, p)
 	struct vnode *vp;
 	struct proc *p;
 {
 	int cnt;
 	struct vnode *nvp;
 	struct vnode **vpp;
-	struct vnode **dircache;
+	struct vnode **dircache, **newdircache;
 	struct union_node *un;
 	int error;
 
 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
-	dircache = VTOUNION(vp)->un_dircache;
+	un = VTOUNION(vp);
+	dircache = un->un_dircache;
+	newdircache = NULL;
 
 	nvp = NULLVP;
 
@@ -1229,8 +1238,8 @@
 		cnt = 0;
 		union_dircache_r(vp, 0, &cnt);
 		cnt++;
-		dircache = malloc(cnt * sizeof(struct vnode *),
-				M_TEMP, M_WAITOK);
+		newdircache = dircache = malloc(cnt * sizeof(struct vnode *),
+						M_UNDCACHE, M_WAITOK);
 		vpp = dircache;
 		union_dircache_r(vp, &vpp, &cnt);
 		*vpp = NULLVP;
@@ -1238,7 +1247,7 @@
 	} else {
 		vpp = dircache;
 		do {
-			if (*vpp++ == VTOUNION(vp)->un_uppervp)
+			if (*vpp++ == un->un_uppervp)
 				break;
 		} while (*vpp != NULLVP);
 	}
@@ -1254,15 +1263,35 @@
 	if (error)
 		goto out;
 
-	VTOUNION(vp)->un_dircache = 0;
-	un = VTOUNION(nvp);
-	un->un_dircache = dircache;
+	un->un_dircache = NULL;
+	VTOUNION(nvp)->un_dircache = dircache;
+	newdircache = NULL;
 
 out:
+	/*
+	 * If we allocated a new dircache and couldn't attach
+	 * it to a new vp, free the resources we allocated.
+	 */
+	if (newdircache) {
+		for (vpp = newdircache; *vpp != NULLVP; vpp++)
+			vrele(*vpp);
+		free(newdircache, M_UNDCACHE);
+	}
 	VOP_UNLOCK(vp, 0, p);
 	return (nvp);
 }
 
+void
+union_dircache_free(struct union_node *un)
+{
+	struct vnode **vpp;
+
+	for (vpp = un->un_dircache; *vpp != NULLVP; vpp++)
+		vrele(*vpp);
+	free(un->un_dircache, M_UNDCACHE);
+	un->un_dircache = NULL;
+}
+
 /*
  * Guarentee coherency with the VM cache by invalidating any clean VM pages
  * associated with this write and updating any dirty VM pages.  Since our
@@ -1308,7 +1337,7 @@
 	if ((*vp)->v_op == union_vnodeop_p) {
 		struct vnode *lvp;
 
-		lvp = union_dircache(*vp, p);
+		lvp = union_dircache_get(*vp, p);
 		if (lvp != NULLVP) {
 			struct vattr va;
 
@@ -1319,7 +1348,7 @@
 			error = VOP_GETATTR(*vp, &va, fp->f_cred, p);
 			if (va.va_flags & OPAQUE) {
 				vput(lvp);
-				lvp = NULL;
+				lvp = NULLVP;
 			}
 		}
 
Index: sys/miscfs/union/union_vfsops.c
===================================================================
RCS file: /cvs/src/sys/miscfs/union/Attic/union_vfsops.c,v
retrieving revision 1.39.2.2
diff -u -r1.39.2.2 union_vfsops.c
--- sys/miscfs/union/union_vfsops.c	25 Oct 2001 19:18:53 -0000	1.39.2.2
+++ sys/miscfs/union/union_vfsops.c	28 May 2003 06:19:12 -0000
@@ -54,6 +54,8 @@
 #include <miscfs/union/union.h>
 #include <vm/vm_zone.h>
 
+MALLOC_DEFINE(M_UNPATH, "unpath", "UNION path component");
+MALLOC_DEFINE(M_UNDCACHE, "undcac", "UNION directory cache");
 static MALLOC_DEFINE(M_UNIONFSMNT, "UNION mount", "UNION mount structure");
 
 extern int	union_init __P((struct vfsconf *));
Index: sys/miscfs/union/union_vnops.c
===================================================================
RCS file: /cvs/src/sys/miscfs/union/Attic/union_vnops.c,v
retrieving revision 1.72
diff -u -r1.72 union_vnops.c
--- sys/miscfs/union/union_vnops.c	15 Dec 1999 23:02:14 -0000	1.72
+++ sys/miscfs/union/union_vnops.c	31 May 2003 17:09:36 -0000
@@ -672,9 +672,22 @@
 	struct vnode *uppervp;
 	int error = EOPNOTSUPP;
 
-	if ((uppervp = union_lock_upper(un, cnp->cn_proc)) != NULLVP) {
-		error = VOP_WHITEOUT(un->un_uppervp, cnp, ap->a_flags);
-		union_unlock_upper(uppervp, cnp->cn_proc);
+	switch (ap->a_flags) {
+	case LOOKUP:
+		/*
+		 * Our upper layer supports whiteout entries, so we can, too.
+		 */
+		error = 0;
+		break;
+	case CREATE:
+	case DELETE:
+		if ((uppervp = union_lock_upper(un, cnp->cn_proc)) != NULLVP) {
+			error = VOP_WHITEOUT(un->un_uppervp, cnp, ap->a_flags);
+			union_unlock_upper(uppervp, cnp->cn_proc);
+		}
+		break;
+	default:
+		panic("union_whiteout: unknown op");
 	}
 	return(error);
 }
@@ -1711,12 +1724,8 @@
 	 * That's too much work for now.
 	 */
 
-	if (un->un_dircache != 0) {
-		for (vpp = un->un_dircache; *vpp != NULLVP; vpp++)
-			vrele(*vpp);
-		free (un->un_dircache, M_TEMP);
-		un->un_dircache = 0;
-	}
+	if (un->un_dircache != 0)
+		union_dircache_free(un);
 
 #if 0
 	if ((un->un_flags & UN_ULOCK) && un->un_uppervp) {






More information about the Submit mailing list