diff --git a/cmd/zpool/zpool_main.c b/cmd/zpool/zpool_main.c index 19f1f28a9..da9f3e1a3 100644 --- a/cmd/zpool/zpool_main.c +++ b/cmd/zpool/zpool_main.c @@ -63,6 +63,7 @@ static int zpool_do_destroy(int, char **); static int zpool_do_add(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_iostat(int, char **); @@ -123,6 +124,7 @@ typedef enum { HELP_HISTORY, HELP_IMPORT, HELP_IOSTAT, + HELP_LABELCLEAR, HELP_LIST, HELP_OFFLINE, HELP_ONLINE, @@ -162,6 +164,8 @@ static zpool_command_t command_table[] = { { "add", zpool_do_add, HELP_ADD }, { "remove", zpool_do_remove, HELP_REMOVE }, { NULL }, + { "labelclear", zpool_do_labelclear, HELP_LABELCLEAR }, + { NULL }, { "list", zpool_do_list, HELP_LIST }, { "iostat", zpool_do_iostat, HELP_IOSTAT }, { "status", zpool_do_status, HELP_STATUS }, @@ -233,6 +237,8 @@ get_usage(zpool_help_t idx) { case HELP_IOSTAT: return (gettext("\tiostat [-v] [-T d|u] [pool] ... [interval " "[count]]\n")); + case HELP_LABELCLEAR: + return (gettext("\tlabelclear [-f] \n")); case HELP_LIST: return (gettext("\tlist [-H] [-o property[,...]] " "[-T d|u] [pool] ... [interval [count]]\n")); @@ -641,6 +647,127 @@ zpool_do_remove(int argc, char **argv) return (ret); } +/* + * zpool labelclear + * + * 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] ... * [-O file-system-property=value] ... diff --git a/include/libzfs.h b/include/libzfs.h index 82cb66ab5..3472b7699 100644 --- a/include/libzfs.h +++ b/include/libzfs.h @@ -212,6 +212,7 @@ extern void zpool_close(zpool_handle_t *); extern const char *zpool_get_name(zpool_handle_t *); extern int zpool_get_state(zpool_handle_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 *); /* diff --git a/lib/libzfs/libzfs_import.c b/lib/libzfs/libzfs_import.c index 58b6043be..de9851e60 100644 --- a/lib/libzfs/libzfs_import.c +++ b/lib/libzfs/libzfs_import.c @@ -902,8 +902,8 @@ zpool_read_label(int fd, nvlist_t **config) /* * 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 - * module. + * is used in the appliance stack as part of the ZFS sysevent module and + * to implement the "zpool labelclear" command. */ int zpool_clear_label(int fd) diff --git a/lib/libzfs/libzfs_pool.c b/lib/libzfs/libzfs_pool.c index eca1dc36a..a6cacd370 100644 --- a/lib/libzfs/libzfs_pool.c +++ b/lib/libzfs/libzfs_pool.c @@ -204,6 +204,36 @@ zpool_state_to_name(vdev_state_t state, vdev_aux_t aux) 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 * a pre-allocated buffer. diff --git a/man/man8/zpool.8 b/man/man8/zpool.8 index 388c89da9..c1ee0d5de 100644 --- a/man/man8/zpool.8 +++ b/man/man8/zpool.8 @@ -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]] .fi +.LP +.nf +\fBzpool labelclear\fR [\fB-f\fR] \fIdevice\fR +.fi + .LP .nf \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 +.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 .ne 2 .mk