mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-22 02:27:36 +03:00
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:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user