From 7cfa8da52cfd4b8dbe75786832df9f844940be57 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Fri, 10 Feb 2012 14:12:13 -0800 Subject: [PATCH] hammer2 - flesh out inode and blockref chaining * 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 | 3 +- sys/vfs/hammer2/hammer2.h | 74 ++++++-- sys/vfs/hammer2/hammer2_chain.c | 105 +++++++++++ sys/vfs/hammer2/hammer2_disk.h | 12 +- .../{hammer2_subr.c => hammer2_inode.c} | 172 +++-------------- sys/vfs/hammer2/hammer2_subr.c | 175 +----------------- sys/vfs/hammer2/hammer2_vfsops.c | 56 ++++-- 7 files changed, 243 insertions(+), 354 deletions(-) create mode 100644 sys/vfs/hammer2/hammer2_chain.c copy sys/vfs/hammer2/{hammer2_subr.c => hammer2_inode.c} (59%) diff --git a/sys/vfs/hammer2/Makefile b/sys/vfs/hammer2/Makefile index 451d07693b..0a712ac344 100644 --- a/sys/vfs/hammer2/Makefile +++ b/sys/vfs/hammer2/Makefile @@ -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 diff --git a/sys/vfs/hammer2/hammer2.h b/sys/vfs/hammer2/hammer2.h index fdac4b9eca..9b0b7e76cb 100644 --- a/sys/vfs/hammer2/hammer2.h +++ b/sys/vfs/hammer2/hammer2.h @@ -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; @@ -110,6 +119,16 @@ typedef struct hammer2_inode hammer2_inode_t; #define HAMMER2_INODE_TYPE_ROOT 0x10 #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) */ @@ -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 index 0000000000..710e73fb15 --- /dev/null +++ b/sys/vfs/hammer2/hammer2_chain.c @@ -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 + * by Venkatesh Srinivas + * + * 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 +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/sys/vfs/hammer2/hammer2_disk.h b/sys/vfs/hammer2/hammer2_disk.h index 03c9f0a091..b2867b14ef 100644 --- a/sys/vfs/hammer2/hammer2_disk.h +++ b/sys/vfs/hammer2/hammer2_disk.h @@ -189,6 +189,14 @@ typedef uint32_t hammer2_crc32_t; #define HAMMER2_OFF_MASK_RADIX 0x000000000000003FULL #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 @@ -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 diff --git a/sys/vfs/hammer2/hammer2_subr.c b/sys/vfs/hammer2/hammer2_inode.c similarity index 59% copy from sys/vfs/hammer2/hammer2_subr.c copy to sys/vfs/hammer2/hammer2_inode.c index 3a71e45c0d..478e20972f 100644 --- a/sys/vfs/hammer2/hammer2_subr.c +++ b/sys/vfs/hammer2/hammer2_inode.c @@ -43,89 +43,27 @@ #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); } diff --git a/sys/vfs/hammer2/hammer2_subr.c b/sys/vfs/hammer2/hammer2_subr.c index 3a71e45c0d..efa70110eb 100644 --- a/sys/vfs/hammer2/hammer2_subr.c +++ b/sys/vfs/hammer2/hammer2_subr.c @@ -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); } @@ -122,168 +122,6 @@ 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. - * - * 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 @@ -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; /* diff --git a/sys/vfs/hammer2/hammer2_vfsops.c b/sys/vfs/hammer2/hammer2_vfsops.c index 5d62bac6c6..85dc1d3336 100644 --- a/sys/vfs/hammer2/hammer2_vfsops.c +++ b/sys/vfs/hammer2/hammer2_vfsops.c @@ -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) { -- 2.41.0