]> git.proxmox.com Git - mirror_zfs.git/blobdiff - lib/libzfs/libzfs_pool.c
Add 'zpool split' coverage to the ZFS Test Suite
[mirror_zfs.git] / lib / libzfs / libzfs_pool.c
index aa77b547aebabf935b80ab7780381a817e546832..3fe0b9e0ee44c6968e1c0be1bc286eca1d6c2327 100644 (file)
@@ -53,6 +53,7 @@
 #include "zfeature_common.h"
 
 static int read_efi_label(nvlist_t *config, diskaddr_t *sb);
+static boolean_t zpool_vdev_is_interior(const char *name);
 
 typedef struct prop_flags {
        int create:1;   /* Validate property on creation */
@@ -112,7 +113,7 @@ zpool_props_refresh(zpool_handle_t *zhp)
        return (0);
 }
 
-static char *
+static const char *
 zpool_get_prop_string(zpool_handle_t *zhp, zpool_prop_t prop,
     zprop_source_t *src)
 {
@@ -180,7 +181,7 @@ zpool_get_prop_int(zpool_handle_t *zhp, zpool_prop_t prop, zprop_source_t *src)
 /*
  * Map VDEV STATE to printed strings.
  */
-char *
+const char *
 zpool_state_to_name(vdev_state_t state, vdev_aux_t aux)
 {
        switch (state) {
@@ -409,6 +410,8 @@ static boolean_t
 bootfs_name_valid(const char *pool, char *bootfs)
 {
        int len = strlen(pool);
+       if (bootfs[0] == '\0')
+               return (B_TRUE);
 
        if (!zfs_name_valid(bootfs, ZFS_TYPE_FILESYSTEM|ZFS_TYPE_SNAPSHOT))
                return (B_FALSE);
@@ -459,7 +462,7 @@ zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname,
                const char *propname = nvpair_name(elem);
 
                prop = zpool_name_to_prop(propname);
-               if (prop == ZPROP_INVAL && zpool_prop_feature(propname)) {
+               if (prop == ZPOOL_PROP_INVAL && zpool_prop_feature(propname)) {
                        int err;
                        char *fname = strchr(propname, '@') + 1;
 
@@ -489,6 +492,15 @@ zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname,
                                goto error;
                        }
 
+                       if (!flags.create &&
+                           strcmp(strval, ZFS_FEATURE_DISABLED) == 0) {
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "property '%s' can only be set to "
+                                   "'disabled' at creation time"), propname);
+                               (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+                               goto error;
+                       }
+
                        if (nvlist_add_uint64(retprops, propname, 0) != 0) {
                                (void) no_memory(hdl);
                                goto error;
@@ -499,7 +511,7 @@ zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname,
                /*
                 * Make sure this property is valid and applies to this type.
                 */
-               if (prop == ZPROP_INVAL) {
+               if (prop == ZPOOL_PROP_INVAL) {
                        zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
                            "invalid property '%s'"), propname);
                        (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
@@ -566,8 +578,7 @@ zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname,
                         * bootfs property value has to be a dataset name and
                         * the dataset has to be in the same pool as it sets to.
                         */
-                       if (strval[0] != '\0' && !bootfs_name_valid(poolname,
-                           strval)) {
+                       if (!bootfs_name_valid(poolname, strval)) {
                                zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' "
                                    "is an invalid name"), strval);
                                (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf);
@@ -2131,10 +2142,7 @@ vdev_to_nvlist_iter(nvlist_t *nv, nvlist_t *search, boolean_t *avail_spare,
                                break;
                        }
 
-                       verify(strncmp(type, VDEV_TYPE_RAIDZ,
-                           strlen(VDEV_TYPE_RAIDZ)) == 0 ||
-                           strncmp(type, VDEV_TYPE_MIRROR,
-                           strlen(VDEV_TYPE_MIRROR)) == 0);
+                       verify(zpool_vdev_is_interior(type));
                        verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_ID,
                            &id) == 0);
 
@@ -2241,10 +2249,13 @@ zpool_find_vdev_by_physpath(zpool_handle_t *zhp, const char *ppath,
 /*
  * Determine if we have an "interior" top-level vdev (i.e mirror/raidz).
  */
-boolean_t
+static boolean_t
 zpool_vdev_is_interior(const char *name)
 {
        if (strncmp(name, VDEV_TYPE_RAIDZ, strlen(VDEV_TYPE_RAIDZ)) == 0 ||
+           strncmp(name, VDEV_TYPE_SPARE, strlen(VDEV_TYPE_SPARE)) == 0 ||
+           strncmp(name,
+           VDEV_TYPE_REPLACING, strlen(VDEV_TYPE_REPLACING)) == 0 ||
            strncmp(name, VDEV_TYPE_MIRROR, strlen(VDEV_TYPE_MIRROR)) == 0)
                return (B_TRUE);
        return (B_FALSE);
@@ -2516,6 +2527,7 @@ zpool_vdev_online(zpool_handle_t *zhp, const char *path, int flags,
 {
        zfs_cmd_t zc = {"\0"};
        char msg[1024];
+       char *pathname;
        nvlist_t *tgt;
        boolean_t avail_spare, l2cache, islog;
        libzfs_handle_t *hdl = zhp->zpool_hdl;
@@ -2539,8 +2551,9 @@ zpool_vdev_online(zpool_handle_t *zhp, const char *path, int flags,
        if (avail_spare)
                return (zfs_error(hdl, EZFS_ISSPARE, msg));
 
-       if (flags & ZFS_ONLINE_EXPAND ||
-           zpool_get_prop_int(zhp, ZPOOL_PROP_AUTOEXPAND, NULL)) {
+       if ((flags & ZFS_ONLINE_EXPAND ||
+           zpool_get_prop_int(zhp, ZPOOL_PROP_AUTOEXPAND, NULL)) &&
+           nvlist_lookup_string(tgt, ZPOOL_CONFIG_PATH, &pathname) == 0) {
                uint64_t wholedisk = 0;
 
                (void) nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_WHOLE_DISK,
@@ -3006,7 +3019,7 @@ zpool_vdev_split(zpool_handle_t *zhp, char *newname, nvlist_t **newroot,
        nvlist_t **varray = NULL, *zc_props = NULL;
        uint_t c, children, newchildren, lastlog = 0, vcount, found = 0;
        libzfs_handle_t *hdl = zhp->zpool_hdl;
-       uint64_t vers;
+       uint64_t vers, readonly = B_FALSE;
        boolean_t freelist = B_FALSE, memory_err = B_TRUE;
        int retval = 0;
 
@@ -3031,6 +3044,14 @@ zpool_vdev_split(zpool_handle_t *zhp, char *newname, nvlist_t **newroot,
                if ((zc_props = zpool_valid_proplist(hdl, zhp->zpool_name,
                    props, vers, flags, msg)) == NULL)
                        return (-1);
+               (void) nvlist_lookup_uint64(zc_props,
+                   zpool_prop_to_name(ZPOOL_PROP_READONLY), &readonly);
+               if (readonly) {
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "property %s can only be set at import time"),
+                           zpool_prop_to_name(ZPOOL_PROP_READONLY));
+                       return (-1);
+               }
        }
 
        if (nvlist_lookup_nvlist_array(tree, ZPOOL_CONFIG_CHILDREN, &child,
@@ -3588,6 +3609,14 @@ zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv,
        char buf[PATH_BUF_LEN];
        char tmpbuf[PATH_BUF_LEN];
 
+       /*
+        * vdev_name will be "root"/"root-0" for the root vdev, but it is the
+        * zpool name that will be displayed to the user.
+        */
+       verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
+       if (zhp != NULL && strcmp(type, "root") == 0)
+               return (zfs_strdup(hdl, zpool_get_name(zhp)));
+
        env = getenv("ZPOOL_VDEV_NAME_PATH");
        if (env && (strtoul(env, NULL, 0) > 0 ||
            !strncasecmp(env, "YES", 3) || !strncasecmp(env, "ON", 2)))
@@ -3669,7 +3698,6 @@ zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv,
                /*
                 * For a block device only use the name.
                 */
-               verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
                if ((strcmp(type, VDEV_TYPE_DISK) == 0) &&
                    !(name_flags & VDEV_NAME_PATH)) {
                        path = strrchr(path, '/');
@@ -3684,7 +3712,7 @@ zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv,
                        return (zfs_strip_partition(path));
                }
        } else {
-               verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &path) == 0);
+               path = type;
 
                /*
                 * If it's a raidz device, we need to stick in the parity level.