diff options
Diffstat (limited to 'usr/src/lib/libzfs/common/libzfs_import.c')
-rw-r--r-- | usr/src/lib/libzfs/common/libzfs_import.c | 49 |
1 files changed, 46 insertions, 3 deletions
diff --git a/usr/src/lib/libzfs/common/libzfs_import.c b/usr/src/lib/libzfs/common/libzfs_import.c index 706f08e6ec..dc15aca0c0 100644 --- a/usr/src/lib/libzfs/common/libzfs_import.c +++ b/usr/src/lib/libzfs/common/libzfs_import.c @@ -169,23 +169,66 @@ zpool_clear_label(int fd) int l; vdev_label_t *label; uint64_t size; + int labels_cleared = 0; if (fstat64(fd, &statbuf) == -1) return (0); + size = P2ALIGN_TYPED(statbuf.st_size, sizeof (vdev_label_t), uint64_t); if ((label = calloc(sizeof (vdev_label_t), 1)) == NULL) return (-1); for (l = 0; l < VDEV_LABELS; l++) { - if (pwrite64(fd, label, sizeof (vdev_label_t), + uint64_t state, guid; + nvlist_t *config; + + if (pread64(fd, label, sizeof (vdev_label_t), label_offset(size, l)) != sizeof (vdev_label_t)) { - free(label); - return (-1); + continue; + } + + if (nvlist_unpack(label->vl_vdev_phys.vp_nvlist, + sizeof (label->vl_vdev_phys.vp_nvlist), &config, 0) != 0) { + continue; + } + + /* Skip labels which do not have a valid guid. */ + if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_GUID, + &guid) != 0 || guid == 0) { + nvlist_free(config); + continue; + } + + /* Skip labels which are not in a known valid state. */ + if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, + &state) != 0 || state > POOL_STATE_L2CACHE) { + nvlist_free(config); + continue; + } + + nvlist_free(config); + + /* + * A valid label was found, overwrite this label's nvlist + * and uberblocks with zeros on disk. This is done to prevent + * system utilities, like blkid, from incorrectly detecting a + * partial label. The leading pad space is left untouched. + */ + memset(label, 0, sizeof (vdev_label_t)); + size_t label_size = sizeof (vdev_label_t) - (2 * VDEV_PAD_SIZE); + + if (pwrite64(fd, label, label_size, label_offset(size, l) + + (2 * VDEV_PAD_SIZE)) == label_size) { + labels_cleared++; } } free(label); + + if (labels_cleared == 0) + return (-1); + return (0); } |