hammer2 - flesh out inode and blockref chaining
authorMatthew Dillon <dillon@apollo.backplane.com>
Fri, 10 Feb 2012 22:12:13 +0000 (14:12 -0800)
committerMatthew Dillon <dillon@apollo.backplane.com>
Fri, 10 Feb 2012 22:12:13 +0000 (14:12 -0800)
* Move the inode code into hammer2_inode.c

* Rename ipstack to chain and do an initial skeleton in hammer2_chain.c

* The hammer2_chain structures embed a blockref and maintain a chain
  of pointers all the way to the volume root.

  hammer2_chain structures are embedded in major hammer2 system memory
  structures (hammer2_inode, hammer2_mount, hammer2_indblock).

  All lookups and searches are tracked via hammer2_chain structures.

sys/vfs/hammer2/Makefile
sys/vfs/hammer2/hammer2.h
sys/vfs/hammer2/hammer2_chain.c [new file with mode: 0644]
sys/vfs/hammer2/hammer2_disk.h
sys/vfs/hammer2/hammer2_inode.c [copied from sys/vfs/hammer2/hammer2_subr.c with 59% similarity]
sys/vfs/hammer2/hammer2_subr.c
sys/vfs/hammer2/hammer2_vfsops.c

index 451d076..0a712ac 100644 (file)
@@ -4,6 +4,7 @@
 .PATH: ${.CURDIR}
 
 KMOD=  hammer2
-SRCS=  hammer2_vfsops.c hammer2_vnops.c hammer2_subr.c hammer2_icrc.c
+SRCS=  hammer2_vfsops.c hammer2_vnops.c hammer2_inode.c
+SRCS+= hammer2_chain.c hammer2_subr.c hammer2_icrc.c
 
 .include <bsd.kmod.mk>
index fdac4b9..9b0b7e7 100644 (file)
@@ -74,21 +74,32 @@ struct hammer2_mount;
  * the root volume.  These consist of indirect blocks, inodes,
  * and eventually the volume header.
  *
