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;
* 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;
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;
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_ */
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);
+}
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.
*/
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");
dev = devstr;
label = strchr(devstr, '@');
if (label == NULL ||
- ((label + 1) - dev) > done)
+ ((label + 1) - dev) > done) {
return (EINVAL);
+ }
*label = '\0';
label++;
if (*label == '\0')
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.
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);
{
hammer2_mount_t *hmp;
int flags;
- int error;
+ int error = 0;
int ronly = ((mp->mnt_flag & MNT_RDONLY) != 0);
struct vnode *devvp;
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:
{
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);
}
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);
}
/*
{
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;
+}