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