Add FreeBSD 'zpool labelclear' command

The FreeBSD implementation of zfs adds the 'zpool labelclear'
command.  Since this functionality is helpful and straight
forward to add it is being included in ZoL.

References:
  freebsd/freebsd@119a041dc9

Ported-by: Dmitry Khasanov <pik4ez@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #1126
This commit is contained in:
Dmitry Khasanov 2013-07-05 18:01:44 +07:00 committed by Brian Behlendorf
parent 51a3ae72d2
commit 131cc95ca7
5 changed files with 187 additions and 2 deletions

View File

@ -63,6 +63,7 @@ static int zpool_do_destroy(int, char **);
static int zpool_do_add(int, char **); static int zpool_do_add(int, char **);
static int zpool_do_remove(int, char **); static int zpool_do_remove(int, char **);
static int zpool_do_labelclear(int, char **);
static int zpool_do_list(int, char **); static int zpool_do_list(int, char **);
static int zpool_do_iostat(int, char **); static int zpool_do_iostat(int, char **);
@ -123,6 +124,7 @@ typedef enum {
HELP_HISTORY, HELP_HISTORY,
HELP_IMPORT, HELP_IMPORT,
HELP_IOSTAT, HELP_IOSTAT,
HELP_LABELCLEAR,
HELP_LIST, HELP_LIST,
HELP_OFFLINE, HELP_OFFLINE,
HELP_ONLINE, HELP_ONLINE,
@ -162,6 +164,8 @@ static zpool_command_t command_table[] = {
{ "add", zpool_do_add, HELP_ADD }, { "add", zpool_do_add, HELP_ADD },
{ "remove", zpool_do_remove, HELP_REMOVE }, { "remove", zpool_do_remove, HELP_REMOVE },
{ NULL }, { NULL },
{ "labelclear", zpool_do_labelclear, HELP_LABELCLEAR },
{ NULL },
{ "list", zpool_do_list, HELP_LIST }, { "list", zpool_do_list, HELP_LIST },
{ "iostat", zpool_do_iostat, HELP_IOSTAT }, { "iostat", zpool_do_iostat, HELP_IOSTAT },
{ "status", zpool_do_status, HELP_STATUS }, { "status", zpool_do_status, HELP_STATUS },
@ -233,6 +237,8 @@ get_usage(zpool_help_t idx) {
case HELP_IOSTAT: case HELP_IOSTAT:
return (gettext("\tiostat [-v] [-T d|u] [pool] ... [interval " return (gettext("\tiostat [-v] [-T d|u] [pool] ... [interval "
"[count]]\n")); "[count]]\n"));
case HELP_LABELCLEAR:
return (gettext("\tlabelclear [-f] <vdev>\n"));
case HELP_LIST: case HELP_LIST:
return (gettext("\tlist [-H] [-o property[,...]] " return (gettext("\tlist [-H] [-o property[,...]] "
"[-T d|u] [pool] ... [interval [count]]\n")); "[-T d|u] [pool] ... [interval [count]]\n"));
@ -641,6 +647,127 @@ zpool_do_remove(int argc, char **argv)
return (ret); return (ret);
} }
/*
* zpool labelclear <vdev>
*
* Verifies that the vdev is not active and zeros out the label information
* on the device.
*/
int
zpool_do_labelclear(int argc, char **argv)
{
char *vdev, *name;
int c, fd = -1, ret = 0;
pool_state_t state;
boolean_t inuse = B_FALSE;
boolean_t force = B_FALSE;
/* check options */
while ((c = getopt(argc, argv, "f")) != -1) {
switch (c) {
case 'f':
force = B_TRUE;
break;
default:
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
optopt);
usage(B_FALSE);
}
}
argc -= optind;
argv += optind;
/* get vdev name */
if (argc < 1) {
(void) fprintf(stderr, gettext("missing vdev device name\n"));
usage(B_FALSE);
}
vdev = argv[0];
if ((fd = open(vdev, O_RDWR)) < 0) {
(void) fprintf(stderr, gettext("Unable to open %s\n"), vdev);
return (B_FALSE);
}
name = NULL;
if (zpool_in_use(g_zfs, fd, &state, &name, &inuse) != 0) {
if (force)
goto wipe_label;
(void) fprintf(stderr,
gettext("Unable to determine pool state for %s\n"
"Use -f to force the clearing any label data\n"), vdev);
return (1);
}
if (inuse) {
switch (state) {
default:
case POOL_STATE_ACTIVE:
case POOL_STATE_SPARE:
case POOL_STATE_L2CACHE:
(void) fprintf(stderr,
gettext("labelclear operation failed.\n"
"\tVdev %s is a member (%s), of pool \"%s\".\n"
"\tTo remove label information from this device, "
"export or destroy\n\tthe pool, or remove %s from "
"the configuration of this pool\n\tand retry the "
"labelclear operation.\n"),
vdev, zpool_pool_state_to_name(state), name, vdev);
ret = 1;
goto errout;
case POOL_STATE_EXPORTED:
if (force)
break;
(void) fprintf(stderr,
gettext("labelclear operation failed.\n\tVdev "
"%s is a member of the exported pool \"%s\".\n"
"\tUse \"zpool labelclear -f %s\" to force the "
"removal of label\n\tinformation.\n"),
vdev, name, vdev);
ret = 1;
goto errout;
case POOL_STATE_POTENTIALLY_ACTIVE:
if (force)
break;
(void) fprintf(stderr,
gettext("labelclear operation failed.\n"
"\tVdev %s is a member of the pool \"%s\".\n"
"\tThis pool is unknown to this system, but may "
"be active on\n\tanother system. Use "
"\'zpool labelclear -f %s\' to force the\n"
"\tremoval of label information.\n"),
vdev, name, vdev);
ret = 1;
goto errout;
case POOL_STATE_DESTROYED:
/* inuse should never be set for a destroyed pool... */
break;
}
}
wipe_label:
if (zpool_clear_label(fd) != 0) {
(void) fprintf(stderr,
gettext("Label clear failed on vdev %s\n"), vdev);
ret = 1;
}
errout:
close(fd);
if (name != NULL)
free(name);
return (ret);
}
/* /*
* zpool create [-fnd] [-o property=value] ... * zpool create [-fnd] [-o property=value] ...
* [-O file-system-property=value] ... * [-O file-system-property=value] ...

View File

@ -212,6 +212,7 @@ extern void zpool_close(zpool_handle_t *);
extern const char *zpool_get_name(zpool_handle_t *); extern const char *zpool_get_name(zpool_handle_t *);
extern int zpool_get_state(zpool_handle_t *); extern int zpool_get_state(zpool_handle_t *);
extern char *zpool_state_to_name(vdev_state_t, vdev_aux_t); extern char *zpool_state_to_name(vdev_state_t, vdev_aux_t);
extern const char *zpool_pool_state_to_name(pool_state_t);
extern void zpool_free_handles(libzfs_handle_t *); extern void zpool_free_handles(libzfs_handle_t *);
/* /*

View File

@ -902,8 +902,8 @@ zpool_read_label(int fd, nvlist_t **config)
/* /*
* Given a file descriptor, clear (zero) the label information. This function * Given a file descriptor, clear (zero) the label information. This function
* is currently only used in the appliance stack as part of the ZFS sysevent * is used in the appliance stack as part of the ZFS sysevent module and
* module. * to implement the "zpool labelclear" command.
*/ */
int int
zpool_clear_label(int fd) zpool_clear_label(int fd)

