hammer2 - wire in statfs/statvfs, add the chain structure, etc
authorMatthew Dillon <dillon@apollo.backplane.com>
Fri, 10 Feb 2012 07:49:37 +0000 (23:49 -0800)
committerMatthew Dillon <dillon@apollo.backplane.com>
Fri, 10 Feb 2012 07:49:37 +0000 (23:49 -0800)
* 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
sys/vfs/hammer2/hammer2_subr.c
sys/vfs/hammer2/hammer2_vfsops.c

index 0af4541..fdac4b9 100644 (file)
@@ -70,16 +70,37 @@ 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.
  */
 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_ */
index d8b52f8..3a71e45 100644 (file)
@@ -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);
+}
index 8e583a8..a669537 100644 (file)
@@ -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;
+}