summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/boot/i386/zfsboot/zfsboot.c23
-rw-r--r--sys/boot/zfs/zfs.c4
-rw-r--r--sys/boot/zfs/zfsimpl.c71
-rw-r--r--sys/cddl/boot/zfs/zfsimpl.h18
4 files changed, 93 insertions, 23 deletions
diff --git a/sys/boot/i386/zfsboot/zfsboot.c b/sys/boot/i386/zfsboot/zfsboot.c
index a654393..c0dedd7 100644
--- a/sys/boot/i386/zfsboot/zfsboot.c
+++ b/sys/boot/i386/zfsboot/zfsboot.c
@@ -474,6 +474,7 @@ probe_drive(struct dsk *dsk, spa_t **spap)
slba = hdr.hdr_lba_table;
elba = slba + hdr.hdr_entries / entries_per_sec;
while (slba < elba) {
+ dsk->start = 0;
if (drvread(dsk, sec, slba, 1))
return;
for (part = 0; part < entries_per_sec; part++) {
@@ -494,7 +495,6 @@ probe_drive(struct dsk *dsk, spa_t **spap)
*/
dsk = copy_dsk(dsk);
}
- break;
}
}
slba++;
@@ -857,12 +857,13 @@ static void
printf(const char *fmt,...)
{
va_list ap;
- char buf[10];
+ char buf[20];
char *s;
- unsigned u;
+ unsigned long long u;
int c;
int minus;
int prec;
+ int l;
int len;
int pad;
@@ -871,6 +872,7 @@ printf(const char *fmt,...)
if (c == '%') {
minus = 0;
prec = 0;
+ l = 0;
nextfmt:
c = *fmt++;
switch (c) {
@@ -892,6 +894,9 @@ printf(const char *fmt,...)
case 'c':
putchar(va_arg(ap, int));
continue;
+ case 'l':
+ l++;
+ goto nextfmt;
case 's':
s = va_arg(ap, char *);
if (prec) {
@@ -914,7 +919,17 @@ printf(const char *fmt,...)
}
continue;
case 'u':
- u = va_arg(ap, unsigned);
+ switch (l) {
+ case 2:
+ u = va_arg(ap, unsigned long long);
+ break;
+ case 1:
+ u = va_arg(ap, unsigned long);
+ break;
+ default:
+ u = va_arg(ap, unsigned);
+ break;
+ }
s = buf;
do
*s++ = '0' + u % 10U;
diff --git a/sys/boot/zfs/zfs.c b/sys/boot/zfs/zfs.c
index 9784ef9..52df773 100644
--- a/sys/boot/zfs/zfs.c
+++ b/sys/boot/zfs/zfs.c
@@ -100,7 +100,7 @@ zfs_open(const char *upath, struct open_file *f)
f->f_fsdata = (void *)fp;
if (spa->spa_root_objset.os_type != DMU_OST_ZFS) {
- printf("Unexpected object set type %lld\n",
+ printf("Unexpected object set type %llu\n",
spa->spa_root_objset.os_type);
rc = EIO;
goto out;
@@ -413,7 +413,7 @@ zfs_dev_init(void)
if (vdev_probe(vdev_read, (void*) (uintptr_t) fd, 0))
close(fd);
- for (slice = 1; slice <= 4; slice++) {
+ for (slice = 1; slice <= 128; slice++) {
sprintf(devname, "disk%dp%d:", unit, slice);
fd = open(devname, O_RDONLY);
if (fd == -1) {
diff --git a/sys/boot/zfs/zfsimpl.c b/sys/boot/zfs/zfsimpl.c
index ff567a4..497fd7c 100644
--- a/sys/boot/zfs/zfsimpl.c
+++ b/sys/boot/zfs/zfsimpl.c
@@ -53,6 +53,8 @@ static char *zfs_temp_buf, *zfs_temp_end, *zfs_temp_ptr;
#define TEMP_SIZE (1*SPA_MAXBLOCKSIZE)
+static int zio_read(spa_t *spa, const blkptr_t *bp, void *buf);
+
static void
zfs_init(void)
{
@@ -897,6 +899,33 @@ ilog2(int n)
}
static int
+zio_read_gang(spa_t *spa, const blkptr_t *bp, const dva_t *dva, void *buf)
+{
+ zio_gbh_phys_t zio_gb;
+ vdev_t *vdev;
+ int vdevid;
+ off_t offset;
+ int i;
+
+ vdevid = DVA_GET_VDEV(dva);
+ offset = DVA_GET_OFFSET(dva);
+ STAILQ_FOREACH(vdev, &spa->spa_vdevs, v_childlink)
+ if (vdev->v_id == vdevid)
+ break;
+ if (!vdev || !vdev->v_read)
+ return (EIO);
+ if (vdev->v_read(vdev, bp, &zio_gb, offset, SPA_GANGBLOCKSIZE))
+ return (EIO);
+
+ for (i = 0; i < SPA_GBH_NBLKPTRS; i++) {
+ if (zio_read(spa, &zio_gb.zg_blkptr[i], buf))
+ return (EIO);
+ }
+
+ return (0);
+}
+
+static int
zio_read(spa_t *spa, const blkptr_t *bp, void *buf)
{
int cpfunc = BP_GET_COMPRESS(bp);
@@ -920,20 +949,27 @@ zio_read(spa_t *spa, const blkptr_t *bp, void *buf)
if (!dva->dva_word[0] && !dva->dva_word[1])
continue;
- vdevid = DVA_GET_VDEV(dva);
- offset = DVA_GET_OFFSET(dva);
- STAILQ_FOREACH(vdev, &spa->spa_vdevs, v_childlink)
- if (vdev->v_id == vdevid)
- break;
- if (!vdev || !vdev->v_read)
- continue;
- if (vdev->v_read(vdev, bp, pbuf, offset, psize))
- continue;
+ if (DVA_GET_GANG(dva)) {
+ printf("ZFS: gang block detected!\n");
+ if (zio_read_gang(spa, bp, dva, buf))
+ return (EIO);
+ } else {
+ vdevid = DVA_GET_VDEV(dva);
+ offset = DVA_GET_OFFSET(dva);
+ STAILQ_FOREACH(vdev, &spa->spa_vdevs, v_childlink)
+ if (vdev->v_id == vdevid)
+ break;
+ if (!vdev || !vdev->v_read) {
+ continue;
+ }
+ if (vdev->v_read(vdev, bp, pbuf, offset, psize))
+ continue;
- if (cpfunc != ZIO_COMPRESS_OFF) {
- if (zio_decompress_data(cpfunc, pbuf, psize,
- buf, lsize))
- return (EIO);
+ if (cpfunc != ZIO_COMPRESS_OFF) {
+ if (zio_decompress_data(cpfunc, pbuf, psize,
+ buf, lsize))
+ return (EIO);
+ }
}
return (0);
@@ -1331,13 +1367,13 @@ zfs_mount_dataset(spa_t *spa, uint64_t objnum, objset_phys_t *objset)
dsl_dataset_phys_t *ds;
if (objset_get_dnode(spa, &spa->spa_mos, objnum, &dataset)) {
- printf("ZFS: can't find dataset %lld\n", objnum);
+ printf("ZFS: can't find dataset %llu\n", objnum);
return (EIO);
}
ds = (dsl_dataset_phys_t *) &dataset.dn_bonus;
if (zio_read(spa, &ds->ds_bp, objset)) {
- printf("ZFS: can't read object set for dataset %lld\n", objnum);
+ printf("ZFS: can't read object set for dataset %llu\n", objnum);
return (EIO);
}
@@ -1367,7 +1403,8 @@ zfs_mount_root(spa_t *spa, objset_phys_t *objset)
*/
if (zap_lookup(spa, &dir, DMU_POOL_PROPS, &props) == 0
&& objset_get_dnode(spa, &spa->spa_mos, props, &propdir) == 0
- && zap_lookup(spa, &propdir, "bootfs", &bootfs) == 0)
+ && zap_lookup(spa, &propdir, "bootfs", &bootfs) == 0
+ && bootfs != 0)
return zfs_mount_dataset(spa, bootfs, objset);
/*
@@ -1425,7 +1462,7 @@ zfs_lookup(spa_t *spa, const char *upath, dnode_phys_t *dnode)
int symlinks_followed = 0;
if (spa->spa_root_objset.os_type != DMU_OST_ZFS) {
- printf("ZFS: unexpected object set type %lld\n",
+ printf("ZFS: unexpected object set type %llu\n",
spa->spa_root_objset.os_type);
return (EIO);
}
diff --git a/sys/cddl/boot/zfs/zfsimpl.h b/sys/cddl/boot/zfs/zfsimpl.h
index a0b7b72..688bb5c 100644
--- a/sys/cddl/boot/zfs/zfsimpl.h
+++ b/sys/cddl/boot/zfs/zfsimpl.h
@@ -374,6 +374,24 @@ typedef struct vdev_label {
#define VDEV_LABEL_END_SIZE (2 * sizeof (vdev_label_t))
#define VDEV_LABELS 4
+/*
+ * Gang block headers are self-checksumming and contain an array
+ * of block pointers.
+ */
+#define SPA_GANGBLOCKSIZE SPA_MINBLOCKSIZE
+#define SPA_GBH_NBLKPTRS ((SPA_GANGBLOCKSIZE - \
+ sizeof (zio_block_tail_t)) / sizeof (blkptr_t))
+#define SPA_GBH_FILLER ((SPA_GANGBLOCKSIZE - \
+ sizeof (zio_block_tail_t) - \
+ (SPA_GBH_NBLKPTRS * sizeof (blkptr_t))) /\
+ sizeof (uint64_t))
+
+typedef struct zio_gbh {
+ blkptr_t zg_blkptr[SPA_GBH_NBLKPTRS];
+ uint64_t zg_filler[SPA_GBH_FILLER];
+ zio_block_tail_t zg_tail;
+} zio_gbh_phys_t;
+
enum zio_checksum {
ZIO_CHECKSUM_INHERIT = 0,
ZIO_CHECKSUM_ON,
OpenPOWER on IntegriCloud