summaryrefslogtreecommitdiff
path: root/usr/src/lib/libzfs/common/libzfs_import.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libzfs/common/libzfs_import.c')
-rw-r--r--usr/src/lib/libzfs/common/libzfs_import.c49
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);
}