[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