diff options
author | Toomas Soome <tsoome@me.com> | 2016-11-07 15:37:12 +0200 |
---|---|---|
committer | Robert Mustacchi <rm@joyent.com> | 2017-04-05 04:23:47 +0000 |
commit | edb35047b6b720980b6de7117a950b94ae288202 (patch) | |
tree | e0e93a8a019a41c525efec5e8bddc76fed1d52d4 | |
parent | dde8fce6139e57132d03ce57125c94e66c8ade09 (diff) | |
download | illumos-joyent-edb35047b6b720980b6de7117a950b94ae288202.tar.gz |
7540 loader zfs should check all labels
Reviewed by: Andriy Gapon <agapon@gmail.com>
Reviewed by: Paul Dagnelie <pcd@delphix.com>
Approved by: Robert Mustacchi <rm@joyent.com>
-rw-r--r-- | usr/src/boot/Makefile.version | 2 | ||||
-rw-r--r-- | usr/src/boot/sys/boot/efi/boot1/zfs_module.c | 9 | ||||
-rw-r--r-- | usr/src/boot/sys/boot/efi/libefi/efipart.c | 31 | ||||
-rw-r--r-- | usr/src/boot/sys/boot/efi/loader/main.c | 11 | ||||
-rw-r--r-- | usr/src/boot/sys/boot/i386/gptzfsboot/zfsboot.c | 10 | ||||
-rw-r--r-- | usr/src/boot/sys/boot/i386/libi386/biosdisk.c | 6 | ||||
-rw-r--r-- | usr/src/boot/sys/boot/i386/loader/main.c | 11 | ||||
-rw-r--r-- | usr/src/boot/sys/boot/zfs/libzfs.h | 1 | ||||
-rw-r--r-- | usr/src/boot/sys/boot/zfs/zfs.c | 2 | ||||
-rw-r--r-- | usr/src/boot/sys/boot/zfs/zfsimpl.c | 245 |
10 files changed, 221 insertions, 107 deletions
diff --git a/usr/src/boot/Makefile.version b/usr/src/boot/Makefile.version index 60ad7be601..6e85cbfb08 100644 --- a/usr/src/boot/Makefile.version +++ b/usr/src/boot/Makefile.version @@ -33,4 +33,4 @@ LOADER_VERSION = 1.1 # Use date like formatting here, YYYY.MM.DD.XX, without leading zeroes. # The version is processed from left to right, the version number can only # be increased. -BOOT_VERSION = $(LOADER_VERSION)-2017.3.29.1 +BOOT_VERSION = $(LOADER_VERSION)-2017.4.1.1 diff --git a/usr/src/boot/sys/boot/efi/boot1/zfs_module.c b/usr/src/boot/sys/boot/efi/boot1/zfs_module.c index 9cbe1582f1..c81f759876 100644 --- a/usr/src/boot/sys/boot/efi/boot1/zfs_module.c +++ b/usr/src/boot/sys/boot/efi/boot1/zfs_module.c @@ -38,6 +38,15 @@ static dev_info_t *devices; +uint64_t +ldi_get_size(void *priv) +{ + dev_info_t *devinfo = priv; + + return (devinfo->dev->Media->BlockSize * + (devinfo->dev->Media->LastBlock + 1)); +} + static int vdev_read(vdev_t *vdev, void *priv, off_t off, void *buf, size_t bytes) { diff --git a/usr/src/boot/sys/boot/efi/libefi/efipart.c b/usr/src/boot/sys/boot/efi/libefi/efipart.c index eaaa56714b..e4f3e1151b 100644 --- a/usr/src/boot/sys/boot/efi/libefi/efipart.c +++ b/usr/src/boot/sys/boot/efi/libefi/efipart.c @@ -25,8 +25,8 @@ */ #include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); +#include <sys/disk.h> #include <sys/param.h> #include <sys/time.h> #include <stddef.h> @@ -45,6 +45,7 @@ static int efipart_strategy(void *, int, daddr_t, size_t, char *, size_t *); static int efipart_realstrategy(void *, int, daddr_t, size_t, char *, size_t *); static int efipart_open(struct open_file *, ...); static int efipart_close(struct open_file *); +static int efipart_ioctl(struct open_file *, u_long, void *); static int efipart_print(int); struct devsw efipart_dev = { @@ -54,7 +55,7 @@ struct devsw efipart_dev = { .dv_strategy = efipart_strategy, .dv_open = efipart_open, .dv_close = efipart_close, - .dv_ioctl = noioctl, + .dv_ioctl = efipart_ioctl, .dv_print = efipart_print, .dv_cleanup = NULL }; @@ -241,6 +242,32 @@ efipart_close(struct open_file *f) return (0); } +static int +efipart_ioctl(struct open_file *f, u_long cmd, void *data) +{ + struct devdesc *dev; + EFI_BLOCK_IO *blkio; + + dev = (struct devdesc *)(f->f_devdata); + if (dev->d_opendata == NULL) + return (EINVAL); + blkio = dev->d_opendata; + + switch (cmd) { + case DIOCGSECTORSIZE: + *(u_int *)data = blkio->Media->BlockSize; + break; + case DIOCGMEDIASIZE: + *(uint64_t *)data = blkio->Media->BlockSize * + (blkio->Media->LastBlock + 1); + break; + default: + return (ENOTTY); + } + + return (0); +} + /* * efipart_readwrite() * Internal equivalent of efipart_strategy(), which operates on the diff --git a/usr/src/boot/sys/boot/efi/loader/main.c b/usr/src/boot/sys/boot/efi/loader/main.c index 3a056cd444..b0bbce638e 100644 --- a/usr/src/boot/sys/boot/efi/loader/main.c +++ b/usr/src/boot/sys/boot/efi/loader/main.c @@ -27,6 +27,7 @@ #include <sys/cdefs.h> +#include <sys/disk.h> #include <sys/param.h> #include <sys/reboot.h> #include <sys/boot.h> @@ -1078,4 +1079,14 @@ efi_zfs_probe(void) (void)efi_handle_update_dev(h, &zfs_dev, unit++, guid); } } + +uint64_t +ldi_get_size(void *priv) +{ + int fd = (uintptr_t) priv; + uint64_t size; + + ioctl(fd, DIOCGMEDIASIZE, &size); + return (size); +} #endif diff --git a/usr/src/boot/sys/boot/i386/gptzfsboot/zfsboot.c b/usr/src/boot/sys/boot/i386/gptzfsboot/zfsboot.c index 53c18c6bfe..0ee7f2c9bb 100644 --- a/usr/src/boot/sys/boot/i386/gptzfsboot/zfsboot.c +++ b/usr/src/boot/sys/boot/i386/gptzfsboot/zfsboot.c @@ -718,3 +718,13 @@ i386_zfs_probe(void) probe_disk(devname); } } + +uint64_t +ldi_get_size(void *priv) +{ + int fd = (uintptr_t) priv; + uint64_t size; + + ioctl(fd, DIOCGMEDIASIZE, &size); + return (size); +} diff --git a/usr/src/boot/sys/boot/i386/libi386/biosdisk.c b/usr/src/boot/sys/boot/i386/libi386/biosdisk.c index 3c38c44524..10efb5e422 100644 --- a/usr/src/boot/sys/boot/i386/libi386/biosdisk.c +++ b/usr/src/boot/sys/boot/i386/libi386/biosdisk.c @@ -412,8 +412,14 @@ static int bd_ioctl(struct open_file *f, u_long cmd, void *data) { struct disk_devdesc *dev; + int rc; dev = (struct disk_devdesc *)f->f_devdata; + + rc = disk_ioctl(dev, cmd, data); + if (rc != ENOTTY) + return (rc); + switch (cmd) { case DIOCGSECTORSIZE: *(u_int *)data = BD(dev).bd_sectorsize; diff --git a/usr/src/boot/sys/boot/i386/loader/main.c b/usr/src/boot/sys/boot/i386/loader/main.c index 3ab2ef408f..be092c552f 100644 --- a/usr/src/boot/sys/boot/i386/loader/main.c +++ b/usr/src/boot/sys/boot/i386/loader/main.c @@ -37,6 +37,7 @@ #include <machine/bootinfo.h> #include <machine/cpufunc.h> #include <machine/psl.h> +#include <sys/disk.h> #include <sys/reboot.h> #include "bootstrap.h" @@ -436,4 +437,14 @@ i386_zfs_probe(void) zfs_probe_dev(devname, NULL); } } + +uint64_t +ldi_get_size(void *priv) +{ + int fd = (uintptr_t) priv; + uint64_t size; + + ioctl(fd, DIOCGMEDIASIZE, &size); + return (size); +} #endif diff --git a/usr/src/boot/sys/boot/zfs/libzfs.h b/usr/src/boot/sys/boot/zfs/libzfs.h index b237a38b96..d08f76e569 100644 --- a/usr/src/boot/sys/boot/zfs/libzfs.h +++ b/usr/src/boot/sys/boot/zfs/libzfs.h @@ -63,6 +63,7 @@ char *zfs_bootfs(void *vdev); char *zfs_fmtdev(void *vdev); int zfs_probe_dev(const char *devname, uint64_t *pool_guid); int zfs_list(const char *name); +uint64_t ldi_get_size(void *); #ifdef __FreeBSD__ void init_zfs_bootenv(char *currdev); int zfs_bootenv(const char *name); diff --git a/usr/src/boot/sys/boot/zfs/zfs.c b/usr/src/boot/sys/boot/zfs/zfs.c index 3f6455c80c..d4b7e8ef40 100644 --- a/usr/src/boot/sys/boot/zfs/zfs.c +++ b/usr/src/boot/sys/boot/zfs/zfs.c @@ -487,7 +487,7 @@ zfs_probe_dev(const char *devname, uint64_t *pool_guid) { struct ptable *table; struct zfs_probe_args pa; - off_t mediasz; + uint64_t mediasz; int ret; pa.fd = open(devname, O_RDONLY); diff --git a/usr/src/boot/sys/boot/zfs/zfsimpl.c b/usr/src/boot/sys/boot/zfs/zfsimpl.c index 87a3a34efe..c3f439855f 100644 --- a/usr/src/boot/sys/boot/zfs/zfsimpl.c +++ b/usr/src/boot/sys/boot/zfs/zfsimpl.c @@ -66,8 +66,7 @@ static const char *features_for_read[] = { */ static spa_list_t zfs_pools; -static uint64_t zfs_crc64_table[256]; -static const dnode_phys_t *dnode_cache_obj = 0; +static const dnode_phys_t *dnode_cache_obj; static uint64_t dnode_cache_bn; static char *dnode_cache_buf; static char *zap_scratch; @@ -519,12 +518,11 @@ vdev_init_from_nvlist(const unsigned char *nvlist, vdev_t *pvdev, int nkids, i, is_new; uint64_t is_offline, is_faulted, is_degraded, is_removed, isnt_present; - if (nvlist_find(nvlist, ZPOOL_CONFIG_GUID, - DATA_TYPE_UINT64, 0, &guid) - || nvlist_find(nvlist, ZPOOL_CONFIG_ID, - DATA_TYPE_UINT64, 0, &id) - || nvlist_find(nvlist, ZPOOL_CONFIG_TYPE, - DATA_TYPE_STRING, 0, &type)) { + if (nvlist_find(nvlist, ZPOOL_CONFIG_GUID, DATA_TYPE_UINT64, + NULL, &guid) || + nvlist_find(nvlist, ZPOOL_CONFIG_ID, DATA_TYPE_UINT64, NULL, &id) || + nvlist_find(nvlist, ZPOOL_CONFIG_TYPE, DATA_TYPE_STRING, + NULL, &type)) { printf("ZFS: can't find vdev details\n"); return (ENOENT); } @@ -542,16 +540,16 @@ vdev_init_from_nvlist(const unsigned char *nvlist, vdev_t *pvdev, is_offline = is_removed = is_faulted = is_degraded = isnt_present = 0; - nvlist_find(nvlist, ZPOOL_CONFIG_OFFLINE, DATA_TYPE_UINT64, 0, - &is_offline); - nvlist_find(nvlist, ZPOOL_CONFIG_REMOVED, DATA_TYPE_UINT64, 0, - &is_removed); - nvlist_find(nvlist, ZPOOL_CONFIG_FAULTED, DATA_TYPE_UINT64, 0, - &is_faulted); - nvlist_find(nvlist, ZPOOL_CONFIG_DEGRADED, DATA_TYPE_UINT64, 0, - &is_degraded); - nvlist_find(nvlist, ZPOOL_CONFIG_NOT_PRESENT, DATA_TYPE_UINT64, 0, - &isnt_present); + nvlist_find(nvlist, ZPOOL_CONFIG_OFFLINE, DATA_TYPE_UINT64, NULL, + &is_offline); + nvlist_find(nvlist, ZPOOL_CONFIG_REMOVED, DATA_TYPE_UINT64, NULL, + &is_removed); + nvlist_find(nvlist, ZPOOL_CONFIG_FAULTED, DATA_TYPE_UINT64, NULL, + &is_faulted); + nvlist_find(nvlist, ZPOOL_CONFIG_DEGRADED, DATA_TYPE_UINT64, NULL, + &is_degraded); + nvlist_find(nvlist, ZPOOL_CONFIG_NOT_PRESENT, DATA_TYPE_UINT64, NULL, + &isnt_present); vdev = vdev_find(guid); if (!vdev) { @@ -569,30 +567,34 @@ vdev_init_from_nvlist(const unsigned char *nvlist, vdev_t *pvdev, vdev->v_id = id; vdev->v_top = pvdev != NULL ? pvdev : vdev; if (nvlist_find(nvlist, ZPOOL_CONFIG_ASHIFT, - DATA_TYPE_UINT64, 0, &ashift) == 0) + DATA_TYPE_UINT64, NULL, &ashift) == 0) { vdev->v_ashift = ashift; - else + } else { vdev->v_ashift = 0; + } if (nvlist_find(nvlist, ZPOOL_CONFIG_NPARITY, - DATA_TYPE_UINT64, 0, &nparity) == 0) + DATA_TYPE_UINT64, NULL, &nparity) == 0) { vdev->v_nparity = nparity; - else + } else { vdev->v_nparity = 0; + } if (nvlist_find(nvlist, ZPOOL_CONFIG_PATH, - DATA_TYPE_STRING, 0, &path) == 0) { + DATA_TYPE_STRING, NULL, &path) == 0) { if (strncmp(path, "/dev/dsk/", 9) == 0) path += 9; vdev->v_name = strdup(path); if (nvlist_find(nvlist, ZPOOL_CONFIG_PHYS_PATH, - DATA_TYPE_STRING, 0, &path) == 0) + DATA_TYPE_STRING, NULL, &path) == 0) { vdev->v_phys_path = strdup(path); - else + } else { vdev->v_phys_path = NULL; + } if (nvlist_find(nvlist, ZPOOL_CONFIG_DEVID, - DATA_TYPE_STRING, 0, &path) == 0) + DATA_TYPE_STRING, NULL, &path) == 0) { vdev->v_devid = strdup(path); - else + } else { vdev->v_devid = NULL; + } } else { if (!strcmp(type, "raidz")) { if (vdev->v_nparity == 1) @@ -631,8 +633,8 @@ vdev_init_from_nvlist(const unsigned char *nvlist, vdev_t *pvdev, vdev->v_state = VDEV_STATE_CANT_OPEN; } - rc = nvlist_find(nvlist, ZPOOL_CONFIG_CHILDREN, - DATA_TYPE_NVLIST_ARRAY, &nkids, &kids); + rc = nvlist_find(nvlist, ZPOOL_CONFIG_CHILDREN, DATA_TYPE_NVLIST_ARRAY, + &nkids, &kids); /* * Its ok if we don't have any kids. */ @@ -747,12 +749,17 @@ spa_get_primary_vdev(const spa_t *spa) } static spa_t * -spa_create(uint64_t guid) +spa_create(uint64_t guid, const char *name) { spa_t *spa; - spa = malloc(sizeof(spa_t)); + if ((spa = malloc(sizeof(spa_t))) == NULL) + return (NULL); memset(spa, 0, sizeof(spa_t)); + if ((spa->spa_name = strdup(name)) == NULL) { + free(spa); + return (NULL); + } STAILQ_INIT(&spa->spa_vdevs); spa->spa_guid = guid; STAILQ_INSERT_TAIL(&zfs_pools, spa, spa_link); @@ -899,24 +906,39 @@ spa_all_status(void) return (ret); } +uint64_t +vdev_label_offset(uint64_t psize, int l, uint64_t offset) +{ + uint64_t label_offset; + + if (l < VDEV_LABELS / 2) + label_offset = 0; + else + label_offset = psize - VDEV_LABELS * sizeof (vdev_label_t); + + return (offset + l * sizeof (vdev_label_t) + label_offset); +} + static int vdev_probe(vdev_phys_read_t *phys_read, void *read_priv, spa_t **spap) { vdev_t vtmp; vdev_phys_t *vdev_label = (vdev_phys_t *) zap_scratch; + vdev_phys_t *tmp_label = zfs_alloc(sizeof(vdev_phys_t)); spa_t *spa; vdev_t *vdev, *top_vdev, *pool_vdev; off_t off; blkptr_t bp; - const unsigned char *nvlist; + const unsigned char *nvlist = NULL; uint64_t val; uint64_t guid; + uint64_t best_txg = 0; uint64_t pool_txg, pool_guid; - uint64_t is_log; + uint64_t psize; const char *pool_name; const unsigned char *vdevs; const unsigned char *features; - int i, rc, is_newer; + int i, l, rc, is_newer; char *upbuf; const struct uberblock *up; @@ -927,26 +949,47 @@ vdev_probe(vdev_phys_read_t *phys_read, void *read_priv, spa_t **spap) memset(&vtmp, 0, sizeof(vtmp)); vtmp.v_phys_read = phys_read; vtmp.v_read_priv = read_priv; - off = offsetof(vdev_label_t, vl_vdev_phys); - BP_ZERO(&bp); - BP_SET_LSIZE(&bp, sizeof(vdev_phys_t)); - BP_SET_PSIZE(&bp, sizeof(vdev_phys_t)); - BP_SET_CHECKSUM(&bp, ZIO_CHECKSUM_LABEL); - BP_SET_COMPRESS(&bp, ZIO_COMPRESS_OFF); - DVA_SET_OFFSET(BP_IDENTITY(&bp), off); - ZIO_SET_CHECKSUM(&bp.blk_cksum, off, 0, 0, 0); - if (vdev_read_phys(&vtmp, &bp, vdev_label, off, 0)) - return (EIO); + psize = P2ALIGN(ldi_get_size(read_priv), + (uint64_t)sizeof (vdev_label_t)); - if (vdev_label->vp_nvlist[0] != NV_ENCODE_XDR) { - return (EIO); + for (l = 0; l < VDEV_LABELS; l++) { + off = vdev_label_offset(psize, l, + offsetof(vdev_label_t, vl_vdev_phys)); + + BP_ZERO(&bp); + BP_SET_LSIZE(&bp, sizeof(vdev_phys_t)); + BP_SET_PSIZE(&bp, sizeof(vdev_phys_t)); + BP_SET_CHECKSUM(&bp, ZIO_CHECKSUM_LABEL); + BP_SET_COMPRESS(&bp, ZIO_COMPRESS_OFF); + DVA_SET_OFFSET(BP_IDENTITY(&bp), off); + ZIO_SET_CHECKSUM(&bp.blk_cksum, off, 0, 0, 0); + + if (vdev_read_phys(&vtmp, &bp, tmp_label, off, 0)) + continue; + + if (tmp_label->vp_nvlist[0] != NV_ENCODE_XDR) + continue; + + nvlist = (const unsigned char *) tmp_label->vp_nvlist + 4; + if (nvlist_find(nvlist, ZPOOL_CONFIG_POOL_TXG, + DATA_TYPE_UINT64, NULL, &pool_txg) != 0) + continue; + + if (best_txg <= pool_txg) { + best_txg = pool_txg; + memcpy(vdev_label, tmp_label, sizeof (vdev_phys_t)); + } } + zfs_free(tmp_label, sizeof (vdev_phys_t)); + + if (vdev_label->vp_nvlist[0] != NV_ENCODE_XDR) + return (EIO); + nvlist = (const unsigned char *) vdev_label->vp_nvlist + 4; - if (nvlist_find(nvlist, - ZPOOL_CONFIG_VERSION, - DATA_TYPE_UINT64, 0, &val)) { + if (nvlist_find(nvlist, ZPOOL_CONFIG_VERSION, DATA_TYPE_UINT64, + NULL, &val) != 0) { return (EIO); } @@ -957,15 +1000,14 @@ vdev_probe(vdev_phys_read_t *phys_read, void *read_priv, spa_t **spap) } /* Check ZFS features for read */ - if (nvlist_find(nvlist, - ZPOOL_CONFIG_FEATURES_FOR_READ, - DATA_TYPE_NVLIST, 0, &features) == 0 - && nvlist_check_features_for_read(features) != 0) + if (nvlist_find(nvlist, ZPOOL_CONFIG_FEATURES_FOR_READ, + DATA_TYPE_NVLIST, NULL, &features) == 0 && + nvlist_check_features_for_read(features) != 0) { return (EIO); + } - if (nvlist_find(nvlist, - ZPOOL_CONFIG_POOL_STATE, - DATA_TYPE_UINT64, 0, &val)) { + if (nvlist_find(nvlist, ZPOOL_CONFIG_POOL_STATE, DATA_TYPE_UINT64, + NULL, &val) != 0) { return (EIO); } @@ -974,15 +1016,12 @@ vdev_probe(vdev_phys_read_t *phys_read, void *read_priv, spa_t **spap) return (EIO); } - if (nvlist_find(nvlist, - ZPOOL_CONFIG_POOL_TXG, - DATA_TYPE_UINT64, 0, &pool_txg) - || nvlist_find(nvlist, - ZPOOL_CONFIG_POOL_GUID, - DATA_TYPE_UINT64, 0, &pool_guid) - || nvlist_find(nvlist, - ZPOOL_CONFIG_POOL_NAME, - DATA_TYPE_STRING, 0, &pool_name)) { + if (nvlist_find(nvlist, ZPOOL_CONFIG_POOL_TXG, DATA_TYPE_UINT64, + NULL, &pool_txg) != 0 || + nvlist_find(nvlist, ZPOOL_CONFIG_POOL_GUID, DATA_TYPE_UINT64, + NULL, &pool_guid) != 0 || + nvlist_find(nvlist, ZPOOL_CONFIG_POOL_NAME, DATA_TYPE_STRING, + NULL, &pool_name) != 0) { /* * Cache and spare devices end up here - just ignore * them. @@ -991,25 +1030,26 @@ vdev_probe(vdev_phys_read_t *phys_read, void *read_priv, spa_t **spap) return (EIO); } - is_log = 0; - (void) nvlist_find(nvlist, ZPOOL_CONFIG_IS_LOG, DATA_TYPE_UINT64, 0, - &is_log); - if (is_log) + if (nvlist_find(nvlist, ZPOOL_CONFIG_IS_LOG, DATA_TYPE_UINT64, + NULL, &val) == 0 && val != 0) { return (EIO); + } /* * Create the pool if this is the first time we've seen it. */ spa = spa_find_by_guid(pool_guid); - if (!spa) { - spa = spa_create(pool_guid); - spa->spa_name = strdup(pool_name); + if (spa == NULL) { + spa = spa_create(pool_guid, pool_name); + if (spa == NULL) + return (ENOMEM); } if (pool_txg > spa->spa_txg) { spa->spa_txg = pool_txg; is_newer = 1; - } else + } else { is_newer = 0; + } /* * Get the vdev tree and create our in-core copy of it. @@ -1017,23 +1057,21 @@ vdev_probe(vdev_phys_read_t *phys_read, void *read_priv, spa_t **spap) * be some kind of alias (overlapping slices, dangerously dedicated * disks etc). */ - if (nvlist_find(nvlist, - ZPOOL_CONFIG_GUID, - DATA_TYPE_UINT64, 0, &guid)) { + if (nvlist_find(nvlist, ZPOOL_CONFIG_GUID, DATA_TYPE_UINT64, + NULL, &guid) != 0) { return (EIO); } vdev = vdev_find(guid); if (vdev && vdev->v_phys_read) /* Has this vdev already been inited? */ return (EIO); - if (nvlist_find(nvlist, - ZPOOL_CONFIG_VDEV_TREE, - DATA_TYPE_NVLIST, 0, &vdevs)) { + if (nvlist_find(nvlist, ZPOOL_CONFIG_VDEV_TREE, DATA_TYPE_NVLIST, + NULL, &vdevs)) { return (EIO); } rc = vdev_init_from_nvlist(vdevs, NULL, &top_vdev, is_newer); - if (rc) + if (rc != 0) return (rc); /* @@ -1071,35 +1109,36 @@ vdev_probe(vdev_phys_read_t *phys_read, void *read_priv, spa_t **spap) */ upbuf = zfs_alloc(VDEV_UBERBLOCK_SIZE(vdev)); up = (const struct uberblock *)upbuf; - for (i = 0; - i < VDEV_UBERBLOCK_COUNT(vdev); - i++) { - off = VDEV_UBERBLOCK_OFFSET(vdev, i); - BP_ZERO(&bp); - DVA_SET_OFFSET(&bp.blk_dva[0], off); - BP_SET_LSIZE(&bp, VDEV_UBERBLOCK_SIZE(vdev)); - BP_SET_PSIZE(&bp, VDEV_UBERBLOCK_SIZE(vdev)); - BP_SET_CHECKSUM(&bp, ZIO_CHECKSUM_LABEL); - BP_SET_COMPRESS(&bp, ZIO_COMPRESS_OFF); - ZIO_SET_CHECKSUM(&bp.blk_cksum, off, 0, 0, 0); - - if (vdev_read_phys(vdev, &bp, upbuf, off, 0)) - continue; + for (l = 0; l < VDEV_LABELS; l++) { + for (i = 0; i < VDEV_UBERBLOCK_COUNT(vdev); i++) { + off = vdev_label_offset(psize, l, + VDEV_UBERBLOCK_OFFSET(vdev, i)); + BP_ZERO(&bp); + DVA_SET_OFFSET(&bp.blk_dva[0], off); + BP_SET_LSIZE(&bp, VDEV_UBERBLOCK_SIZE(vdev)); + BP_SET_PSIZE(&bp, VDEV_UBERBLOCK_SIZE(vdev)); + BP_SET_CHECKSUM(&bp, ZIO_CHECKSUM_LABEL); + BP_SET_COMPRESS(&bp, ZIO_COMPRESS_OFF); + ZIO_SET_CHECKSUM(&bp.blk_cksum, off, 0, 0, 0); + + if (vdev_read_phys(vdev, &bp, upbuf, off, 0) != 0) + continue; - if (up->ub_magic != UBERBLOCK_MAGIC) - continue; - if (up->ub_txg < spa->spa_txg) - continue; - if (up->ub_txg > spa->spa_uberblock.ub_txg) { - spa->spa_uberblock = *up; - } else if (up->ub_txg == spa->spa_uberblock.ub_txg) { - if (up->ub_timestamp > spa->spa_uberblock.ub_timestamp) + if (up->ub_magic != UBERBLOCK_MAGIC) + continue; + if (up->ub_txg < spa->spa_txg) + continue; + if (up->ub_txg > spa->spa_uberblock.ub_txg || + (up->ub_txg == spa->spa_uberblock.ub_txg && + up->ub_timestamp > + spa->spa_uberblock.ub_timestamp)) { spa->spa_uberblock = *up; + } } } zfs_free(upbuf, VDEV_UBERBLOCK_SIZE(vdev)); - if (spap) + if (spap != NULL) *spap = spa; return (0); } |