View File

@ -204,6 +204,36 @@ zpool_state_to_name(vdev_state_t state, vdev_aux_t aux)
return (gettext("UNKNOWN")); return (gettext("UNKNOWN"));
} }
/*
* Map POOL STATE to printed strings.
*/
const char *
zpool_pool_state_to_name(pool_state_t state)
{
switch (state) {
default:
break;
case POOL_STATE_ACTIVE:
return (gettext("ACTIVE"));
case POOL_STATE_EXPORTED:
return (gettext("EXPORTED"));
case POOL_STATE_DESTROYED:
return (gettext("DESTROYED"));
case POOL_STATE_SPARE:
return (gettext("SPARE"));
case POOL_STATE_L2CACHE:
return (gettext("L2CACHE"));
case POOL_STATE_UNINITIALIZED:
return (gettext("UNINITIALIZED"));
case POOL_STATE_UNAVAIL:
return (gettext("UNAVAIL"));
case POOL_STATE_POTENTIALLY_ACTIVE:
return (gettext("POTENTIALLY_ACTIVE"));
}
return (gettext("UNKNOWN"));
}
/* /*
* Get a zpool property value for 'prop' and return the value in * Get a zpool property value for 'prop' and return the value in
* a pre-allocated buffer. * a pre-allocated buffer.

View File

@ -92,6 +92,11 @@ zpool \- configures ZFS storage pools
\fBzpool iostat\fR [\fB-T\fR u | d ] [\fB-v\fR] [\fIpool\fR] ... [\fIinterval\fR[\fIcount\fR]] \fBzpool iostat\fR [\fB-T\fR u | d ] [\fB-v\fR] [\fIpool\fR] ... [\fIinterval\fR[\fIcount\fR]]
.fi .fi
.LP
.nf
\fBzpool labelclear\fR [\fB-f\fR] \fIdevice\fR
.fi
.LP .LP
.nf .nf
\fBzpool list\fR [\fB-Hv\fR] [\fB-o\fR \fIproperty\fR[,...]] [\fIpool\fR] ... \fBzpool list\fR [\fB-Hv\fR] [\fB-o\fR \fIproperty\fR[,...]] [\fIpool\fR] ...
@ -1426,6 +1431,28 @@ Verbose statistics. Reports usage statistics for individual \fIvdevs\fR within t
.RE .RE
.sp
.ne 2
.mk
.na
\fB\fBzpool labelclear\fR [\fB-f\fR] \fIdevice\fR
.ad
.sp .6
.RS 4n
Removes ZFS label information from the specified device. The device must not be part of an active pool configuration.
.sp
.ne 2
.mk
.na
\fB\fB-f\fR\fR
.ad
.RS 12n
.rt
Treat exported or foreign devices as inactive.
.RE
.RE
.sp .sp
.ne 2 .ne 2
.mk .mk