- * The chain structure is embedded in the hammer2_mount and
- * hammer2_inode, and dynamically allocated for indirect blocks.
- * ip will be non-NULL for chain elements representing inodes.
+ * The chain structure is embedded in the hammer2_mount, hammer2_inode,
+ * and other system memory structures.  The chain structure typically
+ * implements the reference count and busy flag for the larger structure.
+ *
+ * It is always possible to track a chain element all the way back to the
+ * root by following the (parent) links.  (index) is a type-dependent index
+ * in the parent indicating where in the parent the chain element resides.
  */
 struct hammer2_chain {
        struct hammer2_blockref bref;
-       struct hammer2_inode *ip;
-       struct hammer2_chain *parent;
+       struct hammer2_chain *parent;   /* return chain to root */
+       union {
+               struct hammer2_inode *ip;
+               struct hammer2_indblock *ind;
+       } u;
+       u_int   index;                  /* index in parent */
        u_int   refs;
+       u_int   busy;
 };
 
 typedef struct hammer2_chain hammer2_chain_t;
 
 /*
  * A hammer2 inode.
+ *
+ * NOTE: An inode's ref count shares chain.refs.
  */
 struct hammer2_inode {
        struct hammer2_mount    *hmp;
@@ -96,8 +107,6 @@ struct hammer2_inode {
        struct vnode            *vp;
 
        unsigned char           type;
-       u_int                   refs;
-       int                     busy;
 
        hammer2_chain_t         chain;
        hammer2_inode_data_t    data;
@@ -111,6 +120,16 @@ typedef struct hammer2_inode hammer2_inode_t;
 #define HAMMER2_INODE_TYPE_MASK        0x07
 
 /*
+ * A hammer2 indirect block
+ */
+struct hammer2_indblock {
+       hammer2_chain_t         chain;
+       hammer2_indblock_data_t data;
+};
+
+typedef struct hammer2_indblock hammer2_indblock_t;
+
+/*
  * Governing mount structure for filesystem (aka vp->v_mount)
  */
 struct hammer2_mount {
@@ -120,8 +139,6 @@ struct hammer2_mount {
        struct netexport export;        /* nfs export */
        int             ronly;          /* read-only mount */
 
-       struct hammer2_inode *iroot;
-
        struct malloc_type *inodes;
        int             ninodes;
        int             maxinodes;
@@ -129,7 +146,10 @@ struct hammer2_mount {
        struct malloc_type *ipstacks;
        int             nipstacks;
        int             maxipstacks;
-       hammer2_chain_t chain;
+       hammer2_chain_t vchain;         /* anchor chain */
+       hammer2_chain_t *schain;        /* super-root */
+       hammer2_chain_t *rchain;        /* label-root */
+       struct hammer2_inode *iroot;
 
        hammer2_volume_data_t voldata;
 };
@@ -161,8 +181,9 @@ extern struct vop_ops hammer2_vnode_vops;
 extern struct vop_ops hammer2_spec_vops;
 extern struct vop_ops hammer2_fifo_vops;
 
-/* hammer2_subr.c */
-
+/*
+ * hammer2_subr.c
+ */
 void hammer2_inode_lock_sh(hammer2_inode_t *ip);
 void hammer2_inode_lock_up(hammer2_inode_t *ip);
 void hammer2_inode_lock_ex(hammer2_inode_t *ip);
@@ -174,11 +195,34 @@ void hammer2_mount_exlock(hammer2_mount_t *hmp);
 void hammer2_mount_shlock(hammer2_mount_t *hmp);
 void hammer2_mount_unlock(hammer2_mount_t *hmp);
 
+hammer2_key_t hammer2_dirhash(const unsigned char *name, size_t len);
+
+/*
+ * hammer2_inode.c
+ */
 struct vnode *hammer2_igetv(hammer2_inode_t *ip, int *errorp);
-hammer2_inode_t *hammer2_alloci(hammer2_mount_t *hmp);
-void hammer2_freei(hammer2_inode_t *ip);
+hammer2_inode_t *hammer2_inode_alloc(hammer2_mount_t *hmp);
+void hammer2_inode_free(hammer2_inode_t *ip);
+void hammer2_inode_ref(hammer2_inode_t *ip);
+void hammer2_inode_drop(hammer2_inode_t *ip);
 
-hammer2_key_t hammer2_dirhash(const unsigned char *name, size_t len);
+/*
+ * hammer2_chain.c
+ */
+void hammer2_chain_ref(hammer2_mount_t *hmp, hammer2_chain_t *chain);
+void hammer2_chain_drop(hammer2_mount_t *hmp, hammer2_chain_t *chain);
+
+hammer2_chain_t *hammer2_chain_push(hammer2_mount_t *hmp,
+                                   hammer2_chain_t *parent,
+                                   hammer2_key_t key);
+hammer2_chain_t *hammer2_chain_first(hammer2_mount_t *hmp,
+                                    hammer2_chain_t *parent,
+                                    hammer2_key_t key,
+                                    hammer2_key_t mask);
+hammer2_chain_t *hammer2_chain_next(hammer2_mount_t *hmp,
+                                   hammer2_chain_t *current,
+                                   hammer2_key_t key,
+                                   hammer2_key_t mask);
 
 #endif /* !_KERNEL */
 #endif /* !_VFS_HAMMER2_HAMMER2_H_ */
diff --git a/sys/vfs/hammer2/hammer2_chain.c b/sys/vfs/hammer2/hammer2_chain.c
new file mode 100644 (file)
index 0000000..710e73f
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2011-2012 The DragonFly Project.  All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Matthew Dillon <dillon@dragonflybsd.org>
+ * by Venkatesh Srinivas <vsrinivas@dragonflybsd.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific, prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <sys/cdefs.h>
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/types.h>
+#include <sys/lock.h>
+#include <sys/uuid.h>
+
+#include "hammer2.h"
+
+/*
+ * Add a reference to a chain element (for shared access).  The chain
+ * element must already have at least 1 ref.
+ */
+void
+hammer2_chain_ref(hammer2_mount_t *hmp, hammer2_chain_t *chain)
+{
+       KKASSERT(chain->refs > 0);
+       atomic_add_int(&chain->refs, 1);
+}
+
+/*
+ * Drop the callers reference to the chain element.  If the ref count
+ * reaches zero the chain element and any related structure (typically an
+ * inode or indirect block) will be freed.
+ *
+ * Keep in mind that hammer2_chain structures are typically directly embedded
+ * in major hammer2 memory structures.
+ */
+void
+hammer2_chain_drop(hammer2_mount_t *hmp, hammer2_chain_t *chain)
+{
+       if (atomic_fetchadd_int(&chain->refs, -1) == 1) {
+               if (chain->bref.type == HAMMER2_BREF_TYPE_INODE) {
+                       KKASSERT(chain == &chain->u.ip->chain);
+                       hammer2_inode_free(chain->u.ip);
+               }
+       }
+}
+
+/*
+ * Locate the exact key relative to the parent chain.
+ */
+hammer2_chain_t *
+hammer2_chain_push(hammer2_mount_t *hmp, hammer2_chain_t *parent,
+                  hammer2_key_t key)
+{
+       return NULL;
+}
+
+/*
+ * Initiate a ranged search, locating the first element matching (key & ~mask).
+ * That is, the passed mask represents the bits we wish to ignore.
+ */
+hammer2_chain_t *
+hammer2_chain_first(hammer2_mount_t *hmp, hammer2_chain_t *parent,
+                   hammer2_key_t key, hammer2_key_t mask)
+{
+       return NULL;
+}
+
+/*
+ * Locate the next element matching (key & ~mask) occuring after the current
+ * element.
+ */
+hammer2_chain_t *
+hammer2_chain_next(hammer2_mount_t *hmp, hammer2_chain_t *current,
+                  hammer2_key_t key, hammer2_key_t mask)
+{
+       return NULL;
+}
index 03c9f0a..b2867b1 100644 (file)
@@ -190,6 +190,14 @@ typedef uint32_t hammer2_crc32_t;
 #define HAMMER2_MAX_COPIES     6
 
 /*
+ * HAMMER2 directory support and pre-defined keys
+ */
+#define HAMMER2_DIRHASH_VISIBLE        0x8000000000000000ULL
+#define HAMMER2_DIRHASH_LOMASK 0x00000000FFFFFFFFULL
+
+#define HAMMER2_SROOT_KEY      0x0000000000000000ULL   /* volume to sroot */
+
+/*
  * The media block reference structure.  This forms the core of the HAMMER2
  * media topology recursion.  This 64-byte data structure is embedded in the
  * volume header, in inodes (which are also directory entries), and in
@@ -310,11 +318,11 @@ typedef struct hammer2_blockset hammer2_blockset_t;
 /*
  * The media indirect block structure.
  */
-struct hammer2_indblock {
+struct hammer2_indblock_data {
        hammer2_blockref_t blocks[HAMMER2_IND_COUNT];
 };
 
-typedef struct hammer2_indblock hammer2_indblock_t;
+typedef struct hammer2_indblock_data hammer2_indblock_data_t;
 
 /*
  * In HAMMER2 inodes ARE directory entries, with a special exception for
similarity index 59%
copy from sys/vfs/hammer2/hammer2_subr.c
copy to sys/vfs/hammer2/hammer2_inode.c
index 3a71e45..478e209 100644 (file)
 #include "hammer2.h"
 
 /*
- * HAMMER2 inode locks
- *
- * HAMMER2 offers shared locks, update locks, and exclusive locks on inodes.
- *
- * Shared locks allow concurrent access to an inode's fields, but exclude
- * access by concurrent exclusive locks.
- *
- * Update locks are interesting -- an update lock will be taken after all
- * shared locks on an inode are released, but once it is in place, shared
- * locks may proceed. The update field is signalled by a busy flag in the
- * inode. Only one update lock may be in place at a given time on an inode.
- *
- * Exclusive locks prevent concurrent access to the inode.
- *
- * XXX: What do we use each for? How is visibility to the inode controlled?
+ * Adding a ref to an inode is only legal if the inode already has at least
+ * one ref.
  */
-
-void
-hammer2_inode_lock_sh(hammer2_inode_t *ip)
-{
-       lockmgr(&ip->lk, LK_SHARED);
-}
-
-void
-hammer2_inode_lock_up(hammer2_inode_t *ip)
-{
-       lockmgr(&ip->lk, LK_EXCLUSIVE);
-       ++ip->busy;
-       lockmgr(&ip->lk, LK_DOWNGRADE);
-}
-
-void
-hammer2_inode_lock_ex(hammer2_inode_t *ip)
-{
-       lockmgr(&ip->lk, LK_EXCLUSIVE);
-}
-
-void
-hammer2_inode_unlock_ex(hammer2_inode_t *ip)
-{
-       lockmgr(&ip->lk, LK_RELEASE);
-}
-
-void
-hammer2_inode_unlock_up(hammer2_inode_t *ip)
-{
-       lockmgr(&ip->lk, LK_UPGRADE);
-       --ip->busy;
-       lockmgr(&ip->lk, LK_RELEASE);
-}
-
 void
-hammer2_inode_unlock_sh(hammer2_inode_t *ip)
+hammer2_inode_ref(hammer2_inode_t *ip)
 {
-       lockmgr(&ip->lk, LK_RELEASE);
+       KKASSERT(ip->chain.refs > 0);
+       atomic_add_int(&ip->chain.refs, 1);
 }
 
 /*
- * Mount-wide locks
+ * Drop an inode reference, freeing the inode when the last reference goes
+ * away.
  */
-
-void
-hammer2_mount_exlock(hammer2_mount_t *hmp)
-{
-       lockmgr(&hmp->lk, LK_EXCLUSIVE);
-}
-
 void
-hammer2_mount_shlock(hammer2_mount_t *hmp)
+hammer2_inode_drop(hammer2_inode_t *ip)
 {
-       lockmgr(&hmp->lk, LK_SHARED);
+       if (atomic_fetchadd_int(&ip->chain.refs, -1) == 1)
+               hammer2_inode_free(ip);
 }
 
-void
-hammer2_mount_unlock(hammer2_mount_t *hmp)
-{
-       lockmgr(&hmp->lk, LK_RELEASE);
-}
-
-/*
- * Inode/vnode subroutines
- */
-
 /*
  * Get the vnode associated with the given inode, allocating the vnode if
  * necessary.
@@ -239,29 +177,25 @@ hammer2_igetv(hammer2_inode_t *ip, int *errorp)
 /*
  * Allocate a HAMMER2 inode memory structure.
  *
- * The returned inode is locked exclusively and referenced.
- * The HAMMER2 mountpoint must be locked on entry.
+ * Returns a busied but unlocked inode
  */
 hammer2_inode_t *
-hammer2_alloci(hammer2_mount_t *hmp)
+hammer2_inode_alloc(hammer2_mount_t *hmp)
 {
        hammer2_inode_t *ip;
 
-       kprintf("alloci\n");
-
        ip = kmalloc(sizeof(hammer2_inode_t), hmp->inodes, M_WAITOK | M_ZERO);
        if (!ip) {
                /* XXX */
        }
 
-       ++hmp->ninodes;
-
+       atomic_add_int(&hmp->ninodes, 1);
        ip->type = 0;
        ip->hmp = hmp;
        lockinit(&ip->lk, "h2inode", 0, 0);
        ip->vp = NULL;
-       ip->refs = 1;
-       hammer2_inode_lock_ex(ip);
+       ip->chain.refs = 1;
+       ip->chain.busy = 1;
 
        return (ip);
 }
@@ -273,80 +207,16 @@ hammer2_alloci(hammer2_mount_t *hmp)
  * be destroyed on return.
  */
 void
-hammer2_freei(hammer2_inode_t *ip)
+hammer2_inode_free(hammer2_inode_t *ip)
 {
        hammer2_mount_t *hmp = ip->hmp;
-       
+
        KKASSERT(ip->hmp != NULL);
        KKASSERT(ip->vp == NULL);
-       KKASSERT(ip->refs == 1);
-       hammer2_inode_unlock_ex(ip);
-       kfree(ip, hmp->inodes);
-}
+       KKASSERT(ip->chain.refs == 0);
 
-/*
- * Borrow HAMMER1's directory hash algorithm #1 with a few modifications.
- * The filename is split into fields which are hashed separately and then
- * added together.
- *
- * Differences include: bit 63 must be set to 1 for HAMMER2 (HAMMER1 sets
- * it to 0), this is because bit63=0 is used for hidden hardlinked inodes.
- * (This means we do not need to do a 0-check/or-with-0x100000000 either).
- *
- * Also, the iscsi crc code is used instead of the old crc32 code.
- */
-hammer2_key_t
-hammer2_dirhash(const unsigned char *name, size_t len)
-{
-       const unsigned char *aname = name;
-       uint32_t crcx;
-       uint64_t key;
-       size_t i;
-       size_t j;
+       atomic_add_int(&hmp->ninodes, -1);
+       ip->chain.u.ip = NULL;
 
-       /*
-        * Filesystem version 6 or better will create directories
-        * using the ALG1 dirhash.  This hash breaks the filename
-        * up into domains separated by special characters and
-        * hashes each domain independently.
-        *
-        * We also do a simple sub-sort using the first character
-        * of the filename in the top 5-bits.
-        */
-       key = 0;
-
-       /*
-        * m32
-        */
-       crcx = 0;
-       for (i = j = 0; i < len; ++i) {
-               if (aname[i] == '.' ||
-                   aname[i] == '-' ||
-                   aname[i] == '_' ||
-                   aname[i] == '~') {
-                       if (i != j)
-                               crcx += hammer2_icrc32(aname + j, i - j);
-                       j = i + 1;
-               }
-       }
-       if (i != j)
-               crcx += hammer2_icrc32(aname + j, i - j);
-
-       /*
-        * The directory hash utilizes the top 32 bits of the 64-bit key.
-        * Bit 63 must be set to 1.
-        */
-       crcx |= 0x80000000U;
-       key |= (uint64_t)crcx << 32;
-
-       /*
-        * l16 - crc of entire filename
-        *
-        * This crc reduces degenerate hash collision conditions
-        */
-       crcx = hammer2_icrc32(aname, len);
-       crcx = crcx ^ (crcx << 16);
-       key |= crcx & 0xFFFF0000U;
-
-       return (key);
+       kfree(ip, hmp->inodes);
 }
index 3a71e45..efa7011 100644 (file)
@@ -70,7 +70,7 @@ void
 hammer2_inode_lock_up(hammer2_inode_t *ip)
 {
        lockmgr(&ip->lk, LK_EXCLUSIVE);
-       ++ip->busy;
+       ++ip->chain.busy;
        lockmgr(&ip->lk, LK_DOWNGRADE);
 }
 
@@ -90,7 +90,7 @@ void
 hammer2_inode_unlock_up(hammer2_inode_t *ip)
 {
        lockmgr(&ip->lk, LK_UPGRADE);
-       --ip->busy;
+       --ip->chain.busy;
        lockmgr(&ip->lk, LK_RELEASE);
 }
 
@@ -123,168 +123,6 @@ hammer2_mount_unlock(hammer2_mount_t *hmp)
 }
 
 /*
- * Inode/vnode subroutines
- */
-
-/*
- * Get the vnode associated with the given inode, allocating the vnode if
- * necessary.
- *
- * Great care must be taken to avoid deadlocks and vnode acquisition/reclaim
- * races.
- *
- * The vnode will be returned exclusively locked and referenced.  The
- * reference on the vnode prevents it from being reclaimed.
- *
- * The inode (ip) must be referenced by the caller and not locked to avoid
- * it getting ripped out from under us or deadlocked.
- */
-struct vnode *
-hammer2_igetv(hammer2_inode_t *ip, int *errorp)
-{
-       struct vnode *vp;
-       hammer2_mount_t *hmp;
-
-       hmp = ip->hmp;
-       *errorp = 0;
-
-       for (;;) {
-               /*
-                * Attempt to reuse an existing vnode assignment.  It is
-                * possible to race a reclaim so the vget() may fail.  The
-                * inode must be unlocked during the vget() to avoid a
-                * deadlock against a reclaim.
-                */
-               vp = ip->vp;
-               if (vp) {
-                       /*
-                        * Lock the inode and check for a reclaim race
-                        */
-                       hammer2_inode_lock_ex(ip);
-                       if (ip->vp != vp) {
-                               hammer2_inode_unlock_ex(ip);
-                               continue;
-                       }
-
-                       /*
-                        * Inode must be unlocked during the vget() to avoid
-                        * possible deadlocks, vnode is held to prevent
-                        * destruction during the vget().  The vget() can
-                        * still fail if we lost a reclaim race on the vnode.
-                        */
-                       vhold_interlocked(vp);
-                       hammer2_inode_unlock_ex(ip);
-                       if (vget(vp, LK_EXCLUSIVE)) {
-                               vdrop(vp);
-                               continue;
-                       }
-                       vdrop(vp);
-                       /* vp still locked and ref from vget */
-                       *errorp = 0;
-                       break;
-               }
-
-               /*
-                * No vnode exists, allocate a new vnode.  Beware of
-                * allocation races.  This function will return an
-                * exclusively locked and referenced vnode.
-                */
-               *errorp = getnewvnode(VT_HAMMER2, H2TOMP(hmp), &vp, 0, 0);
-               if (*errorp) {
-                       vp = NULL;
-                       break;
-               }
-
-               /*
-                * Lock the inode and check for an allocation race.
-                */
-               hammer2_inode_lock_ex(ip);
-               if (ip->vp != NULL) {
-                       vp->v_type = VBAD;
-                       vx_put(vp);
-                       hammer2_inode_unlock_ex(ip);
-                       continue;
-               }
-
-               kprintf("igetv new\n");
-               switch (ip->type & HAMMER2_INODE_TYPE_MASK) {
-               case HAMMER2_INODE_TYPE_DIR:
-                       vp->v_type = VDIR;
-                       break;
-               case HAMMER2_INODE_TYPE_FILE:
-                       vp->v_type = VREG;
-                       vinitvmio(vp, 0, HAMMER2_LBUFSIZE,
-                                 (int)ip->data.size & HAMMER2_LBUFMASK);
-                       break;
-               /* XXX FIFO */
-               default:
-                       break;
-               }
-
-               if (ip->type & HAMMER2_INODE_TYPE_ROOT)
-                       vsetflags(vp, VROOT);
-
-               vp->v_data = ip;
-               ip->vp = vp;
-               hammer2_inode_unlock_ex(ip);
-               break;
-       }
-
-       /*
-        * Return non-NULL vp and *errorp == 0, or NULL vp and *errorp != 0.
-        */
-       return (vp);
-}
-
-/*
- * Allocate a HAMMER2 inode memory structure.
- *
- * The returned inode is locked exclusively and referenced.
- * The HAMMER2 mountpoint must be locked on entry.
- */
-hammer2_inode_t *
-hammer2_alloci(hammer2_mount_t *hmp)
-{
-       hammer2_inode_t *ip;
-
-       kprintf("alloci\n");
-
-       ip = kmalloc(sizeof(hammer2_inode_t), hmp->inodes, M_WAITOK | M_ZERO);
-       if (!ip) {
-               /* XXX */
-       }
-
-       ++hmp->ninodes;
-
-       ip->type = 0;
-       ip->hmp = hmp;
-       lockinit(&ip->lk, "h2inode", 0, 0);
-       ip->vp = NULL;
-       ip->refs = 1;
-       hammer2_inode_lock_ex(ip);
-
-       return (ip);
-}
-
-/*
- * Free a HAMMER2 inode memory structure.
- *
- * The inode must be locked exclusively with one reference and will
- * be destroyed on return.
- */
-void
-hammer2_freei(hammer2_inode_t *ip)
-{
-       hammer2_mount_t *hmp = ip->hmp;
-       
-       KKASSERT(ip->hmp != NULL);
-       KKASSERT(ip->vp == NULL);
-       KKASSERT(ip->refs == 1);
-       hammer2_inode_unlock_ex(ip);
-       kfree(ip, hmp->inodes);
-}
-
-/*
  * Borrow HAMMER1's directory hash algorithm #1 with a few modifications.
  * The filename is split into fields which are hashed separately and then
  * added together.
@@ -304,15 +142,6 @@ hammer2_dirhash(const unsigned char *name, size_t len)
        size_t i;
        size_t j;
 
-       /*
-        * Filesystem version 6 or better will create directories
-        * using the ALG1 dirhash.  This hash breaks the filename
-        * up into domains separated by special characters and
-        * hashes each domain independently.
-        *
-        * We also do a simple sub-sort using the first character
-        * of the filename in the top 5-bits.
-        */
        key = 0;
 
        /*
index 5d62bac..85dc1d3 100644 (file)
@@ -140,8 +140,11 @@ hammer2_mount(struct mount *mp, char *path, caddr_t data,
 {
        struct hammer2_mount_info info;
        hammer2_mount_t *hmp;
+       hammer2_key_t lhc;
        struct vnode *devvp;
        struct nlookupdata nd;
+       hammer2_chain_t *schain;
+       hammer2_chain_t *rchain;
        char devstr[MNAMELEN];
        size_t size;
        size_t done;
@@ -271,16 +274,39 @@ hammer2_mount(struct mount *mp, char *path, caddr_t data,
        mp->mnt_vstat.f_bsize = HAMMER2_PBUFSIZE;
 
        /*
-        * Locate the root inode.  The volume header points to the
-        * super-root directory.
+        * First locate the super-root inode, which is key 0 relative to the
+        * volume header's blockset.
+        *
+        * Then locate the root inode by scanning the directory keyspace
+        * represented by the label.
         */
-       /* XXX */
-
-
-       /* Setup root inode */
-       hmp->iroot = hammer2_alloci(hmp);
-       hmp->iroot->type = HAMMER2_INODE_TYPE_DIR | HAMMER2_INODE_TYPE_ROOT;
-       hmp->iroot->data.inum = 1;
+       lhc = hammer2_dirhash(label, strlen(label));
+       schain = hammer2_chain_push(hmp, &hmp->vchain, HAMMER2_SROOT_KEY);
+       if (schain == NULL) {
+               kprintf("hammer2_mount: invalid super-root\n");
+               hammer2_unmount(mp, MNT_FORCE);
+               return EINVAL;
+       }
+       rchain = hammer2_chain_first(hmp, schain, lhc, HAMMER2_DIRHASH_LOMASK);
+       while (rchain) {
+               if (rchain->bref.type == HAMMER2_BREF_TYPE_INODE &&
+                   rchain->u.ip &&
+                   strcmp(label, rchain->u.ip->data.filename) == 0) {
+                       break;
+               }
+               rchain = hammer2_chain_next(hmp, rchain,
+                                           lhc, HAMMER2_DIRHASH_LOMASK);
+       }
+       if (rchain == NULL) {
+               kprintf("hammer2_mount: root label not found\n");
+               hammer2_chain_drop(hmp, schain);
+               hammer2_unmount(mp, MNT_FORCE);
+               return EINVAL;
+       }
+       hmp->schain = schain;
+       hmp->rchain = rchain;
+       hmp->iroot = rchain->u.ip;
+       hammer2_inode_ref(hmp->iroot);
 
        vfs_getnewfsid(mp);
        vfs_add_vnodeops(mp, &hammer2_vnode_vops, &mp->mnt_vn_norm_ops);
@@ -346,10 +372,16 @@ hammer2_unmount(struct mount *mp, int mntflags)
         *      3) Destroy the kmalloc inode zone
         *      4) Free the mount point
         */
-
+       if (hmp->rchain) {
+               hammer2_chain_drop(hmp, hmp->rchain);
+               hmp->rchain = NULL;
+       }
+       if (hmp->schain) {
+               hammer2_chain_drop(hmp, hmp->schain);
+               hmp->schain = NULL;
+       }
        if (hmp->iroot) {
-               hammer2_inode_lock_ex(hmp->iroot);
-               hammer2_freei(hmp->iroot);
+               hammer2_inode_drop(hmp->iroot);
                hmp->iroot = NULL;
        }
        if ((devvp = hmp->devvp) != NULL) {