From 50e4f8f480b812c317378afdf893900917475b9c Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Thu, 9 Feb 2012 23:49:37 -0800 Subject: [PATCH] hammer2 - wire in statfs/statvfs, add the chain structure, etc * Wire mnt_stat and mnt_vstat. Currently dummy-up the values. This allows the mount point to show up in 'df' output. * Add the chain structure for upcoming directory search work. This structure will also be used to track through indirect blocks. The chain structure supplies the full blockref chain from an in-memory structure to the root volume, allowing modifications to be properly tracked. * Move the volume header read to its own support procedure, it's going to eventually be considerably more complex. * Bring the hammer2_dirhash() procedure in from newfs_hammer2. --- sys/vfs/hammer2/hammer2.h | 37 +++++++-- sys/vfs/hammer2/hammer2_subr.c | 67 ++++++++++++++++ sys/vfs/hammer2/hammer2_vfsops.c | 128 +++++++++++++++++++++---------- 3 files changed, 185 insertions(+), 47 deletions(-) diff --git a/sys/vfs/hammer2/hammer2.h b/sys/vfs/hammer2/hammer2.h index 0af4541f5f..fdac4b9eca 100644 --- a/sys/vfs/hammer2/hammer2.h +++ b/sys/vfs/hammer2/hammer2.h @@ -69,6 +69,24 @@ struct hammer2_inode; struct hammer2_mount; +/* + * The chain structure tracks blockref recursions all the way to + * 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. + */ +struct hammer2_chain { + struct hammer2_blockref bref; + struct hammer2_inode *ip; + struct hammer2_chain *parent; + u_int refs; +}; + +typedef struct hammer2_chain hammer2_chain_t; + /* * A hammer2 inode. */ @@ -76,10 +94,13 @@ struct hammer2_inode { struct hammer2_mount *hmp; struct lock lk; struct vnode *vp; - hammer2_inode_data_t data; + unsigned char type; - int busy; u_int refs; + int busy; + + hammer2_chain_t chain; + hammer2_inode_data_t data; }; typedef struct hammer2_inode hammer2_inode_t; @@ -93,10 +114,11 @@ typedef struct hammer2_inode hammer2_inode_t; * Governing mount structure for filesystem (aka vp->v_mount) */ struct hammer2_mount { - struct mount *mp; - int ronly; /* block device mounted read-only */ - struct vnode *devvp; /* device vnode */ + struct mount *mp; /* kernel mount */ + struct vnode *devvp; /* device vnode */ struct lock lk; + struct netexport export; /* nfs export */ + int ronly; /* read-only mount */ struct hammer2_inode *iroot; @@ -107,10 +129,9 @@ struct hammer2_mount { struct malloc_type *ipstacks; int nipstacks; int maxipstacks; + hammer2_chain_t chain; hammer2_volume_data_t voldata; - - struct netexport export; }; typedef struct hammer2_mount hammer2_mount_t; @@ -157,5 +178,7 @@ 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_key_t hammer2_dirhash(const unsigned char *name, size_t len); + #endif /* !_KERNEL */ #endif /* !_VFS_HAMMER2_HAMMER2_H_ */ diff --git a/sys/vfs/hammer2/hammer2_subr.c b/sys/vfs/hammer2/hammer2_subr.c index d8b52f88f9..3a71e45c0d 100644 --- a/sys/vfs/hammer2/hammer2_subr.c +++ b/sys/vfs/hammer2/hammer2_subr.c @@ -283,3 +283,70 @@ hammer2_freei(hammer2_inode_t *ip) 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. + * + * 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; + + /* + * 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); +} diff --git a/sys/vfs/hammer2/hammer2_vfsops.c b/sys/vfs/hammer2/hammer2_vfsops.c index 8e583a8692..a6695370f7 100644 --- a/sys/vfs/hammer2/hammer2_vfsops.c +++ b/sys/vfs/hammer2/hammer2_vfsops.c @@ -66,6 +66,8 @@ static int hammer2_vptofh(struct vnode *vp, struct fid *fhp); static int hammer2_checkexp(struct mount *mp, struct sockaddr *nam, int *exflagsp, struct ucred **credanonp); +static int hammer2_install_volume_header(hammer2_mount_t *hmp); + /* * HAMMER2 vfs operations. */ @@ -139,20 +141,19 @@ hammer2_mount(struct mount *mp, char *path, caddr_t data, struct hammer2_mount_info info; hammer2_mount_t *hmp; struct vnode *devvp; - struct hammer2_volume_data *vd; struct nlookupdata nd; - struct buf *bp; char devstr[MNAMELEN]; size_t size; size_t done; - char *dev, *label; + char *dev; + char *label; int ronly = 1; int error; hmp = NULL; - dev = label = NULL; + dev = NULL; + label = NULL; devvp = NULL; - vd = NULL; kprintf("hammer2_mount\n"); @@ -177,8 +178,9 @@ hammer2_mount(struct mount *mp, char *path, caddr_t data, dev = devstr; label = strchr(devstr, '@'); if (label == NULL || - ((label + 1) - dev) > done) + ((label + 1) - dev) > done) { return (EINVAL); + } *label = '\0'; label++; if (*label == '\0') @@ -232,18 +234,6 @@ hammer2_mount(struct mount *mp, char *path, caddr_t data, if (error) return error; - /* Read the volume header */ - /* XXX: Read four volhdrs, find one w/ highest TID & CRC */ - error = bread(devvp, 0, HAMMER2_PBUFSIZE, &bp); - vd = (struct hammer2_volume_data *) bp->b_data; - if (error || - (vd->magic != HAMMER2_VOLUME_ID_HBO)) { - brelse(bp); - vrele(devvp); - VOP_CLOSE(devvp, ronly ? FREAD : FREAD | FWRITE); - return (EINVAL); - } - /* * Block device opened successfully, finish initializing the * mount structure. @@ -259,16 +249,33 @@ hammer2_mount(struct mount *mp, char *path, caddr_t data, kmalloc_create(&hmp->inodes, "HAMMER2-inodes"); kmalloc_create(&hmp->ipstacks, "HAMMER2-ipstacks"); - bcopy(bp->b_data, &hmp->voldata, sizeof(struct hammer2_volume_data)); - brelse(bp); - bp = NULL; - mp->mnt_flag = MNT_LOCAL; + mp->mnt_kern_flag |= MNTK_ALL_MPSAFE; /* all entry pts are SMP */ + + /* + * Install the volume header + */ + error = hammer2_install_volume_header(hmp); + if (error) { + hammer2_unmount(mp, MNT_FORCE); + return error; + } /* - * Filesystem subroutines are self-synchronized + * required mount structure initializations */ - mp->mnt_kern_flag |= MNTK_ALL_MPSAFE; + mp->mnt_stat.f_iosize = HAMMER2_PBUFSIZE; + mp->mnt_stat.f_bsize = HAMMER2_PBUFSIZE; + + mp->mnt_vstat.f_frsize = HAMMER2_PBUFSIZE; + mp->mnt_vstat.f_bsize = HAMMER2_PBUFSIZE; + + /* + * Locate the root inode. The volume header points to the + * super-root directory. + */ + /* XXX */ + /* Setup root inode */ hmp->iroot = hammer2_alloci(hmp); @@ -308,7 +315,7 @@ hammer2_unmount(struct mount *mp, int mntflags) { hammer2_mount_t *hmp; int flags; - int error; + int error = 0; int ronly = ((mp->mnt_flag & MNT_RDONLY) != 0); struct vnode *devvp; @@ -322,7 +329,15 @@ hammer2_unmount(struct mount *mp, int mntflags) hammer2_mount_exlock(hmp); - error = vflush(mp, 0, flags); + /* + * If mount initialization proceeded far enough we must flush + * its vnodes. + */ + if (hmp->iroot) + error = vflush(mp, 0, flags); + + if (error) + return error; /* * Work to do: @@ -398,21 +413,13 @@ hammer2_statfs(struct mount *mp, struct statfs *sbp, struct ucred *cred) { hammer2_mount_t *hmp; - kprintf("hammer2_statfs\n"); - hmp = MPTOH2(mp); - sbp->f_iosize = PAGE_SIZE; - sbp->f_bsize = PAGE_SIZE; - - sbp->f_blocks = 10; - sbp->f_bavail = 10; - sbp->f_bfree = 10; - - sbp->f_files = 10; - sbp->f_ffree = 10; - sbp->f_owner = 0; + mp->mnt_stat.f_files = 10; + mp->mnt_stat.f_bfree = 10; + mp->mnt_stat.f_bavail = mp->mnt_stat.f_bfree; + *sbp = mp->mnt_stat; return (0); } @@ -420,8 +427,16 @@ static int hammer2_statvfs(struct mount *mp, struct statvfs *sbp, struct ucred *cred) { - kprintf("hammer2_statvfs\n"); - return (EOPNOTSUPP); + hammer2_mount_t *hmp; + + hmp = MPTOH2(mp); + + mp->mnt_vstat.f_files = 10; + mp->mnt_vstat.f_bfree = 10; + mp->mnt_vstat.f_bavail = mp->mnt_stat.f_bfree; + + *sbp = mp->mnt_vstat; + return (0); } /* @@ -480,3 +495,36 @@ hammer2_checkexp(struct mount *mp, struct sockaddr *nam, { return (0); } + +/* + * Support code for hammer2_mount(). Read, verify, and install the volume + * header into the HMP + * + * XXX read four volhdrs and use the one with the highest TID whos CRC + * matches. + * + * XXX check iCRCs. + */ +static +int +hammer2_install_volume_header(hammer2_mount_t *hmp) +{ + hammer2_volume_data_t *vd; + struct buf *bp = NULL; + int error; + + error = bread(hmp->devvp, 0, HAMMER2_PBUFSIZE, &bp); + if (error) + return error; + bcopy(bp->b_data, &hmp->voldata, sizeof(hmp->voldata)); + brelse(bp); + bp = NULL; + + vd = &hmp->voldata; + if (vd->magic != HAMMER2_VOLUME_ID_HBO) { + kprintf("hammer_mount: volume header magic is wrong\n"); + return EINVAL; + } + kprintf("hammer_mount: volume header magic good\n"); + return 0; +} -- 2.41.0