aboutsummaryrefslogtreecommitdiffstats
path: root/lib/libzfs/libzfs_pool.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libzfs/libzfs_pool.c')
-rw-r--r--lib/libzfs/libzfs_pool.c226
1 files changed, 223 insertions, 3 deletions
diff --git a/lib/libzfs/libzfs_pool.c b/lib/libzfs/libzfs_pool.c
index e2a67c6a7..eca1dc36a 100644
--- a/lib/libzfs/libzfs_pool.c
+++ b/lib/libzfs/libzfs_pool.c
@@ -45,6 +45,7 @@
#include "zfs_prop.h"
#include "libzfs_impl.h"
#include "zfs_comutil.h"
+#include "zfeature_common.h"
static int read_efi_label(nvlist_t *config, diskaddr_t *sb);
@@ -273,6 +274,7 @@ zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len,
case ZPOOL_PROP_SIZE:
case ZPOOL_PROP_ALLOCATED:
case ZPOOL_PROP_FREE:
+ case ZPOOL_PROP_FREEING:
case ZPOOL_PROP_EXPANDSZ:
case ZPOOL_PROP_ASHIFT:
(void) zfs_nicenum(intval, buf, len);
@@ -299,6 +301,12 @@ zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len,
(void) strlcpy(buf, zpool_state_to_name(intval,
vs->vs_aux), len);
break;
+ case ZPOOL_PROP_VERSION:
+ if (intval >= SPA_VERSION_FEATURES) {
+ (void) snprintf(buf, len, "-");
+ break;
+ }
+ /* FALLTHROUGH */
default:
(void) snprintf(buf, len, "%llu", (u_longlong_t)intval);
}
@@ -403,10 +411,48 @@ zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname,
while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
const char *propname = nvpair_name(elem);
+ prop = zpool_name_to_prop(propname);
+ if (prop == ZPROP_INVAL && zpool_prop_feature(propname)) {
+ int err;
+ zfeature_info_t *feature;
+ char *fname = strchr(propname, '@') + 1;
+
+ err = zfeature_lookup_name(fname, &feature);
+ if (err != 0) {
+ ASSERT3U(err, ==, ENOENT);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "invalid feature '%s'"), fname);
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ goto error;
+ }
+
+ if (nvpair_type(elem) != DATA_TYPE_STRING) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' must be a string"), propname);
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ goto error;
+ }
+
+ (void) nvpair_value_string(elem, &strval);
+ if (strcmp(strval, ZFS_FEATURE_ENABLED) != 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "property '%s' can only be set to "
+ "'enabled'"), propname);
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ goto error;
+ }
+
+ if (nvlist_add_uint64(retprops, propname, 0) != 0) {
+ (void) no_memory(hdl);
+ goto error;
+ }
+ continue;
+ }
+
/*
* Make sure this property is valid and applies to this type.
*/
- if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) {
+ if (prop == ZPROP_INVAL) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"invalid property '%s'"), propname);
(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
@@ -431,7 +477,8 @@ zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname,
default:
break;
case ZPOOL_PROP_VERSION:
- if (intval < version || intval > SPA_VERSION) {
+ if (intval < version ||
+ !SPA_VERSION_IS_SUPPORTED(intval)) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"property '%s' number %d is invalid."),
propname, intval);
@@ -673,10 +720,79 @@ zpool_expand_proplist(zpool_handle_t *zhp, zprop_list_t **plp)
libzfs_handle_t *hdl = zhp->zpool_hdl;
zprop_list_t *entry;
char buf[ZFS_MAXPROPLEN];
+ nvlist_t *features = NULL;
+ nvpair_t *nvp;
+ zprop_list_t **last;
+ boolean_t firstexpand = (NULL == *plp);
+ int i;
if (zprop_expand_list(hdl, plp, ZFS_TYPE_POOL) != 0)
return (-1);
+ last = plp;
+ while (*last != NULL)
+ last = &(*last)->pl_next;
+
+ if ((*plp)->pl_all)
+ features = zpool_get_features(zhp);
+
+ if ((*plp)->pl_all && firstexpand) {
+ for (i = 0; i < SPA_FEATURES; i++) {
+ zprop_list_t *entry = zfs_alloc(hdl,
+ sizeof (zprop_list_t));
+ entry->pl_prop = ZPROP_INVAL;
+ entry->pl_user_prop = zfs_asprintf(hdl, "feature@%s",
+ spa_feature_table[i].fi_uname);
+ entry->pl_width = strlen(entry->pl_user_prop);
+ entry->pl_all = B_TRUE;
+
+ *last = entry;
+ last = &entry->pl_next;
+ }
+ }
+
+ /* add any unsupported features */
+ for (nvp = nvlist_next_nvpair(features, NULL);
+ nvp != NULL; nvp = nvlist_next_nvpair(features, nvp)) {
+ char *propname;
+ boolean_t found;
+ zprop_list_t *entry;
+
+ if (zfeature_is_supported(nvpair_name(nvp)))
+ continue;
+
+ propname = zfs_asprintf(hdl, "unsupported@%s",
+ nvpair_name(nvp));
+
+ /*
+ * Before adding the property to the list make sure that no
+ * other pool already added the same property.
+ */
+ found = B_FALSE;
+ entry = *plp;
+ while (entry != NULL) {
+ if (entry->pl_user_prop != NULL &&
+ strcmp(propname, entry->pl_user_prop) == 0) {
+ found = B_TRUE;
+ break;
+ }
+ entry = entry->pl_next;
+ }
+ if (found) {
+ free(propname);
+ continue;
+ }
+
+ entry = zfs_alloc(hdl, sizeof (zprop_list_t));
+ entry->pl_prop = ZPROP_INVAL;
+ entry->pl_user_prop = propname;
+ entry->pl_width = strlen(entry->pl_user_prop);
+ entry->pl_all = B_TRUE;
+
+ *last = entry;
+ last = &entry->pl_next;
+ }
+
for (entry = *plp; entry != NULL; entry = entry->pl_next) {
if (entry->pl_fixed)
@@ -693,6 +809,66 @@ zpool_expand_proplist(zpool_handle_t *zhp, zprop_list_t **plp)
return (0);
}
+/*
+ * Get the state for the given feature on the given ZFS pool.
+ */
+int
+zpool_prop_get_feature(zpool_handle_t *zhp, const char *propname, char *buf,
+ size_t len)
+{
+ uint64_t refcount;
+ boolean_t found = B_FALSE;
+ nvlist_t *features = zpool_get_features(zhp);
+ boolean_t supported;
+ const char *feature = strchr(propname, '@') + 1;
+
+ supported = zpool_prop_feature(propname);
+ ASSERT(supported || zpool_prop_unsupported(propname));
+
+ /*
+ * Convert from feature name to feature guid. This conversion is
+ * unecessary for unsupported@... properties because they already
+ * use guids.
+ */
+ if (supported) {
+ int ret;
+ zfeature_info_t *fi;
+
+ ret = zfeature_lookup_name(feature, &fi);
+ if (ret != 0) {
+ (void) strlcpy(buf, "-", len);
+ return (ENOTSUP);
+ }
+ feature = fi->fi_guid;
+ }
+
+ if (nvlist_lookup_uint64(features, feature, &refcount) == 0)
+ found = B_TRUE;
+
+ if (supported) {
+ if (!found) {
+ (void) strlcpy(buf, ZFS_FEATURE_DISABLED, len);
+ } else {
+ if (refcount == 0)
+ (void) strlcpy(buf, ZFS_FEATURE_ENABLED, len);
+ else
+ (void) strlcpy(buf, ZFS_FEATURE_ACTIVE, len);
+ }
+ } else {
+ if (found) {
+ if (refcount == 0) {
+ (void) strcpy(buf, ZFS_UNSUPPORTED_INACTIVE);
+ } else {
+ (void) strcpy(buf, ZFS_UNSUPPORTED_READONLY);
+ }
+ } else {
+ (void) strlcpy(buf, "-", len);
+ return (ENOTSUP);
+ }
+ }
+
+ return (0);
+}
/*
* Don't start the slice at the default block of 34; many storage
@@ -1291,8 +1467,10 @@ zpool_rewind_exclaim(libzfs_handle_t *hdl, const char *name, boolean_t dryrun,
if (!hdl->libzfs_printerr || config == NULL)
return;
- if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO, &nv) != 0)
+ if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO, &nv) != 0 ||
+ nvlist_lookup_nvlist(nv, ZPOOL_CONFIG_REWIND_INFO, &nv) != 0) {
return;
+ }
if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_LOAD_TIME, &rewindto) != 0)
return;
@@ -1349,6 +1527,7 @@ zpool_explain_recover(libzfs_handle_t *hdl, const char *name, int reason,
/* All attempted rewinds failed if ZPOOL_CONFIG_LOAD_TIME missing */
if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO, &nv) != 0 ||
+ nvlist_lookup_nvlist(nv, ZPOOL_CONFIG_REWIND_INFO, &nv) != 0 ||
nvlist_lookup_uint64(nv, ZPOOL_CONFIG_LOAD_TIME, &rewindto) != 0)
goto no_info;
@@ -1473,6 +1652,31 @@ print_vdev_tree(libzfs_handle_t *hdl, const char *name, nvlist_t *nv,
}
}
+void
+zpool_print_unsup_feat(nvlist_t *config)
+{
+ nvlist_t *nvinfo, *unsup_feat;
+ nvpair_t *nvp;
+
+ verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO, &nvinfo) ==
+ 0);
+ verify(nvlist_lookup_nvlist(nvinfo, ZPOOL_CONFIG_UNSUP_FEAT,
+ &unsup_feat) == 0);
+
+ for (nvp = nvlist_next_nvpair(unsup_feat, NULL); nvp != NULL;
+ nvp = nvlist_next_nvpair(unsup_feat, nvp)) {
+ char *desc;
+
+ verify(nvpair_type(nvp) == DATA_TYPE_STRING);
+ verify(nvpair_value_string(nvp, &desc) == 0);
+
+ if (strlen(desc) > 0)
+ (void) printf("\t%s (%s)\n", nvpair_name(nvp), desc);
+ else
+ (void) printf("\t%s\n", nvpair_name(nvp));
+ }
+}
+
/*
* Import the given pool using the known configuration and a list of
* properties to be set. The configuration should have come from
@@ -1579,6 +1783,22 @@ zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname,
switch (error) {
case ENOTSUP:
+ if (nv != NULL && nvlist_lookup_nvlist(nv,
+ ZPOOL_CONFIG_LOAD_INFO, &nvinfo) == 0 &&
+ nvlist_exists(nvinfo, ZPOOL_CONFIG_UNSUP_FEAT)) {
+ (void) printf(dgettext(TEXT_DOMAIN, "This "
+ "pool uses the following feature(s) not "
+ "supported by this system:\n"));
+ zpool_print_unsup_feat(nv);
+ if (nvlist_exists(nvinfo,
+ ZPOOL_CONFIG_CAN_RDONLY)) {
+ (void) printf(dgettext(TEXT_DOMAIN,
+ "All unsupported features are only "
+ "required for writing to the pool."
+ "\nThe pool can be imported using "
+ "'-o readonly=on'.\n"));
+ }
+ }
/*
* Unsupported version.
*/