-
Notifications
You must be signed in to change notification settings - Fork 69
7584 Improve 'zpool labelclear' command #424
Changes from 7 commits
4e55a80
ccdede9
31452fc
c876bde
1561da9
72b508c
c94b7fd
22fe1ea
dc767f1
81bb4c6
8c9eeb3
e0dbeda
7485b1b
7be4c74
29d743b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -36,6 +36,7 @@ | |
#include <libgen.h> | ||
#include <libintl.h> | ||
#include <libuutil.h> | ||
#include <limits.h> | ||
#include <locale.h> | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
|
@@ -47,6 +48,7 @@ | |
#include <zone.h> | ||
#include <zfs_prop.h> | ||
#include <sys/fs/zfs.h> | ||
#include <sys/vdev_impl.h> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's possible that this is causing the compilation (lint) error (see http://jenkins.open-zfs.org/blue/organizations/jenkins/openzfs%2Fopenzfs/detail/PR-424/4/pipeline). Is this needed just for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, this is needed just for VDEV_LABELS. You mean moving VDEV_LABELS definition to sys/fs/zfs.h ? I don't know what that would imply for other parts of the code :/ Help would be welcome here :) |
||
#include <sys/stat.h> | ||
|
||
#include <libzfs.h> | ||
|
@@ -234,7 +236,8 @@ get_usage(zpool_help_t idx) | |
return (gettext("\tiostat [-v] [-T d|u] [pool] ... [interval " | ||
"[count]]\n")); | ||
case HELP_LABELCLEAR: | ||
return (gettext("\tlabelclear [-f] <vdev>\n")); | ||
return (gettext("\tlabelclear [-b | -e | -i index] [-c] [-m] " | ||
"[-f] <vdev>\n")); | ||
case HELP_LIST: | ||
return (gettext("\tlist [-Hp] [-o property[,...]] " | ||
"[-T d|u] [pool] ... [interval [count]]\n")); | ||
|
@@ -652,10 +655,39 @@ zpool_do_labelclear(int argc, char **argv) | |
pool_state_t state; | ||
boolean_t inuse = B_FALSE; | ||
boolean_t force = B_FALSE; | ||
boolean_t check = B_FALSE; | ||
boolean_t cherry = B_FALSE; | ||
unsigned int start = 0, n = VDEV_LABELS; | ||
long long index = 0; | ||
const char *errstr; | ||
|
||
/* check options */ | ||
while ((c = getopt(argc, argv, "f")) != -1) { | ||
while ((c = getopt(argc, argv, "bei:cmf")) != -1) { | ||
switch (c) { | ||
case 'b': | ||
start = 0; | ||
n = VDEV_LABELS / 2; | ||
break; | ||
case 'e': | ||
start = VDEV_LABELS / 2; | ||
n = VDEV_LABELS / 2; | ||
break; | ||
case 'i': | ||
index = strtonum(optarg, 0, VDEV_LABELS - 1, &errstr); | ||
if(errstr) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. cstyle: add space after |
||
(void) fprintf(stderr, | ||
gettext("Invalid index value provided\n")); | ||
return (1); | ||
} | ||
start = (unsigned int)index; | ||
n = 1; | ||
break; | ||
case 'c': | ||
check = B_TRUE; | ||
break; | ||
case 'm': | ||
cherry = B_TRUE; | ||
break; | ||
case 'f': | ||
force = B_TRUE; | ||
break; | ||
|
@@ -708,8 +740,12 @@ zpool_do_labelclear(int argc, char **argv) | |
} | ||
|
||
if (zpool_read_label(fd, &config) != 0 || config == NULL) { | ||
(void) fprintf(stderr, | ||
gettext("failed to read label from %s\n"), vdev); | ||
if (force) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't this check force_invalid since it's possible for zpool_read_label to return -1 for reasons other than the inability to read the label. If just force is used then we could wipe out the label of a legit pool. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hi @grwilson , The original version of FreeBSD's labelclear command allowed to forcibly wipe a label in any case (except when a pool is in use), see : https://svnweb.freebsd.org/base?view=revision&revision=224171 but that "feature" disappeared when the labelclear command was imported from upstream : https://svnweb.freebsd.org/base?view=revision&revision=297760 So this is just a fix to re-add that possibility : if we really want to force a wipe out, I think the command should not prevent us from doing so ; and that becomes even more useful when working with individual labels, as that patch now allows. |
||
goto wipe_label; | ||
(void) fprintf(stderr, gettext( | ||
"use '-f' to override the following error:\n" | ||
"failed to read label from \"%s\"\n"), | ||
vdev); | ||
return (1); | ||
} | ||
nvlist_free(config); | ||
|
@@ -762,7 +798,7 @@ zpool_do_labelclear(int argc, char **argv) | |
} | ||
|
||
wipe_label: | ||
ret = zpool_clear_label(fd); | ||
ret = zpool_clear_n_labels(fd, start, n, check, cherry); | ||
if (ret != 0) { | ||
(void) fprintf(stderr, | ||
gettext("failed to clear label for %s\n"), vdev); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1063,35 +1063,67 @@ zpool_open_func(void *arg) | |
} | ||
|
||
/* | ||
* Given a file descriptor, clear (zero) the label information. | ||
* Given a file descriptor, a starting label and a number of labels to clear, | ||
* clear (zero) the label information. | ||
*/ | ||
int | ||
zpool_clear_label(int fd) | ||
zpool_clear_n_labels(int fd, unsigned int start, unsigned int n, | ||
boolean_t check, boolean_t cherry) | ||
{ | ||
struct stat64 statbuf; | ||
int l; | ||
vdev_label_t *label; | ||
unsigned int l, end; | ||
vdev_label_t label; | ||
uint64_t size; | ||
|
||
char *buf = label.vl_vdev_phys.vp_nvlist; | ||
size_t buflen = sizeof (label.vl_vdev_phys.vp_nvlist); | ||
|
||
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) | ||
end = start + n; | ||
if (end > VDEV_LABELS) | ||
return (-1); | ||
|
||
for (l = 0; l < VDEV_LABELS; l++) { | ||
if (pwrite64(fd, label, sizeof (vdev_label_t), | ||
label_offset(size, l)) != sizeof (vdev_label_t)) { | ||
free(label); | ||
return (-1); | ||
for (l = start; l < end; l++) { | ||
if (check || cherry) { | ||
if (pread64(fd, &label, sizeof (vdev_label_t), | ||
label_offset(size, l)) != sizeof (vdev_label_t)) | ||
return (-1); | ||
|
||
if (check == B_TRUE) { | ||
nvlist_t *config = NULL; | ||
if (nvlist_unpack(buf, buflen, &config, 0) != 0) | ||
return (-1); | ||
nvlist_free(config); | ||
} | ||
} | ||
|
||
if (cherry == B_TRUE) { | ||
if (nvlist_invalidate(buf, buflen) != 0) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the goal is to prevent zpool import from showing the pool, then we should set the TXG value to 0 which is how ZFS clears a label while still leaving some information around for debugging. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The main goal of the patch is to allow wiping a single label with minimal changes. Acting on nvs encoding type (introducing a new type "invalid") allows touching a single byte, which is great because it minimizes the risks of damaging another FS that would have been created over the label. Acting on txg would touch 8 bytes and greatly improve the chances to break something. Also, as a side effect, acting on nvs encoding type keeps last txg value available for debugging. |
||
return (-1); | ||
} else { | ||
(void) memset(&label, 0, sizeof (vdev_label_t)); | ||
} | ||
|
||
if (pwrite64(fd, &label, sizeof (vdev_label_t), | ||
label_offset(size, l)) != sizeof (vdev_label_t)) | ||
return (-1); | ||
} | ||
|
||
free(label); | ||
return (0); | ||
} | ||
|
||
/* | ||
* Given a file descriptor, clear (zero) the label information. | ||
*/ | ||
int | ||
zpool_clear_label(int fd) | ||
{ | ||
return (zpool_clear_n_labels(fd, 0, VDEV_LABELS, B_FALSE, B_FALSE)); | ||
} | ||
|
||
/* | ||
* Given a list of directories to search, find all pools stored on disk. This | ||
* includes partial pools which are not available to import. If no args are | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use the $(C99_ENABLE) macro instead for both.