hammer2 - Add hammer2 boot support
authorMatthew Dillon <dillon@backplane.com>
Tue, 24 Sep 2013 22:14:26 +0000 (15:14 -0700)
committerMatthew Dillon <dillon@backplane.com>
Tue, 24 Sep 2013 22:29:57 +0000 (15:29 -0700)
* Add hammer2 boot loader support.  The hammer2 boot loader accesses the
  hammer2 mount starting at the super-root.  To use hammer2 boot support
  you need to have a PFS called 'boot', which will be seen as "/boot" by
  the boot loader.

  The 'boot' PFS can be created either by creating a boot-specific H2
  partition with 'newfs_hammer2 -L boot ...', or by using
  'hammer2 pfs-create boot' to create a PFS called 'boot'.

  You can access any super-root if desired.

* Since boot is a super-root you can mix boot PFS's and other PFS's on the
  same hammer2 filesystem, including creating a boot PFS far later on.

* WARNING!!!!!  The 'boot' PFS must be configured without compression.
  i.e. 'hammer2 setcomp autozero /boot' (assuming you've mounted it on /boot),
  before you install anything.  The newfs_hammer2 utility will automatically
  handle this if you specify a label name of 'boot' (i.e. -L boot).

* WARNING!!!!!  The BIOS may not be able to reliably access very high
  sector numbers on large hard drives, so to be safe we recommend creating
  a small 'a' partition anyway, unless the drive / main hammer2 filesystem
  is small enough to not cause problems.

* Add %qx support to boot2's mini printf().

* Fix ipdata->comp_algo propagation bug in hammer2_inode_create()

* newfs_hammer2 and the pfs_create ioctl will set comp_algo to AUTOZERO
  for PFS's called "boot" automatically.

17 files changed:
lib/libstand/Makefile
lib/libstand/hammer1.c [new file with mode: 0644]
lib/libstand/hammer2.c
lib/libstand/printf.c
lib/libstand/read.c
lib/libstand/stand.h
sbin/newfs_hammer2/newfs_hammer2.c
sys/boot/Makefile
sys/boot/common/boot2.h
sys/boot/common/help.common
sys/boot/common/loader.8
sys/boot/pc32/boot2/Makefile
sys/boot/pc32/boot2/boot2.c
sys/boot/pc32/libi386/biosdisk.c
sys/boot/pc32/loader/dloader.rc
sys/vfs/hammer2/hammer2_inode.c
sys/vfs/hammer2/hammer2_ioctl.c

index 46ee091..d5cb42c 100644 (file)
@@ -48,6 +48,9 @@ SRCS+=        bcmp.c bcopy.c bzero.c ffs.c index.c memccpy.c memchr.c memcmp.c \
 SRCS+=  ucmpdi2.c
 .endif
 
+.PATH: ${.CURDIR}/../../sys/libkern
+SRCS+=  icrc32.c
+
 # _setjmp/_longjmp
 .if ${MACHINE_ARCH} == "i386" || ${MACHINE_ARCH} == "x86_64"
 .PATH: ${.CURDIR}/i386
@@ -89,7 +92,8 @@ SRCS+=        ufs.c nfs.c cd9660.c tftp.c zipfs.c bzipfs.c gzipfs.c
 SRCS+= netif.c nfs.c
 SRCS+= dosfs.c ext2fs.c
 SRCS+= splitfs.c
-SRCS+= hammerread.c
+SRCS+= hammer1.c
+SRCS+= hammer2.c
 
 .include <bsd.lib.mk>
 
diff --git a/lib/libstand/hammer1.c b/lib/libstand/hammer1.c
new file mode 100644 (file)
index 0000000..785c13c
--- /dev/null
@@ -0,0 +1,1109 @@
+/*
+ * Copyright (c) 2008 The DragonFly Project.  All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Simon Schubert <corecode@fs.ei.tum.de>
+ * and Matthew Dillon <dillon@backplane.com>
+ *
+ * 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.
+ */
+
+/*
+ * This file is being used by boot2 and libstand (loader).
+ * Compile with -DTESTING to obtain a binary.
+ */
+
+
+#if !defined(BOOT2) && !defined(TESTING)
+#define        LIBSTAND        1
+#endif
+
+#ifdef BOOT2
+#include "boot2.h"
+#else
+#include <sys/param.h>
+#include <stddef.h>
+#include <stdint.h>
+#endif
+
+#ifdef TESTING
+#include <sys/fcntl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <dirent.h>
+#endif
+
+#ifdef LIBSTAND
+#include "stand.h"
+#endif
+
+#include <vfs/hammer/hammer_disk.h>
+
+#ifndef BOOT2
+struct blockentry {
+       hammer_off_t    off;
+       int             use;
+       char            *data;
+};
+
+#ifdef TESTING
+#define NUMCACHE       16
+#else
+#define        NUMCACHE        6
+#endif
+
+struct hfs {
+#ifdef TESTING
+       int             fd;
+#else  // libstand
+       struct open_file *f;
+#endif
+       hammer_off_t    root;
+       int64_t         buf_beg;
+       int64_t         last_dir_ino;
+       u_int8_t        last_dir_cap_flags;
+       int             lru;
+       struct blockentry cache[NUMCACHE];
+};
+
+static void *
+hread(struct hfs *hfs, hammer_off_t off)
+{
+       hammer_off_t boff = off & ~HAMMER_BUFMASK64;
+
+       boff &= HAMMER_OFF_LONG_MASK;
+
+       if (HAMMER_ZONE_DECODE(off) != HAMMER_ZONE_RAW_VOLUME_INDEX)
+               boff += hfs->buf_beg;
+
+       struct blockentry *be = NULL;
+       for (int i = 0; i < NUMCACHE; i++) {
+               if (be == NULL || be->use > hfs->cache[i].use)
+                       be = &hfs->cache[i];
+               if (hfs->cache[i].off == boff) {
+                       be = &hfs->cache[i];
+                       break;
+               }
+       }
+       if (be->off != boff) {
+               // Didn't find any match
+               be->off = boff;
+#ifdef TESTING
+               ssize_t res = pread(hfs->fd, be->data, HAMMER_BUFSIZE,
+                                   boff & HAMMER_OFF_SHORT_MASK);
+               if (res != HAMMER_BUFSIZE)
+                       err(1, "short read on off %llx", boff);
+#else  // libstand
+               size_t rlen;
+               int rv = hfs->f->f_dev->dv_strategy(hfs->f->f_devdata, F_READ,
+                       boff >> DEV_BSHIFT, HAMMER_BUFSIZE,
+                       be->data, &rlen);
+               if (rv || rlen != HAMMER_BUFSIZE)
+                       return (NULL);
+#endif
+       }
+
+       be->use = ++hfs->lru;
+       return &be->data[off & HAMMER_BUFMASK];
+}
+
+#else  /* BOOT2 */
+
+struct hammer_dmadat {
+       struct boot2_dmadat boot2;
+       char            buf[HAMMER_BUFSIZE];
+};
+
+#define fsdmadat       ((struct hammer_dmadat *)boot2_dmadat)
+
+struct hfs {
+       hammer_off_t    root;
+       int64_t         last_dir_ino;
+       u_int8_t        last_dir_cap_flags;
+       int64_t         buf_beg;
+};
+
+static void *
+hread(struct hfs *hfs, hammer_off_t off)
+{
+       char *buf = fsdmadat->buf;
+
+       hammer_off_t boff = off & ~HAMMER_BUFMASK64;
+       boff &= HAMMER_OFF_LONG_MASK;
+       if (HAMMER_ZONE_DECODE(off) != HAMMER_ZONE_RAW_VOLUME_INDEX)
+               boff += hfs->buf_beg;
+       boff &= HAMMER_OFF_SHORT_MASK;
+       boff >>= DEV_BSHIFT;
+       if (dskread(buf, boff, HAMMER_BUFSIZE >> DEV_BSHIFT))
+               return (NULL);
+       return (&buf[off & HAMMER_BUFMASK]);
+}
+
+static void
+bzero(void *buf, size_t size)
+{
+       for (size_t i = 0; i < size; i++)
+               ((char *)buf)[i] = 0;
+}
+
+static void
+bcopy(void *src, void *dst, size_t size)
+{
+       memcpy(dst, src, size);
+}
+
+static size_t
+strlen(const char *s)
+{
+       size_t l = 0;
+       for (; *s != 0; s++)
+               l++;
+       return (l);
+}
+
+static int
+memcmp(const void *a, const void *b, size_t len)
+{
+       for (size_t p = 0; p < len; p++) {
+               int r = ((const char *)a)[p] - ((const char *)b)[p];
+               if (r != 0)
+                       return (r);
+       }
+
+       return (0);
+}
+
+#endif
+
+/*
+ * (from hammer_btree.c)
+ *
+ * Compare two B-Tree elements, return -N, 0, or +N (e.g. similar to strcmp).
+ *
+ * Note that for this particular function a return value of -1, 0, or +1
+ * can denote a match if create_tid is otherwise discounted.  A create_tid
+ * of zero is considered to be 'infinity' in comparisons.
+ *
+ * See also hammer_rec_rb_compare() and hammer_rec_cmp() in hammer_object.c.
+ */
+static int
+hammer_btree_cmp(hammer_base_elm_t key1, hammer_base_elm_t key2)
+{
+       if (key1->localization < key2->localization)
+               return(-5);
+       if (key1->localization > key2->localization)
+               return(5);
+
+       if (key1->obj_id < key2->obj_id)
+               return(-4);
+       if (key1->obj_id > key2->obj_id)
+               return(4);
+
+       if (key1->rec_type < key2->rec_type)
+               return(-3);
+       if (key1->rec_type > key2->rec_type)
+               return(3);
+
+       if (key1->key < key2->key)
+               return(-2);
+       if (key1->key > key2->key)
+               return(2);
+
+       /*
+        * A create_tid of zero indicates a record which is undeletable
+        * and must be considered to have a value of positive infinity.
+        */
+       if (key1->create_tid == 0) {
+               if (key2->create_tid == 0)
+                       return(0);
+               return(1);
+       }
+       if (key2->create_tid == 0)
+               return(-1);
+       if (key1->create_tid < key2->create_tid)
+               return(-1);
+       if (key1->create_tid > key2->create_tid)
+               return(1);
+       return(0);
+}
+
+/*
+ * Heuristical search for the first element whos comparison is <= 1.  May
+ * return an index whos compare result is > 1 but may only return an index
+ * whos compare result is <= 1 if it is the first element with that result.
+ */
+static int
+hammer_btree_search_node(hammer_base_elm_t elm, hammer_node_ondisk_t node)
+{
+       int b;
+       int s;
+       int i;
+       int r;
+
+       /*
+        * Don't bother if the node does not have very many elements
+        */
+       b = 0;
+       s = node->count;
+       while (s - b > 4) {
+               i = b + (s - b) / 2;
+               r = hammer_btree_cmp(elm, &node->elms[i].leaf.base);
+               if (r <= 1) {
+                       s = i;
+               } else {
+                       b = i;
+               }
+       }
+       return(b);
+}
+
+#if 0
+/*
+ * (from hammer_subs.c)
+ *
+ * Return a namekey hash.   The 64 bit namekey hash consists of a 32 bit
+ * crc in the MSB and 0 in the LSB.  The caller will use the low bits to
+ * generate a unique key and will scan all entries with the same upper
+ * 32 bits when issuing a lookup.
+ *
+ * We strip bit 63 in order to provide a positive key, this way a seek
+ * offset of 0 will represent the base of the directory.
+ *
+ * This function can never return 0.  We use the MSB-0 space to synthesize
+ * artificial directory entries such as "." and "..".
+ */
+static int64_t
+hammer_directory_namekey(const void *name, int len)
+{
+       int64_t key;
+
+       key = (int64_t)(crc32(name, len) & 0x7FFFFFFF) << 32;
+       if (key == 0)
+               key |= 0x100000000LL;
+       return(key);
+}
+#else
+static int64_t
+hammer_directory_namekey(const void *name __unused, int len __unused)
+{
+       return (0);
+}
+#endif
+
+
+#ifndef BOOT2
+/*
+ * Misc
+ */
+static u_int32_t
+hammer_to_unix_xid(uuid_t *uuid)
+{
+       return(*(u_int32_t *)&uuid->node[2]);
+}
+
+static int
+hammer_get_dtype(u_int8_t obj_type)
+{
+       switch(obj_type) {
+       case HAMMER_OBJTYPE_DIRECTORY:
+               return(DT_DIR);
+       case HAMMER_OBJTYPE_REGFILE:
+               return(DT_REG);
+       case HAMMER_OBJTYPE_DBFILE:
+               return(DT_DBF);
+       case HAMMER_OBJTYPE_FIFO:
+               return(DT_FIFO);
+       case HAMMER_OBJTYPE_SOCKET:
+               return(DT_SOCK);
+       case HAMMER_OBJTYPE_CDEV:
+               return(DT_CHR);
+       case HAMMER_OBJTYPE_BDEV:
+               return(DT_BLK);
+       case HAMMER_OBJTYPE_SOFTLINK:
+               return(DT_LNK);
+       default:
+               return(DT_UNKNOWN);
+       }
+       /* not reached */
+}
+
+static int
+hammer_get_mode(u_int8_t obj_type)
+{
+       switch(obj_type) {
+       case HAMMER_OBJTYPE_DIRECTORY:
+               return(S_IFDIR);
+       case HAMMER_OBJTYPE_REGFILE:
+               return(S_IFREG);
+       case HAMMER_OBJTYPE_DBFILE:
+               return(S_IFDB);
+       case HAMMER_OBJTYPE_FIFO:
+               return(S_IFIFO);
+       case HAMMER_OBJTYPE_SOCKET:
+               return(S_IFSOCK);
+       case HAMMER_OBJTYPE_CDEV:
+               return(S_IFCHR);
+       case HAMMER_OBJTYPE_BDEV:
+               return(S_IFBLK);
+       case HAMMER_OBJTYPE_SOFTLINK:
+               return(S_IFLNK);
+       default:
+               return(0);
+       }
+       /* not reached */
+}
+
+#if DEBUG > 1
+static void
+hprintb(hammer_base_elm_t e)
+{
+       printf("%d/", e->localization);
+       if (e->obj_id >> 32 != 0)
+               printf("%lx%08lx",
+                      (long)(e->obj_id >> 32),
+                      (long)(e->obj_id & 0xffffffff));
+       else
+               printf("%lx", (long)e->obj_id);
+       printf("/%d/", e->rec_type);
+       if (e->key >> 32 != 0)
+               printf("%lx%08lx",
+                      (long)(e->key >> 32),
+                      (long)(e->key & 0xffffffff));
+       else
+               printf("%lx", (long)e->key);
+#ifdef TESTING
+       printf("/%llx/%llx", e->create_tid, e->delete_tid);
+#endif
+}
+#endif /* DEBUG > 1 */
+#endif /* !BOOT2 */
+
+static hammer_btree_leaf_elm_t
+hfind(struct hfs *hfs, hammer_base_elm_t key, hammer_base_elm_t end)
+{
+#if DEBUG > 1
+       printf("searching for ");
+       hprintb(key);
+       printf(" end ");
+       hprintb(end);
+       printf("\n");
+#endif
+
+       int n;
+       int r;
+       struct hammer_base_elm search = *key;
+       struct hammer_base_elm backtrack;
+       hammer_off_t nodeoff = hfs->root;
+       hammer_node_ondisk_t node;
+       hammer_btree_elm_t e = NULL;
+       int internal;
+
+loop:
+       node = hread(hfs, nodeoff);
+       if (node == NULL)
+               return (NULL);
+       internal = node->type == HAMMER_BTREE_TYPE_INTERNAL;
+
+#if DEBUG > 3
+       for (int i = 0; i < node->count; i++) {
+               printf("E: ");
+               hprintb(&node->elms[i].base);
+               printf("\n");
+       }
+       if (internal) {
+               printf("B: ");
+               hprintb(&node->elms[node->count].base);
+               printf("\n");
+       }
+#endif
+
+       n = hammer_btree_search_node(&search, node);
+
+       // In internal nodes, we cover the right boundary as well.
+       // If we hit it, we'll backtrack.
+       for (; n < node->count + internal; n++) {
+               e = &node->elms[n];
+               r = hammer_btree_cmp(&search, &e->base);
+
+               if (r < 0)
+                       break;
+       }
+
+       // unless we stopped right on the left side, we need to back off a bit
+       if (n > 0)
+               e = &node->elms[--n];
+
+#if DEBUG > 2
+       printf("  found: ");
+       hprintb(&e->base);
+       printf("\n");
+#endif
+
+       if (internal) {
+               // If we hit the right boundary, backtrack to
+               // the next higher level.
+               if (n == node->count)
+                       goto backtrack;
+               nodeoff = e->internal.subtree_offset;
+               backtrack = (e+1)->base;
+               goto loop;
+       }
+
+       r = hammer_btree_cmp(key, &e->base);
+       // If we're more off than the createtid, take the next elem
+       if (r > 1) {
+               e++;
+               n++;
+       }
+
+       // Skip deleted elements
+       while (n < node->count && e->base.delete_tid != 0) {
+               e++;
+               n++;
+       }
+
+       // In the unfortunate event when there is no next
+       // element in this node, we repeat the search with
+       // a key beyond the right boundary
+       if (n == node->count) {
+backtrack:
+               search = backtrack;
+               nodeoff = hfs->root;
+
+#if DEBUG > 2
+               printf("hit right boundary (%d), resetting search to ",
+                      node->count);
+               hprintb(&search);
+               printf("\n");
+#endif
+               goto loop;
+       }
+
+#if DEBUG > 1
+       printf("  result: ");
+       hprintb(&e->base);
+       printf("\n");
+#endif
+
+       if (end != NULL)
+               if (hammer_btree_cmp(end, &e->base) < -1)
+                       goto fail;
+
+       return (&e->leaf);
+
+fail:
+#if DEBUG > 1
+       printf("  fail.\n");
+#endif
+       return (NULL);
+}
+
+/*
+ * Returns the directory entry localization field based on the directory
+ * inode's capabilities.
+ */
+static u_int32_t
+hdirlocalization(struct hfs *hfs, ino_t ino)
+{
+       struct hammer_base_elm key;
+
+       if (ino != hfs->last_dir_ino) {
+               bzero(&key, sizeof(key));
+               key.obj_id = ino;
+               key.localization = HAMMER_LOCALIZE_INODE;
+               key.rec_type = HAMMER_RECTYPE_INODE;
+               hammer_btree_leaf_elm_t e;
+               hammer_data_ondisk_t ed;
+
+               e = hfind(hfs, &key, &key);
+               if (e) {
+                       ed = hread(hfs, e->data_offset);
+                       if (ed) {
+                               hfs->last_dir_ino = ino;
+                               hfs->last_dir_cap_flags = ed->inode.cap_flags;
+                       } else {
+                               printf("hdirlocal: no inode data for %llx\n",
+                                       (long long)ino);
+                       }
+               } else {
+                       printf("hdirlocal: no inode entry for %llx\n",
+                               (long long)ino);
+               }
+       }
+       if (hfs->last_dir_cap_flags & HAMMER_INODE_CAP_DIR_LOCAL_INO)
+               return(HAMMER_LOCALIZE_INODE);
+       else
+               return(HAMMER_LOCALIZE_MISC);
+}
+
+#ifndef BOOT2
+static int
+hreaddir(struct hfs *hfs, ino_t ino, int64_t *off, struct dirent *de)
+{
+       struct hammer_base_elm key, end;
+
+#if DEBUG > 2
+       printf("%s(%llx, %lld)\n", __func__, (long long)ino, *off);
+#endif
+
+       bzero(&key, sizeof(key));
+       key.obj_id = ino;
+       key.localization = hdirlocalization(hfs, ino);
+       key.rec_type = HAMMER_RECTYPE_DIRENTRY;
+       key.key = *off;
+
+       end = key;
+       end.key = HAMMER_MAX_KEY;
+
+       hammer_btree_leaf_elm_t e;
+
+       e = hfind(hfs, &key, &end);
+       if (e == NULL) {
+               errno = ENOENT;
+               return (-1);
+       }
+
+       *off = e->base.key + 1;         // remember next pos
+
+       de->d_namlen = e->data_len - HAMMER_ENTRY_NAME_OFF;
+       de->d_type = hammer_get_dtype(e->base.obj_type);
+       hammer_data_ondisk_t ed = hread(hfs, e->data_offset);
+       if (ed == NULL)
+               return (-1);
+       de->d_ino = ed->entry.obj_id;
+       bcopy(ed->entry.name, de->d_name, de->d_namlen);
+       de->d_name[de->d_namlen] = 0;
+
+       return (0);
+}
+#endif
+
+static ino_t
+hresolve(struct hfs *hfs, ino_t dirino, const char *name)
+{
+       struct hammer_base_elm key, end;
+       size_t namel = strlen(name);
+
+#if DEBUG > 2
+       printf("%s(%llx, %s)\n", __func__, (long long)dirino, name);
+#endif
+
+       bzero(&key, sizeof(key));
+       key.obj_id = dirino;
+       key.localization = hdirlocalization(hfs, dirino);
+       key.key = hammer_directory_namekey(name, namel);
+       key.rec_type = HAMMER_RECTYPE_DIRENTRY;
+       end = key;
+       end.key = HAMMER_MAX_KEY;
+
+       hammer_btree_leaf_elm_t e;
+       while ((e = hfind(hfs, &key, &end)) != NULL) {
+               key.key = e->base.key + 1;
+
+               size_t elen = e->data_len - HAMMER_ENTRY_NAME_OFF;
+               hammer_data_ondisk_t ed = hread(hfs, e->data_offset);
+               if (ed == NULL)
+                       return (-1);
+#ifdef BOOT2
+               if (ls) {
+                       for (int i = 0; i < elen; i++)
+                               putchar(ed->entry.name[i]);
+                       putchar(' ');
+                       ls = 2;
+                       continue;
+               }
+#endif
+               if (elen == namel && memcmp(ed->entry.name, name, MIN(elen, namel)) == 0)
+                       return (ed->entry.obj_id);
+       }
+
+#if BOOT2
+       if (ls == 2)
+               printf("\n");
+#endif
+
+       return -1;
+}
+
+static ino_t
+hlookup(struct hfs *hfs, const char *path)
+{
+#if DEBUG > 2
+       printf("%s(%s)\n", __func__, path);
+#endif
+
+#ifdef BOOT2
+       ls = 0;
+#endif
+       ino_t ino = 1;
+       do {
+               char name[MAXPATHLEN + 1];
+               while (*path == '/')
+                       path++;
+               if (*path == 0)
+                       break;
+               for (char *n = name; *path != 0 && *path != '/'; path++, n++) {
+                       n[0] = *path;
+                       n[1] = 0;
+               }
+
+#ifdef BOOT2
+               // A single ? means "list"
+               if (name[0] == '?' && name[1] == 0)
+                       ls = 1;
+#endif
+
+               ino = hresolve(hfs, ino, name);
+       } while (ino != (ino_t)-1 && *path != 0);
+
+       return (ino);
+}
+
+
+#ifndef BOOT2
+static int
+hstat(struct hfs *hfs, ino_t ino, struct stat* st)
+{
+       struct hammer_base_elm key;
+
+#if DEBUG > 2
+       printf("%s(%llx)\n", __func__, (long long)ino);
+#endif
+
+       bzero(&key, sizeof(key));
+       key.obj_id = ino;
+       key.localization = HAMMER_LOCALIZE_INODE;
+       key.rec_type = HAMMER_RECTYPE_INODE;
+
+       hammer_btree_leaf_elm_t e = hfind(hfs, &key, &key);
+       if (e == NULL) {
+#ifndef BOOT2
+               errno = ENOENT;
+#endif
+               return -1;
+       }
+
+       hammer_data_ondisk_t ed = hread(hfs, e->data_offset);
+       if (ed == NULL)
+               return (-1);
+
+       st->st_mode = ed->inode.mode | hammer_get_mode(ed->inode.obj_type);
+       st->st_uid = hammer_to_unix_xid(&ed->inode.uid);
+       st->st_gid = hammer_to_unix_xid(&ed->inode.gid);
+       st->st_size = ed->inode.size;
+
+       return (0);
+}
+#endif
+
+static ssize_t
+hreadf(struct hfs *hfs, ino_t ino, int64_t off, int64_t len, char *buf)
+{
+       int64_t startoff = off;
+       struct hammer_base_elm key, end;
+
+       bzero(&key, sizeof(key));
+       key.obj_id = ino;
+       key.localization = HAMMER_LOCALIZE_MISC;
+       key.rec_type = HAMMER_RECTYPE_DATA;
+       end = key;
+       end.key = HAMMER_MAX_KEY;
+
+       while (len > 0) {
+               key.key = off + 1;
+               hammer_btree_leaf_elm_t e = hfind(hfs, &key, &end);
+               int64_t dlen;
+
+               if (e == NULL || off > e->base.key) {
+                       bzero(buf, len);
+                       off += len;
+                       len = 0;
+                       break;
+               }
+
+               int64_t doff = e->base.key - e->data_len;
+               if (off < doff) {
+                       // sparse file, beginning
+                       dlen = doff - off;
+                       dlen = MIN(dlen, len);
+                       bzero(buf, dlen);
+               } else {
+                       int64_t boff = off - doff;
+                       hammer_off_t roff = e->data_offset;
+
+                       dlen = e->data_len;
+                       dlen -= boff;
+                       dlen = MIN(dlen, len);
+
+                       while (boff >= HAMMER_BUFSIZE) {
+                               boff -= HAMMER_BUFSIZE;
+                               roff += HAMMER_BUFSIZE;
+                       }
+
+                       /*
+                        * boff - relative offset in disk buffer (not aligned)
+                        * roff - base offset of disk buffer     (not aligned)
+                        * dlen - amount of data we think we can copy
+                        *
+                        * hread only reads 16K aligned buffers, check for
+                        * a length overflow and truncate dlen appropriately.
+                        */
+                       if ((roff & ~HAMMER_BUFMASK64) != ((roff + boff + dlen - 1) & ~HAMMER_BUFMASK64))
+                               dlen = HAMMER_BUFSIZE - ((boff + roff) & HAMMER_BUFMASK);
+                       char *data = hread(hfs, roff);
+                       if (data == NULL)
+                               return (-1);
+                       bcopy(data + boff, buf, dlen);
+               }
+
+               buf += dlen;
+               off += dlen;
+               len -= dlen;
+       }
+
+       return (off - startoff);
+}
+
+#ifdef BOOT2
+struct hfs hfs;
+
+static int
+boot2_hammer_init(void)
+{
+       hammer_volume_ondisk_t volhead;
+
+       volhead = hread(&hfs, HAMMER_ZONE_ENCODE(1, 0));
+       if (volhead == NULL)
+               return (-1);
+       if (volhead->vol_signature != HAMMER_FSBUF_VOLUME)
+               return (-1);
+       hfs.root = volhead->vol0_btree_root;
+       hfs.buf_beg = volhead->vol_buf_beg;
+       return (0);
+}
+
+static boot2_ino_t
+boot2_hammer_lookup(const char *path)
+{
+       ino_t ino = hlookup(&hfs, path);
+
+       if (ino == -1)
+               ino = 0;
+
+       fs_off = 0;
+
+       return (ino);
+}
+
+static ssize_t
+boot2_hammer_read(boot2_ino_t ino, void *buf, size_t len)
+{
+       ssize_t rlen = hreadf(&hfs, ino, fs_off, len, buf);
+       if (rlen != -1)
+               fs_off += rlen;
+       return (rlen);
+}
+
+const struct boot2_fsapi boot2_hammer_api = {
+       .fsinit = boot2_hammer_init,
+       .fslookup = boot2_hammer_lookup,
+       .fsread = boot2_hammer_read
+};
+
+#endif
+
+#ifndef BOOT2
+static int
+hinit(struct hfs *hfs)
+{
+#if DEBUG
+       printf("hinit\n");
+#endif
+       for (int i = 0; i < NUMCACHE; i++) {
+               hfs->cache[i].data = malloc(HAMMER_BUFSIZE);
+               hfs->cache[i].off = -1; // invalid
+               hfs->cache[i].use = 0;
+
+#if DEBUG
+               if (hfs->cache[i].data == NULL)
+                       printf("malloc failed\n");
+#endif
+       }
+       hfs->lru = 0;
+       hfs->last_dir_ino = -1;
+
+       hammer_volume_ondisk_t volhead = hread(hfs, HAMMER_ZONE_ENCODE(1, 0));
+
+#ifdef TESTING
+       if (volhead) {
+               printf("signature: %svalid\n",
+                      volhead->vol_signature != HAMMER_FSBUF_VOLUME ?
+                               "in" :
+                               "");
+               printf("name: %s\n", volhead->vol_name);
+       }
+#endif
+
+       if (volhead == NULL || volhead->vol_signature != HAMMER_FSBUF_VOLUME) {
+               for (int i = 0; i < NUMCACHE; i++) {
+                       free(hfs->cache[i].data);
+                       hfs->cache[i].data = NULL;
+               }
+               errno = ENODEV;
+               return (-1);
+       }
+
+       hfs->root = volhead->vol0_btree_root;
+       hfs->buf_beg = volhead->vol_buf_beg;
+
+       return (0);
+}
+
+static void
+hclose(struct hfs *hfs)
+{
+#if DEBUG
+       printf("hclose\n");
+#endif
+       for (int i = 0; i < NUMCACHE; i++) {
+               if (hfs->cache[i].data) {
+                       free(hfs->cache[i].data);
+                       hfs->cache[i].data = NULL;
+               }
+       }
+}
+#endif
+
+#ifdef LIBSTAND
+struct hfile {
+       struct hfs      hfs;
+       ino_t           ino;
+       int64_t         fsize;
+};
+
+static int
+hammer_open(const char *path, struct open_file *f)
+{
+       struct hfile *hf = malloc(sizeof(*hf));
+
+       bzero(hf, sizeof(*hf));
+       f->f_fsdata = hf;
+       hf->hfs.f = f;
+       f->f_offset = 0;
+
+       int rv = hinit(&hf->hfs);
+       if (rv) {
+               f->f_fsdata = NULL;
+               free(hf);
+               return (rv);
+       }
+
+#if DEBUG
+       printf("hammer_open %s %p %ld\n", path, f);
+#endif
+
+       hf->ino = hlookup(&hf->hfs, path);
+       if (hf->ino == -1)
+               goto fail;
+
+       struct stat st;
+       if (hstat(&hf->hfs, hf->ino, &st) == -1)
+               goto fail;
+       hf->fsize = st.st_size;
+
+#if DEBUG
+       printf("        %ld\n", (long)hf->fsize);
+#endif
+
+       return (0);
+
+fail:
+#if DEBUG
+       printf("hammer_open fail\n");
+#endif
+       f->f_fsdata = NULL;
+       hclose(&hf->hfs);
+       free(hf);
+       return (ENOENT);
+}
+
+static int
+hammer_close(struct open_file *f)
+{
+       struct hfile *hf = f->f_fsdata;
+
+       f->f_fsdata = NULL;
+       if (hf) {
+           hclose(&hf->hfs);
+           free(hf);
+       }
+       return (0);
+}
+
+static int
+hammer_read(struct open_file *f, void *buf, size_t len, size_t *resid)
+{
+       struct hfile *hf = f->f_fsdata;
+
+#if DEBUG
+       printf("hammer_read %p %ld %ld\n", f, f->f_offset, len);
+#endif
+
+       if (f->f_offset >= hf->fsize)
+               return (EINVAL);
+
+       size_t maxlen = len;
+       if (f->f_offset + len > hf->fsize)
+               maxlen = hf->fsize - f->f_offset;
+
+       ssize_t rlen = hreadf(&hf->hfs, hf->ino, f->f_offset, maxlen, buf);
+       if (rlen == -1)
+               return (EINVAL);
+
+       f->f_offset += rlen;
+
+       *resid = len - rlen;
+       return (0);
+}
+
+static off_t
+hammer_seek(struct open_file *f, off_t offset, int whence)
+{
+       struct hfile *hf = f->f_fsdata;
+
+       switch (whence) {
+       case SEEK_SET:
+               f->f_offset = offset;
+               break;
+       case SEEK_CUR:
+               f->f_offset += offset;
+               break;
+       case SEEK_END:
+               f->f_offset = hf->fsize - offset;
+               break;
+       default:
+               return (-1);
+       }
+       return (f->f_offset);
+}
+
+static int
+hammer_stat(struct open_file *f, struct stat *st)
+{
+       struct hfile *hf = f->f_fsdata;
+
+       return (hstat(&hf->hfs, hf->ino, st));
+}
+
+static int
+hammer_readdir(struct open_file *f, struct dirent *d)
+{
+       struct hfile *hf = f->f_fsdata;
+
+       int64_t off = f->f_offset;
+       int rv = hreaddir(&hf->hfs, hf->ino, &off, d);
+       f->f_offset = off;
+       return (rv);
+}
+
+// libstand
+struct fs_ops hammer_fsops = {
+       "hammer",
+       hammer_open,
+       hammer_close,
+       hammer_read,
+       null_write,
+       hammer_seek,
+       hammer_stat,
+       hammer_readdir
+};
+#endif // LIBSTAND
+
+#ifdef TESTING
+int
+main(int argc, char **argv)
+{
+       if (argc < 2) {
+               fprintf(stderr, "usage: hammerread <dev>\n");
+               return (1);
+       }
+
+       struct hfs hfs;
+       hfs.fd = open(argv[1], O_RDONLY);
+       if (hfs.fd == -1)
+               err(1, "unable to open %s", argv[1]);
+
+       if (hinit(&hfs) == -1)
+               err(1, "invalid hammerfs");
+
+       for (int i = 2; i < argc; i++) {
+               ino_t ino = hlookup(&hfs, argv[i]);
+               if (ino == (ino_t)-1) {
+                       warn("hlookup %s", argv[i]);
+                       continue;
+               }
+
+               struct stat st;
+               if (hstat(&hfs, ino, &st)) {
+                       warn("hstat %s", argv[i]);
+                       continue;
+               }
+
+               printf("%s %d/%d %o %lld\n",
+                      argv[i],
+                      st.st_uid, st.st_gid,
+                      st.st_mode, st.st_size);
+
+               if (S_ISDIR(st.st_mode)) {
+                       int64_t off = 0;
+                       struct dirent de;
+                       while (hreaddir(&hfs, ino, &off, &de) == 0) {
+                               printf("%s %d %llx\n",
+                                      de.d_name, de.d_type, de.d_ino);
+                       }
+               } else if (S_ISREG(st.st_mode)) {
+                       char *buf = malloc(100000);
+                       int64_t off = 0;
+                       while (off < st.st_size) {
+                               int64_t len = MIN(100000, st.st_size - off);
+                               int64_t rl = hreadf(&hfs, ino, off, len, buf);
+                               fwrite(buf, rl, 1, stdout);
+                               off += rl;
+                       }
+                       free(buf);
+               }
+       }
+
+       return 0;
+}
+#endif
index 0d4cf4e..665f1b4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2012 The DragonFly Project.  All rights reserved.
+ * Copyright (c) 2011-2013 The DragonFly Project.  All rights reserved.
  *
  * This code is derived from software contributed to The DragonFly Project
  * by Matthew Dillon <dillon@dragonflybsd.org>
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+
+#if !defined(BOOT2) && !defined(TESTING)
+#define LIBSTAND        1
+#endif
+
+#ifdef BOOT2
+#include "boot2.h"
+#endif
+
+#ifdef TESTING
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/uuid.h>
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <stddef.h>
 #include <string.h>
 #include <strings.h>
 #include <errno.h>
+#endif
+
+#ifdef LIBSTAND
+#include "stand.h"
+#endif
+
+#include <vfs/hammer2/hammer2_disk.h>
 
-#include <hammer2/hammer2_disk.h>
+uint32_t iscsi_crc32(const void *buf, size_t size);
+uint32_t iscsi_crc32_ext(const void *buf, size_t size, uint32_t ocrc);
 
-struct hammer2 {
-       int                             fd;     /* Device fd */
-       struct hammer2_blockref         sroot;  /* Superroot blockref */
+#define hammer2_icrc32(buf, size)      iscsi_crc32(buf, size)
+
+struct hammer2_fs {
+       struct hammer2_volume_data      vol;
+       hammer2_blockref_t              sroot;
+#if defined(TESTING)
+       int                             fd;
+#elif defined(LIBSTAND)
+       struct open_file                *f;
+#elif defined(BOOT2)
+       /* BOOT2 doesn't use a descriptor */
+#else
+#error "hammer2: unknown library API"
+#endif
 };
 
-struct inode {
-       struct hammer2_inode_data       dat;    /* raw inode data */
+struct hammer2_inode {
+       struct hammer2_inode_data       ino;    /* raw inode data */
        off_t                           doff;   /* disk inode offset */
 };
 
-off_t blockoff(ref)
-       struct hammer2_blockref ref;
+#ifdef BOOT2
+
+static void
+bzero(void *buf, size_t size)
 {
+       for (size_t i = 0; i < size; i++)
+               ((char *)buf)[i] = 0;
+}
 
+static void
+bcopy(void *src, void *dst, size_t size)
+{
+       memcpy(dst, src, size);
 }
 
-hinit(hfs)
-       struct hammer2 *hfs;
+#if 0
+static size_t
+strlen(const char *s)
 {
-       struct hammer2_volume_data volhdr;
-       ssize_t rc;
-       hammer2_crc_t crc0;
+       size_t l = 0;
+       for (; *s != 0; s++)
+               l++;
+       return (l);
+}
+#endif
 
-       rc = pread(hfs->fd, &volhdr, HAMMER2_VOLUME_SIZE, 0);
-       if (volhdr.magic == HAMMER2_VOLUME_ID_HBO) {
-               printf("Valid HAMMER2 filesystem\n");
-       } else {
-               return (-1);
+static int
+memcmp(const void *a, const void *b, size_t len)
+{
+       for (size_t p = 0; p < len; p++) {
+               int r = ((const char *)a)[p] - ((const char *)b)[p];
+               if (r != 0)
+                       return (r);
        }
 
-       hfs->sroot = volhdr.sroot_blockref;
        return (0);
 }
 
-shread(hfs, ino, buf, off, len)
-       struct hammer2 *hfs;
-       struct inode *ino;
-       char *buf;
-       off_t off;
-       size_t len;
+#endif
+
+static
+off_t
+blockoff(hammer2_blockref_t *bref)
+{
+       return(bref->data_off & ~HAMMER2_OFF_MASK_RADIX);
+}
+
+static
+size_t
+blocksize(hammer2_blockref_t *bref)
+{
+       return(1 << (int)(bref->data_off & HAMMER2_OFF_MASK_RADIX));
+}
+
+static
+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;
+
+       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;
+
        /*
-        * Read [off, off+len) from inode ino rather than from disk
-        * offsets; correctly decodes blockrefs/indirs/...
+        * l16 - crc of entire filename
+        *
+        * This crc reduces degenerate hash collision conditions
         */
+       crcx = hammer2_icrc32(aname, len);
+       crcx = crcx ^ (crcx << 16);
+       key |= crcx & 0xFFFF0000U;
+
+       /*
+        * Set bit 15.  This allows readdir to strip bit 63 so a positive
+        * 64-bit cookie/offset can always be returned, and still guarantee
+        * that the values 0x0000-0x7FFF are available for artificial entries.
+        * ('.' and '..').
+        */
+       key |= 0x8000U;
+
+       return (key);
 }
 
-struct inode *hlookup1(hfs, ino, name)
-       struct hammer2 *hfs;
-       struct inode *ino;
-       char *name;
+/*
+ * Low level read
+ */
+static
+int
+h2read(struct hammer2_fs *hfs, void *buf, size_t nbytes, off_t off)
 {
-       static struct inode filino;
-       off_t off;
+#if defined(LIBSTAND)
+       size_t rlen;
+#endif
+       int rc;
+
+#if defined(TESTING)
+       rc = pread(hfs->fd, &hfs->vol, nbytes, off);
+       if (rc == (int)nbytes)
+               rc = 0;
+       else
+               rc = -1;
+#elif defined(LIBSTAND)
+       rc = hfs->f->f_dev->dv_strategy(hfs->f->f_devdata, F_READ,
+                                       off >> DEV_BSHIFT, nbytes,
+                                       buf, &rlen);
+       if (rc || rlen != nbytes)
+               rc = -1;
+#elif defined(BOOT2)
+       rc = dskread(buf, off >> DEV_BSHIFT, nbytes >> DEV_BSHIFT);
+       if (rc)
+               rc = -1;
+#else
+#error "hammer2: unknown library API"
+#endif
+       return rc;
+}
+
+/*
+ * Common code
+ *
+ * Initialize for HAMMER2 filesystem access given a hammer2_fs with
+ * its device file descriptor initialized.
+ */
+
+/*
+ * Lookup within the block specified by (*base), loading the block from disk
+ * if necessary.  Locate the first key within the requested range and
+ * recursively run through indirect blocks as needed.  The caller may loop
+ * by setting key_beg to *key_ret.
+ *
+ * Returns 0 if nothing could be found and the key range has been exhausted.
+ * returns -1 if a disk error occured.  Otherwise returns the size of the
+ * data block and returns the data block in *pptr and bref in *bref_ret.
+ *
+ * NOTE! When reading file data, the returned bref's key will be the nearest
+ *      data block we looked up.  The file read procedure must handle any
+ *       zero-fill or skip.  However, we will truncate the return value to
+ *      the file size.
+ */
+static int
+h2lookup(struct hammer2_fs *hfs, hammer2_blockref_t *base,
+        hammer2_key_t key_beg, hammer2_key_t key_end,
+        hammer2_blockref_t *bref_ret, void **pptr)
+{
+       hammer2_blockref_t *bref;
+       hammer2_blockref_t best;
+       hammer2_key_t scan_beg;
+       hammer2_key_t scan_end;
+       int i;
        int rc;
+       int count;
+       int dev_boff;
+       int dev_bsize;
+       static hammer2_media_data_t media;
+       static hammer2_blockref_t saved_base;
 
-       bzero(&filino, sizeof(struct inode));
+       if (base == NULL) {
+               saved_base.data_off = (hammer2_off_t)-1;
+               return(0);
+       }
+       if (base->data_off == (hammer2_off_t)-1)
+               return(-1);
 
-       for (off = 0;
-            off < ino->dat.size;
-            off += sizeof(struct hammer2_inode_data))
-       {
-               rc = shread(hfs, ino, &filino.dat, off,
-                           sizeof(struct hammer2_inode_data));
-               if (rc != sizeof(struct hammer2_inode_data))
+       /*
+        * Calculate the number of blockrefs to scan
+        */
+       switch(base->type) {
+       case HAMMER2_BREF_TYPE_VOLUME:
+               count = HAMMER2_SET_COUNT;
+               break;
+       case HAMMER2_BREF_TYPE_INODE:
+               count = HAMMER2_SET_COUNT;
+               break;
+       case HAMMER2_BREF_TYPE_INDIRECT:
+               count = blocksize(base) / sizeof(hammer2_blockref_t);
+               break;
+       }
+
+       /*
+        * Find the best candidate (the lowest blockref within the specified
+        * range).  The array can be fully set associative so make no ordering
+        * assumptions.
+        */
+again:
+       best.key = HAMMER2_MAX_KEY;
+       best.type = 0;
+
+       for (i = 0; i < count; ++i) {
+               /*
+                * [re]load when returning from our recursion
+                */
+               if (base->type != HAMMER2_BREF_TYPE_VOLUME &&
+                   base->data_off != saved_base.data_off) {
+                       if (h2read(hfs, &media,
+                                  blocksize(base), blockoff(base))) {
+                               return(-1);
+                       }
+                       saved_base = *base;
+               }
+
+               /*
+                * Special case embedded file data
+                */
+               if (base->type == HAMMER2_BREF_TYPE_INODE) {
+                       if (media.ipdata.op_flags & HAMMER2_OPFLAG_DIRECTDATA) {
+                               *pptr = media.ipdata.u.data;
+                               bref_ret->type = HAMMER2_BREF_TYPE_DATA;
+                               bref_ret->key = 0;
+                               return HAMMER2_EMBEDDED_BYTES;
+                       }
+               }
+
+               /*
+                * Calculate the bref in our scan.
+                */
+               switch(base->type) {
+               case HAMMER2_BREF_TYPE_VOLUME:
+                       bref = &hfs->vol.sroot_blockset.blockref[i];
+                       break;
+               case HAMMER2_BREF_TYPE_INODE:
+                       bref = &media.ipdata.u.blockset.blockref[i];
+                       break;
+               case HAMMER2_BREF_TYPE_INDIRECT:
+                       bref = &media.npdata[i];
+                       break;
+               }
+               if (bref->type == 0)
                        continue;
-               if (strcmp(name, &filino.dat.filename) == 0)
-                       return (&filino);
+               if (bref->key > best.key)
+                       continue;
+               scan_beg = bref->key;
+               scan_end = scan_beg + ((hammer2_key_t)1 << bref->keybits) - 1;
+               if (scan_end >= key_beg && scan_beg <= key_end) {
+                       best = *bref;
+               }
        }
 
-       return (NULL);
+       /*
+        * Figure out what to do with the results.
+        */
+       switch(best.type) {
+       case 0:
+               /*
+                * Return 0
+                */
+               rc = 0;
+               break;
+       case HAMMER2_BREF_TYPE_INDIRECT:
+               /*
+                * Matched an indirect block.  If the block turns out to
+                * contain nothing we continue the iteration, otherwise
+                * we return the data from the recursion.
+                *
+                * Be sure to handle the overflow case when recalculating
+                * key_beg.
+                */
+               rc = h2lookup(hfs, &best, key_beg, key_end, bref_ret, pptr);
+               if (rc == 0) {
+                       key_beg = best.key +
+                                 ((hammer2_key_t)1 << best.keybits);
+                       if (key_beg > best.key && key_beg <= key_end)
+                               goto again;
+               }
+               break;
+       case HAMMER2_BREF_TYPE_INODE:
+       case HAMMER2_BREF_TYPE_DATA:
+               /*
+                * Terminal match.  Leaf elements might not be data-aligned.
+                */
+               dev_bsize = blocksize(&best);
+               if (dev_bsize < HAMMER2_LBUFSIZE)
+                       dev_bsize = HAMMER2_LBUFSIZE;
+               dev_boff = blockoff(&best) -
+                          (blockoff(&best) & ~HAMMER2_LBUFMASK64);
+               if (h2read(hfs, &media, dev_bsize, blockoff(&best) - dev_boff))
+                       return(-1);
+               saved_base.data_off = (hammer2_off_t)-1;
+               *bref_ret = best;
+               *pptr = media.buf + dev_boff;
+               rc = blocksize(&best);
+               break;
+       }
+       return(rc);
 }
 
-struct inode *hlookup(hfs, name)
-       struct hammer2 *hfs;
-       char *name;
+static
+void
+h2resolve(struct hammer2_fs *hfs, const char *path,
+         hammer2_blockref_t *bref, hammer2_inode_data_t **inop)
 {
-       /* Name is of form /SUPERROOT/a/b/c/file */
+       hammer2_blockref_t bres;
+       hammer2_inode_data_t *ino;
+       hammer2_key_t key;
+       ssize_t bytes;
+       size_t len;
+
+       /*
+        * Start point (superroot)
+        */
+       *bref = hfs->sroot;
+       if (inop)
+               *inop = NULL;
+
+       /*
+        * Iterate path elements
+        */
+       while (*path) {
+               while (*path == '/')
+                       ++path;
+               if (*path == 0) /* terminal */
+                       break;
 
+               /*
+                * Calculate path element and look for it in the directory
+                */
+               for (len = 0; path[len]; ++len) {
+                       if (path[len] == '/')
+                               break;
+               }
+               key = hammer2_dirhash(path, len);
+               for (;;) {
+                       bytes = h2lookup(hfs, bref,
+                                        key, key | 0xFFFFU,
+                                        &bres, (void **)&ino);
+                       if (bytes == 0)
+                               break;
+                       if (len == ino->name_len &&
+                           memcmp(path, ino->filename, len) == 0) {
+                               if (inop)
+                                       *inop = ino;
+                               break;
+                       }
+                       key = bres.key + 1;
+               }
+
+               /*
+                * Lookup failure
+                */
+               if (bytes == 0) {
+                       bref->data_off = (hammer2_off_t)-1;
+                       break;
+               }
+
+               /*
+                * Check path continuance, inode must be a directory or
+                * we fail.
+                */
+               path += len;
+               if (*path && ino->type != HAMMER2_OBJTYPE_DIRECTORY) {
+                       bref->data_off = (hammer2_off_t)-1;
+                       break;
+               }
+               *bref = bres;
+       }
 }
 
-void hstat(hfs, ino, sb)
-       struct hammer2 *hfs;
-       struct inode *ino;
-       struct stat *sb;
+static
+ssize_t
+h2readfile(struct hammer2_fs *hfs, hammer2_blockref_t *bref,
+          off_t off, off_t filesize, void *buf, size_t len)
 {
+       hammer2_blockref_t bres;
+       ssize_t total;
+       ssize_t bytes;
+       ssize_t zfill;
+       char *data;
+
+       /*
+        * EOF edge cases
+        */
+       if (off >= filesize)
+               return (0);
+       if (off + len > filesize)
+               len = filesize - off;
+
+       /*
+        * Loop until done 
+        */
+       total = 0;
+       while (len) {
+               /*
+                * Find closest bres >= requested offset.
+                */
+               bytes = h2lookup(hfs, bref, off, off + len - 1,
+                                &bres, (void **)&data);
+
+               if (bytes < 0) {
+                       if (total == 0)
+                               total = -1;
+                       break;
+               }
+
+               /*
+                * Load the data into the buffer.  First handle a degenerate
+                * zero-fill case.
+                */
+               if (bytes == 0) {
+                       bzero(buf, len);
+                       total += len;
+                       break;
+               }
+
+               /*
+                * Returned record overlaps to the left of the requested
+                * position.  It must overlap in this case or h2lookup()
+                * would have returned something else.
+                */
+               if (bres.key < off) {
+                       data += off - bres.key;
+                       bytes -= off - bres.key;
+               }
+
+               /*
+                * Returned record overlaps to the right of the requested
+                * position, handle zero-fill.  Again h2lookup() only returns
+                * this case if there is an actual overlap.
+                */
+               if (bres.key > off) {
+                       zfill = (ssize_t)(bres.key - off);
+                       bzero(buf, zfill);
+                       len -= zfill;
+                       off += zfill;
+                       total += zfill;
+                       buf = (char *)buf + zfill;
+               }
 
+               /*
+                * Trim returned request before copying.
+                */
+               if (bytes > len)
+                       bytes = len;
+               bcopy(data, buf, bytes);
+               len -= bytes;
+               off += bytes;
+               total += bytes;
+               buf = (char *)buf + bytes;
+       }
+       return (total);
 }
 
-main(argc, argv)
-       int argc;
-       char *argv[];
+static
+int
+h2init(struct hammer2_fs *hfs)
 {
-       struct hammer2 hammer2;
-       struct inode *ino;
-       struct stat sb;
+#if 0
+       uint32_t crc0;
+#endif
+       hammer2_tid_t best_tid = 0;
+       void *data;
+       off_t off;
+       int best;
        int i;
 
-       if (argc < 2) {
-               fprintf(stderr, "usage: hammer2 <dev>\n");
-               exit(1);
+       /*
+        * Find the best volume header
+        */
+       best = -1;
+       for (i = 0; i < HAMMER2_NUM_VOLHDRS; ++i) {
+               off = i * HAMMER2_ZONE_BYTES64;
+               if (i)
+                       no_io_error = 1;
+               if (h2read(hfs, &hfs->vol, sizeof(hfs->vol), off))
+                       continue;
+               if (hfs->vol.magic != HAMMER2_VOLUME_ID_HBO)
+                       continue;
+               if (best < 0 || best_tid < hfs->vol.mirror_tid) {
+                       best = i;
+                       best_tid = hfs->vol.mirror_tid;
+               }
+       }
+       no_io_error = 0;
+       if (best < 0)
+               return(-1);
+
+       /*
+        * Reload the best volume header and set up the blockref.
+        */
+       off = best * HAMMER2_ZONE_BYTES64;
+       if (h2read(hfs, &hfs->vol, sizeof(hfs->vol), off))
+               return(-1);
+       hfs->sroot.type = HAMMER2_BREF_TYPE_VOLUME;
+       hfs->sroot.data_off = off;
+       h2lookup(hfs, NULL, 0, 0, NULL, NULL);
+       h2lookup(hfs, &hfs->sroot, 0, 0, &hfs->sroot, &data);
+
+       /*
+        * Clear cache
+        */
+       h2lookup(hfs, NULL, 0, 0, NULL, NULL);
+
+       return (0);
+}
+
+/************************************************************************
+ *                             BOOT2 SUPPORT                           *
+ ************************************************************************
+ *
+ */
+#ifdef BOOT2
+
+static struct hammer2_fs hfs;
+
+static int
+boot2_hammer2_init(void)
+{
+       if (h2init(&hfs))
+               return(-1);
+       return(0);
+}
+
+static boot2_ino_t
+boot2_hammer2_lookup(const char *path)
+{
+       hammer2_blockref_t bref;
+
+       h2resolve(&hfs, path, &bref, NULL);
+       return ((boot2_ino_t)bref.data_off);
+}
+
+static ssize_t
+boot2_hammer2_read(boot2_ino_t ino, void *buf, size_t len)
+{
+       hammer2_blockref_t bref;
+       ssize_t total;
+
+       bzero(&bref, sizeof(bref));
+       bref.type = HAMMER2_BREF_TYPE_INODE;
+       bref.data_off = ino;
+
+       total = h2readfile(&hfs, &bref, fs_off, 0x7FFFFFFF, buf, len);
+       if (total > 0)
+               fs_off += total;
+       return total;
+}
+
+const struct boot2_fsapi boot2_hammer2_api = {
+        .fsinit = boot2_hammer2_init,
+        .fslookup = boot2_hammer2_lookup,
+        .fsread = boot2_hammer2_read
+};
+
+#endif
+
+/************************************************************************
+ *                             BOOT2 SUPPORT                           *
+ ************************************************************************
+ *
+ */
+#ifdef LIBSTAND
+
+struct hfile {
+       struct hammer2_fs hfs;
+       hammer2_blockref_t bref;
+       int64_t         fsize;
+       uint32_t        mode;
+       uint8_t         type;
+};
+
+static
+int
+hammer2_get_dtype(uint8_t type)
+{
+       switch(type) {
+       case HAMMER2_OBJTYPE_DIRECTORY:
+               return(DT_DIR);
+       case HAMMER2_OBJTYPE_REGFILE:
+               return(DT_REG);
+       case HAMMER2_OBJTYPE_FIFO:
+               return(DT_FIFO);
+       case HAMMER2_OBJTYPE_CDEV:
+               return(DT_CHR);
+       case HAMMER2_OBJTYPE_BDEV:
+               return(DT_BLK);
+       case HAMMER2_OBJTYPE_SOFTLINK:
+               return(DT_LNK);
+       case HAMMER2_OBJTYPE_HARDLINK:
+               return(DT_UNKNOWN);
+       case HAMMER2_OBJTYPE_SOCKET:
+               return(DT_SOCK);
+       default:
+               return(DT_UNKNOWN);
        }
+}
 
-       hammer2.fd = open(argv[1], O_RDONLY);
-       if (hammer2.fd < 0) {
-               fprintf(stderr, "unable to open %s\n", argv[1]);
-               exit(1);
+static
+mode_t
+hammer2_get_mode(uint8_t type)
+{
+       switch(type) {
+       case HAMMER2_OBJTYPE_DIRECTORY:
+               return(S_IFDIR);
+       case HAMMER2_OBJTYPE_REGFILE:
+               return(S_IFREG);
+       case HAMMER2_OBJTYPE_FIFO:
+               return(S_IFIFO);
+       case HAMMER2_OBJTYPE_CDEV:
+               return(S_IFCHR);
+       case HAMMER2_OBJTYPE_BDEV:
+               return(S_IFBLK);
+       case HAMMER2_OBJTYPE_SOFTLINK:
+               return(S_IFLNK);
+       case HAMMER2_OBJTYPE_HARDLINK:
+               return(0);
+       case HAMMER2_OBJTYPE_SOCKET:
+               return(S_IFSOCK);
+       default:
+               return(0);
        }
+}
+
+static int
+hammer2_open(const char *path, struct open_file *f)
+{
+       struct hfile *hf = malloc(sizeof(*hf));
+       hammer2_inode_data_t *ipdata;
+
+       bzero(hf, sizeof(*hf));
+       f->f_offset = 0;
+       f->f_fsdata = hf;
+       hf->hfs.f = f;
 
-       if (hinit(&hammer2)) {
-               fprintf(stderr, "invalid fs\n");
-               close(hammer2.fd);
-               exit(1);
+       if (h2init(&hf->hfs)) {
+               f->f_fsdata = NULL;
+               free(hf);
+               errno = ENOENT;
+               return(-1);
        }
+       h2resolve(&hf->hfs, path, &hf->bref, &ipdata);
+       if (hf->bref.data_off == (hammer2_off_t)-1 ||
+           (hf->bref.type != HAMMER2_BREF_TYPE_INODE &&
+           hf->bref.type != HAMMER2_BREF_TYPE_VOLUME)) {
+               f->f_fsdata = NULL;
+               free(hf);
+               errno = ENOENT;
+               return(-1);
+       }
+       if (ipdata) {
+               hf->fsize = ipdata->size;
+               hf->type = ipdata->type;
+               hf->mode = ipdata->mode | hammer2_get_mode(ipdata->type);
+       } else {
+               hf->fsize = 0;
+               hf->type = HAMMER2_OBJTYPE_DIRECTORY;
+               hf->mode = 0755 | S_IFDIR;
+       }
+       return(0);
+}
 
-       for (i = 2; i < argc; i++) {
-               ino = hlookup(&hammer2, argv[i]);
-               if (ino == NULL) {
-                       fprintf(stderr, "hlookup %s\n", argv[i]);
-                       continue;
-               }
-               hstat(&hammer2, ino, &sb);
+static int
+hammer2_close(struct open_file *f)
+{
+       struct hfile *hf = f->f_fsdata;
+
+       f->f_fsdata = NULL;
+       if (hf)
+               free(hf);
+       return (0);
+}
+
+static int
+hammer2_read(struct open_file *f, void *buf, size_t len, size_t *resid)
+{
+       struct hfile *hf = f->f_fsdata;
+       ssize_t total;
+       int rc = 0;
+
+       total = h2readfile(&hf->hfs, &hf->bref,
+                          f->f_offset, hf->fsize, buf, len);
+       if (total < 0) {
+               rc = EIO;
+               total = 0;
+       } else {
+               f->f_offset += total;
+               rc = 0;
+       }
+       *resid = len - total;
+       return rc;
+}
 
-               printf("%s %lld", argv[i], sb.st_size);
+static off_t
+hammer2_seek(struct open_file *f, off_t offset, int whence)
+{
+       struct hfile *hf = f->f_fsdata;
 
+       switch (whence) {
+       case SEEK_SET:
+               f->f_offset = offset;
+               break;
+       case SEEK_CUR:
+               f->f_offset += offset;
+               break;
+       case SEEK_END:
+               f->f_offset = hf->fsize - offset;
+               break;
+       default:
+               return (-1);
        }
+       return (f->f_offset);
 }
+
+static int
+hammer2_stat(struct open_file *f, struct stat *st)
+{
+       struct hfile *hf = f->f_fsdata;
+
+       st->st_mode = hf->mode;
+       st->st_uid = 0;
+       st->st_gid = 0;
+       st->st_size = hf->fsize;
+
+       return (0);
+}
+
+static int
+hammer2_readdir(struct open_file *f, struct dirent *den)
+{
+       struct hfile *hf = f->f_fsdata;
+       hammer2_blockref_t bres;
+       hammer2_inode_data_t *ipdata;
+       int bytes;
+
+       for (;;) {
+               bytes = h2lookup(&hf->hfs, &hf->bref,
+                                f->f_offset | HAMMER2_DIRHASH_VISIBLE, 
+                                HAMMER2_MAX_KEY,
+                                &bres, (void **)&ipdata);
+               if (bytes <= 0)
+                       break;
+               den->d_namlen = ipdata->name_len;
+               den->d_type = hammer2_get_dtype(ipdata->type);
+               den->d_ino = ipdata->inum;
+               bcopy(ipdata->filename, den->d_name, den->d_namlen);
+               den->d_name[den->d_namlen] = 0;
+
+               f->f_offset = bres.key + 1;
+
+               return(0);
+       }
+       return ENOENT;
+}
+
+struct fs_ops hammer_fsops = {
+       "hammer2",
+       hammer2_open,
+       hammer2_close,
+       hammer2_read,
+       null_write,
+       hammer2_seek,
+       hammer2_stat,
+       hammer2_readdir
+};
+
+#endif
index d7d67bb..44685f6 100644 (file)
@@ -233,6 +233,7 @@ kvprintf(char const *fmt, void (*func)(int, void *), void *arg, int radix,
                qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
                sign = 0; dot = 0; dwidth = 0; upper = 0;
                cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0;
+
 reswitch:      switch (ch = (u_char)*fmt++) {
                case '.':
                        dot = 1;
index 337b0b5..4b9090e 100644 (file)
@@ -65,6 +65,8 @@
 #include <sys/param.h>
 #include "stand.h"
 
+int no_io_error;
+
 ssize_t
 read(int fd, void *dest, size_t bcount)
 {
index 150c927..c5aee51 100644 (file)
@@ -152,6 +152,7 @@ struct devsw {
 extern struct devsw netdev;
 
 extern int errno;
+extern int no_io_error;
 
 struct open_file {
     int                        f_flags;        /* see F_* below */
index 9eeae7d..6ea0b07 100644 (file)
@@ -522,8 +522,14 @@ format_hammer2(int fd, hammer2_off_t total_space, hammer2_off_t free_space)
 
        /*
         * Compression mode and supported copyids.
+        *
+        * Do not allow compression when creating a "boot" label
+        * (pfs-create also does the same if the pfs is named "boot")
         */
-       rawip->comp_algo = HAMMER2_COMP_NEWFS_DEFAULT;
+       if (strcmp(Label, "boot") == 0)
+               rawip->comp_algo = HAMMER2_COMP_AUTOZERO;
+       else
+               rawip->comp_algo = HAMMER2_COMP_NEWFS_DEFAULT;
 
        rawip->pfs_clid = Hammer2_RPFSId;
        rawip->pfs_type = HAMMER2_PFSTYPE_MASTER;
index 783c5e4..a800d04 100644 (file)
@@ -14,7 +14,11 @@ SUBDIR+=             ofw
 .endif
 
 # Pick the machine-dependant subdir based on the target architecture.
+.if ${REALLY_X86_64} == "true"
+SUBDIR+=               pc32
+.else
 SUBDIR+=               ${MACHINE_PLATFORM}
+.endif
 
 # Build EFI executable on ia64
 .if ${MACHINE_ARCH} == "ia64"
index 262869b..89ab80e 100644 (file)
@@ -33,7 +33,7 @@
  */
 /*
  * boot2 encapsulated ABI.  The boot2 standalone code provides these functions
- * to the boot2 add-on modules (ufsread.c and hammerread.c).
+ * to the boot2 add-on modules (ufsread.c and hammer2.c).
  */
 
 #ifndef _BOOT_COMMON_BOOT2_H_
@@ -53,7 +53,7 @@
  * We only need a 32 bit ino_t for UFS-only boot code.  We have to squeeze
  * space usage, else we'd just use 64 bits across the board.
  */
-#if defined(HAMMERFS)
+#if defined(HAMMERFS) || defined(HAMMER2FS)
 typedef uint64_t boot2_ino_t;
 #else
 typedef uint32_t boot2_ino_t;
@@ -75,6 +75,7 @@ struct boot2_dmadat {
 };
 
 extern uint32_t fs_off;
+extern int     no_io_error;
 extern int     ls;
 extern struct boot2_dmadat *boot2_dmadat;
 
@@ -90,5 +91,8 @@ extern const struct boot2_fsapi boot2_ufs_api;
 #ifdef HAMMERFS
 extern const struct boot2_fsapi boot2_hammer_api;
 #endif
+#ifdef HAMMER2FS
+extern const struct boot2_fsapi boot2_hammer2_api;
+#endif
 
 #endif
index 724989f..935371a 100644 (file)
 
                        "hammer:da8se1a"
 
-               One file system HAMMER multi volume examples:
+               One file system HAMMER2 redundant copies examples:
 
-                       "hammer:da8s1a:da9s1a"
+                       "hammer2:da8s1a:da9s1a"
 
                Several file systems, boot list, example:
 
-                       "ufs:da0s1a;hammer:ad1s1d"
+                       "ufs:da0s1a;hammer2:ad1s1d"
 
                Each file system in the list will be tried in the order
                specified until the mount succeeds.  If all fail, the
index 60c09d6..83d545c 100644 (file)
@@ -749,12 +749,12 @@ One file system example:
 .Dl hammer:da8s1a
 .Pp
 One file system
-.Nm HAMMER
+.Nm HAMMER2
 multi volume example:
-.Dl hammer:da8s1a:da9s1a
+.Dl hammer2:da8s1a:da9s1a
 .Pp
 Several file systems, boot list, example:
-.Dl ufs:da0s1a;hammer:ad1s1d
+.Dl ufs:da0s1a;hammer2:ad1s1d
 .Pp
 Each file system in the list will be tried in the order specified
 until the mount succeeds.
index 9e4e47a..6df6ac3 100644 (file)
@@ -14,6 +14,7 @@ NXLDFLAGS=
 .PATH: ${.CURDIR}/..
 .PATH: ${.CURDIR}/../../common
 .PATH: ${.CURDIR}/../../../../lib/libstand
+.PATH: ${.CURDIR}/../../../libkern
 
 # A value of 0x80 enables LBA support.
 B1FLAGS=       0x80
@@ -90,8 +91,8 @@ _ADDCFLAGS$s:= -DNSECT=${NSECT$s}
 _ts=   $s
 .if ${_ts} == "_64"
 _ADDCFLAGS$s+= -DDISKLABEL64
-_ADDCFLAGS$s+= -DHAMMERFS -DUFS
-_ADDOBJS$s+= hammerread$s.o ufsread$s.o
+_ADDCFLAGS$s+= -DHAMMER2FS -DUFS
+_ADDOBJS$s+= hammer2$s.o ufsread$s.o icrc32$s.o
 .else
 _ADDCFLAGS$s+= -DUFS -DUFS1_ONLY
 _ADDOBJS$s+= ufsread$s.o
@@ -109,7 +110,9 @@ boot1$s.o: boot1.S
        ${CC} ${CFLAGS} ${_ADDCFLAGS$s} -DFLAGS=${B1FLAGS} \
                ${.ALLSRC} -o ${.TARGET} -c
 
-boot2$s.s: boot2.c boot2$s.h ${.CURDIR}/../../common/ufsread.c ${.CURDIR}/../../../../lib/libstand/hammerread.c
+#${.CURDIR}/../../common/ufsread.c ${.CURDIR}/../../../../lib/libstand/hammer2.c
+
+boot2$s.s: boot2.c boot2$s.h ufsread.c hammer2.c icrc32.c
        ${CC} ${CFLAGS} ${_ADDCFLAGS$s} -S -o boot2$s.s.tmp ${.CURDIR}/boot2.c
        sed -e '/align/d' -e '/nop/d' < ${.TARGET}.tmp > ${.TARGET}
        rm -f ${.TARGET}.tmp
@@ -146,12 +149,15 @@ CLEANFILES+=      boot1$s boot1$s.out boot1$s.o \
                boot2$s.ld boot2$s.out boot2$s.o boot2$s.h boot2$s.s \
                ${_ADDOBJS$s}
 
-hammerread$s.o: hammerread.c
+hammer2$s.o: hammer2.c
        ${CC} ${CFLAGS} ${_ADDCFLAGS$s} ${.ALLSRC} -o ${.TARGET} -c
 
 ufsread$s.o: ufsread.c
        ${CC} ${CFLAGS} ${_ADDCFLAGS$s} ${.ALLSRC} -o ${.TARGET} -c
 
+icrc32$s.o: icrc32.c
+       ${CC} ${CFLAGS} ${_ADDCFLAGS$s} ${.ALLSRC} -o ${.TARGET} -c
+
 .endfor
 
 sio.o: sio.S
index 5d0df04..1ea9632 100644 (file)
@@ -168,6 +168,7 @@ static struct bootinfo bootinfo;
  * NOTE: boot2_dmadat is extended by per-filesystem APIs
  */
 uint32_t fs_off;
+int    no_io_error;
 int    ls;
 struct boot2_dmadat *boot2_dmadat;
 
@@ -200,7 +201,7 @@ strcmp(const char *s1, const char *s2)
     return ((int)((unsigned char)*s1 - (unsigned char)*s2));
 }
 
-#if defined(UFS) && defined(HAMMERFS)
+#if defined(UFS) && defined(HAMMER2FS)
 
 const struct boot2_fsapi *fsapi;
 
@@ -208,9 +209,9 @@ const struct boot2_fsapi *fsapi;
 
 #define fsapi  (&boot2_ufs_api)
 
-#elif defined(HAMMERFS)
+#elif defined(HAMMER2FS)
 
-#define fsapi  (&boot2_hammer_api)
+#define fsapi  (&boot2_hammer2_api)
 
 #endif
 
@@ -602,11 +603,11 @@ dskprobe(void)
     /*
      * Probe filesystem
      */
-#if defined(UFS) && defined(HAMMERFS)
+#if defined(UFS) && defined(HAMMER2FS)
     if (boot2_ufs_api.fsinit() == 0) {
        fsapi = &boot2_ufs_api;
-    } else if (boot2_hammer_api.fsinit() == 0) {
-       fsapi = &boot2_hammer_api;
+    } else if (boot2_hammer2_api.fsinit() == 0) {
+       fsapi = &boot2_hammer2_api;
     } else {
        printf("fs probe failed\n");
        fsapi = &boot2_ufs_api;
@@ -639,6 +640,9 @@ printf(const char *fmt,...)
     static char buf[10];
     char *s;
     unsigned u;
+#ifdef HAMMER2FS
+    uint64_t q;
+#endif
     int c;
 
     va_start(ap, fmt);
@@ -653,6 +657,33 @@ printf(const char *fmt,...)
                for (s = va_arg(ap, char *); *s; s++)
                    putchar(*s);
                continue;
+#ifdef HAMMER2FS
+           case 'q':
+               ++fmt;  /* skip the 'x' */
+               q = va_arg(ap, uint64_t);
+               s = buf;
+               do {
+                   if ((q & 15) < 10)
+                       *s++ = '0' + (q & 15);
+                   else
+                       *s++ = 'a' + (q & 15) - 10;
+               } while (q >>= 4);
+               while (--s >= buf)
+                   putchar(*s);
+               continue;
+           case 'x':
+               u = va_arg(ap, unsigned);
+               s = buf;
+               do {
+                   if ((u & 15) < 10)
+                       *s++ = '0' + (u & 15);
+                   else
+                       *s++ = 'a' + (u & 15) - 10;
+               } while (u >>= 4);
+               while (--s >= buf)
+                   putchar(*s);
+               continue;
+#endif
            case 'u':
                u = va_arg(ap, unsigned);
                s = buf;
@@ -701,7 +732,7 @@ drvread(void *buf, unsigned lba, unsigned nblk)
     v86.edx = nblk << 8 | dsk.drive;
     v86int();
     v86.ctl = V86_FLAGS;
-    if (V86_CY(v86.efl)) {
+    if (V86_CY(v86.efl) && !no_io_error) {
        printf("error %u lba %u\n", v86.eax >> 8 & 0xff, lba);
        return -1;
     }
index 177be53..2ea4aab 100644 (file)
@@ -382,6 +382,7 @@ print_partition(u_int8_t fstype, unsigned long long offset,
        if ((fstype == FS_SWAP) ||
            (fstype == FS_VINUM) ||
            (fstype == FS_HAMMER) ||
+           (fstype == FS_HAMMER2) ||
            (fstype == FS_BSDFFS) ||
            (fstype == FS_ZFS) ||
            (fstype == FS_JFS2) ||
@@ -398,6 +399,7 @@ print_partition(u_int8_t fstype, unsigned long long offset,
                            (fstype == FS_SWAP) ? "swap" :
                            (fstype == FS_VINUM) ? "vinum" :
                            (fstype == FS_HAMMER) ? "HAMMER" :
+                           (fstype == FS_HAMMER2) ? "HAMMER2" :
                            (fstype == FS_JFS2) ? "JFS2" :
                            (fstype == FS_ZFS) ? "ZFS" :
                            (fstype == FS_BSDFFS) ? "FFS" :
@@ -414,6 +416,7 @@ print_partition(u_int8_t fstype, unsigned long long offset,
                            (fstype == FS_SWAP) ? "swap" :
                            (fstype == FS_VINUM) ? "vinum" :
                            (fstype == FS_HAMMER) ? "HAMMER" :
+                           (fstype == FS_HAMMER2) ? "HAMMER2" :
                            (fstype == FS_JFS2) ? "JFS2" :
                            (fstype == FS_ZFS) ? "ZFS" :
                            (fstype == FS_BSDFFS) ? "FFS" :
index 3c2fd40..2a0d155 100644 (file)
@@ -3,7 +3,7 @@
 # common/do_dloader.c has put us in "/boot" if it exists,
 # else we are in "/".  It depends on whether the system
 # is configured with a single boot+root or a separate boot
-# with a HAMMER root.
+# with a HAMMER or HAMMER2 root.
 
 include defaults/loader.conf
 include defaults/dloader.menu
index 49fe816..855bca0 100644 (file)
@@ -559,6 +559,7 @@ hammer2_inode_create(hammer2_trans_t *trans, hammer2_inode_t *dip,
        uuid_t dip_uid;
        uuid_t dip_gid;
        uint32_t dip_mode;
+       uint8_t dip_algo;
 
        lhc = hammer2_dirhash(name, name_len);
        *errorp = 0;
@@ -576,6 +577,7 @@ retry:
        dip_uid = dipdata->uid;
        dip_gid = dipdata->gid;
        dip_mode = dipdata->mode;
+       dip_algo = dipdata->comp_algo;
 
        error = 0;
        while (error == 0) {
@@ -643,7 +645,7 @@ retry:
        
        /* Inherit parent's inode compression mode. */
        nip->comp_heuristic = 0;
-       nipdata->comp_algo = dipdata->comp_algo;
+       nipdata->comp_algo = dip_algo;
        nipdata->version = HAMMER2_INODE_VERSION_ONE;
        hammer2_update_time(&nipdata->ctime);
        nipdata->mtime = nipdata->ctime;
index dbfe896..9cdd3bf 100644 (file)
@@ -508,6 +508,13 @@ hammer2_ioctl_pfs_create(hammer2_inode_t *ip, void *data)
                nipdata->pfs_type = pfs->pfs_type;
                nipdata->pfs_clid = pfs->pfs_clid;
                nipdata->pfs_fsid = pfs->pfs_fsid;
+
+               /*
+                * Do not allow compression on PFS's with the special name
+                * "boot", the boot loader can't decompress (yet).
+                */
+               if (strcmp(pfs->name, "boot") == 0)
+                       nipdata->comp_algo = HAMMER2_COMP_AUTOZERO;
                hammer2_inode_unlock_ex(nip, nchain);
        }
        hammer2_trans_done(&trans);