diff options
author | rnoland <rnoland@FreeBSD.org> | 2009-10-23 18:44:53 +0000 |
---|---|---|
committer | rnoland <rnoland@FreeBSD.org> | 2009-10-23 18:44:53 +0000 |
commit | 8a200b8ecf6471a2f6b31a0056a9302651259a95 (patch) | |
tree | 54470b2775fb022903573c97e9f3370147d0c142 /sys/boot/zfs | |
parent | 364b20ea38ba4e0c43cf52903665e313590f0df6 (diff) | |
download | FreeBSD-src-8a200b8ecf6471a2f6b31a0056a9302651259a95.zip FreeBSD-src-8a200b8ecf6471a2f6b31a0056a9302651259a95.tar.gz |
Correct some issues with zfs boot.
- Teach it to read gang blocks. (essentially untested)
If you see "ZFS: gang block detected!", please let
me know, so we can either remove the printf if it
works, or fix it if it doesn't.
- If multiple partitions exist on a disk, probe them all.
We also need to reset dsk->start to 0 to read the right
sector here.
- With GPT, we can have 128 partitions.
- If the bootfs property has ever been set on a pool
it seems that it never goes away. zpool won't allow
you to add to the pool with the bootfs property set.
However, if you clear the property back to default
we end up getting 0 for the object number and read
a bogus block pointer and fail to boot.
- Fix some error printfs. The printf in the loader is
only capable of c,s and u formats.
- Teach printf how to display %llu
Reviewed by: dfr, jhb
MFC after: 2 weeks
Diffstat (limited to 'sys/boot/zfs')
-rw-r--r-- | sys/boot/zfs/zfs.c | 4 | ||||
-rw-r--r-- | sys/boot/zfs/zfsimpl.c | 71 |
2 files changed, 56 insertions, 19 deletions
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); } |