Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/fs/union Use hashinit() / hashdone() to create the union...
details: https://anonhg.NetBSD.org/src/rev/97a16ae04a93
branches: trunk
changeset: 771498:97a16ae04a93
user: hannken <hannken%NetBSD.org@localhost>
date: Wed Nov 23 19:39:11 2011 +0000
description:
Use hashinit() / hashdone() to create the union node hash list.
Cleanup the hash lookup in union_allocvp().
Needs more work as there is still a possible deadlock between
union_allocvp() and vclean().
diffstat:
sys/fs/union/union.h | 3 +-
sys/fs/union/union_subr.c | 193 ++++++++++++++++++++-----------------------
sys/fs/union/union_vfsops.c | 6 +-
3 files changed, 97 insertions(+), 105 deletions(-)
diffs (truncated from 381 to 300 lines):
diff -r 3567ea6648ea -r 97a16ae04a93 sys/fs/union/union.h
--- a/sys/fs/union/union.h Wed Nov 23 19:25:27 2011 +0000
+++ b/sys/fs/union/union.h Wed Nov 23 19:39:11 2011 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: union.h,v 1.22 2011/11/21 18:29:22 hannken Exp $ */
+/* $NetBSD: union.h,v 1.23 2011/11/23 19:39:11 hannken Exp $ */
/*
* Copyright (c) 1994 The Regents of the University of California.
@@ -175,6 +175,7 @@
extern int (**union_vnodeop_p)(void *);
void union_init(void);
+void union_reinit(void);
void union_done(void);
int union_freevp(struct vnode *);
diff -r 3567ea6648ea -r 97a16ae04a93 sys/fs/union/union_subr.c
--- a/sys/fs/union/union_subr.c Wed Nov 23 19:25:27 2011 +0000
+++ b/sys/fs/union/union_subr.c Wed Nov 23 19:39:11 2011 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: union_subr.c,v 1.53 2011/11/21 18:29:22 hannken Exp $ */
+/* $NetBSD: union_subr.c,v 1.54 2011/11/23 19:39:11 hannken Exp $ */
/*
* Copyright (c) 1994
@@ -72,7 +72,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: union_subr.c,v 1.53 2011/11/21 18:29:22 hannken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: union_subr.c,v 1.54 2011/11/23 19:39:11 hannken Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -96,15 +96,13 @@
#include <miscfs/genfs/genfs.h>
#include <miscfs/specfs/specdev.h>
-/* must be power of two, otherwise change UNION_HASH() */
-#define NHASH 32
-
-/* unsigned int ... */
+static LIST_HEAD(uhashhead, union_node) *uhashtbl;
+static u_long uhash_mask; /* size of hash table - 1 */
#define UNION_HASH(u, l) \
- (((((unsigned long) (u)) + ((unsigned long) l)) >> 8) & (NHASH-1))
+ ((((u_long) (u) + (u_long) (l)) >> 8) & uhash_mask)
+#define NOHASH ((u_long)-1)
-static LIST_HEAD(unhead, union_node) unhead[NHASH];
-static kmutex_t unheadlock[NHASH];
+static kmutex_t uhash_lock;
void union_updatevp(struct union_node *, struct vnode *, struct vnode *);
static int union_do_lookup(struct vnode *, struct componentname *, kauth_cred_t, const char *, u_long);
@@ -115,12 +113,34 @@
void
union_init(void)
{
+
+ mutex_init(&uhash_lock, MUTEX_DEFAULT, IPL_NONE);
+ uhashtbl = hashinit(desiredvnodes, HASH_LIST, true, &uhash_mask);
+}
+
+void
+union_reinit(void)
+{
+ struct union_node *un;
+ struct uhashhead *oldhash, *hash;
+ u_long oldmask, mask, val;
int i;
- for (i = 0; i < NHASH; i++) {
- LIST_INIT(&unhead[i]);
- mutex_init(&unheadlock[i], MUTEX_DEFAULT, IPL_NONE);
+ hash = hashinit(desiredvnodes, HASH_LIST, true, &mask);
+ mutex_enter(&uhash_lock);
+ oldhash = uhashtbl;
+ oldmask = uhash_mask;
+ uhashtbl = hash;
+ uhash_mask = mask;
+ for (i = 0; i <= oldmask; i++) {
+ while ((un = LIST_FIRST(&oldhash[i])) != NULL) {
+ LIST_REMOVE(un, un_cache);
+ val = UNION_HASH(un->un_uppervp, un->un_lowervp);
+ LIST_INSERT_HEAD(&hash[val], un, un_cache);
+ }
}
+ mutex_exit(&uhash_lock);
+ hashdone(oldhash, HASH_LIST, oldmask);
}
/*
@@ -129,10 +149,9 @@
void
union_done(void)
{
- int i;
- for (i = 0; i < NHASH; i++)
- mutex_destroy(&unheadlock[i]);
+ hashdone(uhashtbl, HASH_LIST, uhash_mask);
+ mutex_destroy(&uhash_lock);
/* Make sure to unset the readdir hook. */
vn_union_readdir_hook = NULL;
@@ -145,37 +164,19 @@
int ohash = UNION_HASH(un->un_uppervp, un->un_lowervp);
int nhash = UNION_HASH(uppervp, lowervp);
int docache = (lowervp != NULLVP || uppervp != NULLVP);
- int lhash, uhash;
bool un_unlock;
KASSERT(VOP_ISLOCKED(UNIONTOV(un)) == LK_EXCLUSIVE);
- /*
- * Ensure locking is ordered from lower to higher
- * to avoid deadlocks.
- */
- if (nhash < ohash) {
- lhash = nhash;
- uhash = ohash;
- } else {
- lhash = ohash;
- uhash = nhash;
- }
- if (lhash != uhash)
- mutex_enter(&unheadlock[lhash]);
+ mutex_enter(&uhash_lock);
- mutex_enter(&unheadlock[uhash]);
-
- if (ohash != nhash || !docache) {
+ if (!docache || ohash != nhash) {
if (un->un_cflags & UN_CACHED) {
un->un_cflags &= ~UN_CACHED;
LIST_REMOVE(un, un_cache);
}
}
- if (ohash != nhash)
- mutex_exit(&unheadlock[ohash]);
-
if (un->un_lowervp != lowervp) {
if (un->un_lowervp) {
vrele(un->un_lowervp);
@@ -222,11 +223,11 @@
}
if (docache && (ohash != nhash)) {
- LIST_INSERT_HEAD(&unhead[nhash], un, un_cache);
+ LIST_INSERT_HEAD(&uhashtbl[nhash], un, un_cache);
un->un_cflags |= UN_CACHED;
}
- mutex_exit(&unheadlock[nhash]);
+ mutex_exit(&uhash_lock);
}
void
@@ -337,8 +338,8 @@
struct union_mount *um = MOUNTTOUNIONMOUNT(mp);
voff_t uppersz, lowersz;
dev_t rdev;
- int hash = 0;
- int vflag, iflag;
+ u_long hash[3];
+ int vflag, iflag, lflag;
int try;
if (uppervp)
@@ -366,62 +367,53 @@
vflag = VV_ROOT;
}
-loop:
if (!docache) {
- un = 0;
- } else for (try = 0; try < 3; try++) {
- switch (try) {
- case 0:
- if (lowervp == NULLVP)
- continue;
- hash = UNION_HASH(uppervp, lowervp);
- break;
-
- case 1:
- if (uppervp == NULLVP)
- continue;
- hash = UNION_HASH(uppervp, NULLVP);
- break;
-
- case 2:
- if (lowervp == NULLVP)
- continue;
- hash = UNION_HASH(NULLVP, lowervp);
- break;
- }
-
- mutex_enter(&unheadlock[hash]);
+ un = NULL;
+ goto found;
+ }
- for (un = unhead[hash].lh_first; un != 0;
- un = un->un_cache.le_next) {
- if ((un->un_lowervp == lowervp ||
- un->un_lowervp == NULLVP) &&
- (un->un_uppervp == uppervp ||
- un->un_uppervp == NULLVP) &&
- (UNIONTOV(un)->v_mount == mp)) {
- int lflag;
-
- if (uppervp != NULL && (uppervp == dvp ||
- uppervp == un->un_uppervp))
- /* "." or already locked. */
- lflag = 0;
- else
- lflag = LK_EXCLUSIVE;
- vp = UNIONTOV(un);
- mutex_enter(vp->v_interlock);
- mutex_exit(&unheadlock[hash]);
- if (vget(vp, lflag))
- goto loop;
- break;
- }
- }
-
- if (un)
- break;
-
- mutex_exit(&unheadlock[hash]);
+ /*
+ * If both uppervp and lowervp are not NULL we have to
+ * search union nodes with one vnode as NULL too.
+ */
+ hash[0] = UNION_HASH(uppervp, lowervp);
+ if (uppervp == NULL || lowervp == NULL) {
+ hash[1] = hash[2] = NOHASH;
+ } else {
+ hash[1] = UNION_HASH(uppervp, NULLVP);
+ hash[2] = UNION_HASH(NULLVP, lowervp);
}
+loop:
+ mutex_enter(&uhash_lock);
+
+ for (try = 0; try < 3; try++) {
+ if (hash[try] == NOHASH)
+ continue;
+ 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)
+ continue;
+
+ if (uppervp != NULL &&
+ (uppervp == dvp || uppervp == un->un_uppervp))
+ /* "." or already locked. */
+ lflag = 0;
+ else
+ lflag = LK_EXCLUSIVE;
+ vp = UNIONTOV(un);
+ mutex_enter(vp->v_interlock);
+ mutex_exit(&uhash_lock);
+ if (vget(vp, lflag))
+ goto loop;
+ goto found;
+ }
+ }
+
+ mutex_exit(&uhash_lock);
+
+found:
if (un) {
KASSERT(VOP_ISLOCKED(UNIONTOV(un)) == LK_EXCLUSIVE);
KASSERT(uppervp == NULL ||
@@ -474,7 +466,6 @@
if (error == 0)
lowersz = va.va_size;
}
- hash = UNION_HASH(uppervp, lowervp);
/*
* Get a new vnode and share the lock with upper layer vnode,
@@ -497,8 +488,8 @@
}
if (docache) {
- mutex_enter(&unheadlock[hash]);
- LIST_FOREACH(un1, &unhead[hash], un_cache) {
+ 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) {
@@ -506,7 +497,7 @@
* Another thread beat us, push back freshly
* allocated vnode and retry.
Home |
Main Index |
Thread Index |
Old Index