Improve zpool labelclear

1) As implemented the `zpool labelclear` command overwrites
the calculated offsets of all four vdev labels even when only a
single valid label is found.  If the device as been re-purposed
but still contains a valid label this can result in space no
longer owned by ZFS being zeroed.  Prevent this by verifying
every label removed is intact before it's overwritten.

2) Address a small bug in zpool_do_labelclear() which prevented
labelclear from working on file vdevs.  Only block devices support
BLKFLSBUF, try the ioctl() but when it's reported as unsupported
this should not be fatal.

3) Fix `zpool labelclear` so it can be run on vdevs which were
removed from the pool with `zpool remove`.  Additionally, allow
intact but partial labels to be cleared as in the case of a failed
`zpool attach` or `zpool replace`.

4) Remove LABELCLEAR and LABELREAD variables for test cases.

Reviewed-by: Matt Ahrens <mahrens@delphix.com>
Reviewed-by: Tim Chase <tim@chase2k.com>
Reviewed-by: Tony Hutter <hutter2@llnl.gov>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #8500 
Closes #8373 
Closes #6261
This commit is contained in:
Brian Behlendorf
2019-03-21 10:13:01 -07:00
committed by GitHub
parent 304d469dcd
commit 066da71e7f
12 changed files with 246 additions and 58 deletions
+46 -3
View File
@@ -148,23 +148,66 @@ zpool_clear_label(int fd)
int l;
vdev_label_t *label;
uint64_t size;
int labels_cleared = 0;
if (fstat64_blk(fd, &statbuf) == -1)
return (0);
size = P2ALIGN_TYPED(statbuf.st_size, sizeof (vdev_label_t), uint64_t);
if ((label = calloc(1, sizeof (vdev_label_t))) == 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);
}