]> git.proxmox.com Git - mirror_zfs-debian.git/commitdiff
Illumos #3349: zpool upgrade -V bumps the on disk version number
authorGeorge Wilson <george.wilson@delphix.com>
Sat, 15 Dec 2012 00:28:49 +0000 (16:28 -0800)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Tue, 8 Jan 2013 18:35:43 +0000 (10:35 -0800)
3349 zpool upgrade -V bumps the on disk version number, but leaves
the in core version
Reviewed by: Adam Leventhal <ahl@delphix.com>
Reviewed by: Christopher Siden <chris.siden@delphix.com>
Reviewed by: Matt Ahrens <matthew.ahrens@delphix.com>
Reviewed by: Richard Lowe <richlowe@richlowe.net>
Approved by: Dan McDonald <danmcd@nexenta.com>

References:
  illumos/illumos-gate@25345e466695fbe736faa53b8f3413d8e8f81981
  https://www.illumos.org/issues/3349

Ported-by: Brian Behlendorf <behlendorf1@llnl.gov>
cmd/ztest/ztest.c
module/zfs/spa.c

index 6df0812c62408099341e149224b5f4a6a7eeb94d..c9fdf466f5488804fc50722737d946d90affe74f 100644 (file)
@@ -331,6 +331,7 @@ ztest_func_t ztest_vdev_add_remove;
 ztest_func_t ztest_vdev_aux_add_remove;
 ztest_func_t ztest_split_pool;
 ztest_func_t ztest_reguid;
+ztest_func_t ztest_spa_upgrade;
 
 uint64_t zopt_always = 0ULL * NANOSEC;         /* all the time */
 uint64_t zopt_incessant = 1ULL * NANOSEC / 10; /* every 1/10 second */
@@ -364,6 +365,7 @@ ztest_info_t ztest_info[] = {
        { ztest_reguid,                         1,      &zopt_sometimes },
        { ztest_spa_rename,                     1,      &zopt_rarely    },
        { ztest_scrub,                          1,      &zopt_rarely    },
+       { ztest_spa_upgrade,                    1,      &zopt_rarely    },
        { ztest_dsl_dataset_promote_busy,       1,      &zopt_rarely    },
        { ztest_vdev_attach_detach,             1,      &zopt_rarely    },
        { ztest_vdev_LUN_growth,                1,      &zopt_rarely    },
@@ -818,7 +820,7 @@ ztest_get_ashift(void)
 }
 
 static nvlist_t *
-make_vdev_file(char *path, char *aux, size_t size, uint64_t ashift)
+make_vdev_file(char *path, char *aux, char *pool, size_t size, uint64_t ashift)
 {
        char *pathbuf;
        uint64_t vdev;
@@ -836,12 +838,13 @@ make_vdev_file(char *path, char *aux, size_t size, uint64_t ashift)
                        vdev = ztest_shared->zs_vdev_aux;
                        (void) snprintf(path, MAXPATHLEN,
                            ztest_aux_template, ztest_opts.zo_dir,
-                           ztest_opts.zo_pool, aux, vdev);
+                           pool == NULL ? ztest_opts.zo_pool : pool,
+                           aux, vdev);
                } else {
                        vdev = ztest_shared->zs_vdev_next_leaf++;
                        (void) snprintf(path, MAXPATHLEN,
                            ztest_dev_template, ztest_opts.zo_dir,
-                           ztest_opts.zo_pool, vdev);
+                           pool == NULL ? ztest_opts.zo_pool : pool, vdev);
                }
        }
 
@@ -864,17 +867,18 @@ make_vdev_file(char *path, char *aux, size_t size, uint64_t ashift)
 }
 
 static nvlist_t *
-make_vdev_raidz(char *path, char *aux, size_t size, uint64_t ashift, int r)
+make_vdev_raidz(char *path, char *aux, char *pool, size_t size,
+    uint64_t ashift, int r)
 {
        nvlist_t *raidz, **child;
        int c;
 
        if (r < 2)
-               return (make_vdev_file(path, aux, size, ashift));
+               return (make_vdev_file(path, aux, pool, size, ashift));
        child = umem_alloc(r * sizeof (nvlist_t *), UMEM_NOFAIL);
 
        for (c = 0; c < r; c++)
-               child[c] = make_vdev_file(path, aux, size, ashift);
+               child[c] = make_vdev_file(path, aux, pool, size, ashift);
 
        VERIFY(nvlist_alloc(&raidz, NV_UNIQUE_NAME, 0) == 0);
        VERIFY(nvlist_add_string(raidz, ZPOOL_CONFIG_TYPE,
@@ -893,19 +897,19 @@ make_vdev_raidz(char *path, char *aux, size_t size, uint64_t ashift, int r)
 }
 
 static nvlist_t *
-make_vdev_mirror(char *path, char *aux, size_t size, uint64_t ashift,
-       int r, int m)
+make_vdev_mirror(char *path, char *aux, char *pool, size_t size,
+    uint64_t ashift, int r, int m)
 {
        nvlist_t *mirror, **child;
        int c;
 
        if (m < 1)
-               return (make_vdev_raidz(path, aux, size, ashift, r));
+               return (make_vdev_raidz(path, aux, pool, size, ashift, r));
 
        child = umem_alloc(m * sizeof (nvlist_t *), UMEM_NOFAIL);
 
        for (c = 0; c < m; c++)
-               child[c] = make_vdev_raidz(path, aux, size, ashift, r);
+               child[c] = make_vdev_raidz(path, aux, pool, size, ashift, r);
 
        VERIFY(nvlist_alloc(&mirror, NV_UNIQUE_NAME, 0) == 0);
        VERIFY(nvlist_add_string(mirror, ZPOOL_CONFIG_TYPE,
@@ -922,8 +926,8 @@ make_vdev_mirror(char *path, char *aux, size_t size, uint64_t ashift,
 }
 
 static nvlist_t *
-make_vdev_root(char *path, char *aux, size_t size, uint64_t ashift,
-       int log, int r, int m, int t)
+make_vdev_root(char *path, char *aux, char *pool, size_t size, uint64_t ashift,
+    int log, int r, int m, int t)
 {
        nvlist_t *root, **child;
        int c;
@@ -933,7 +937,8 @@ make_vdev_root(char *path, char *aux, size_t size, uint64_t ashift,
        child = umem_alloc(t * sizeof (nvlist_t *), UMEM_NOFAIL);
 
        for (c = 0; c < t; c++) {
-               child[c] = make_vdev_mirror(path, aux, size, ashift, r, m);
+               child[c] = make_vdev_mirror(path, aux, pool, size, ashift,
+                   r, m);
                VERIFY(nvlist_add_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
                    log) == 0);
        }
@@ -951,6 +956,27 @@ make_vdev_root(char *path, char *aux, size_t size, uint64_t ashift,
        return (root);
 }
 
+/*
+ * Find a random spa version. Returns back a random spa version in the
+ * range [initial_version, SPA_VERSION_FEATURES].
+ */
+static uint64_t
+ztest_random_spa_version(uint64_t initial_version)
+{
+       uint64_t version = initial_version;
+
+       if (version <= SPA_VERSION_BEFORE_FEATURES) {
+               version = version +
+                   ztest_random(SPA_VERSION_BEFORE_FEATURES - version + 1);
+       }
+
+       if (version > SPA_VERSION_BEFORE_FEATURES)
+               version = SPA_VERSION_FEATURES;
+
+       ASSERT(SPA_VERSION_IS_SUPPORTED(version));
+       return (version);
+}
+
 static int
 ztest_random_blocksize(void)
 {
@@ -2306,7 +2332,7 @@ ztest_spa_create_destroy(ztest_ds_t *zd, uint64_t id)
        /*
         * Attempt to create using a bad file.
         */
-       nvroot = make_vdev_root("/dev/bogus", NULL, 0, 0, 0, 0, 0, 1);
+       nvroot = make_vdev_root("/dev/bogus", NULL, NULL, 0, 0, 0, 0, 0, 1);
        VERIFY3U(ENOENT, ==,
            spa_create("ztest_bad_file", nvroot, NULL, NULL, NULL));
        nvlist_free(nvroot);
@@ -2314,7 +2340,7 @@ ztest_spa_create_destroy(ztest_ds_t *zd, uint64_t id)
        /*
         * Attempt to create using a bad mirror.
         */
-       nvroot = make_vdev_root("/dev/bogus", NULL, 0, 0, 0, 0, 2, 1);
+       nvroot = make_vdev_root("/dev/bogus", NULL, NULL, 0, 0, 0, 0, 2, 1);
        VERIFY3U(ENOENT, ==,
            spa_create("ztest_bad_mirror", nvroot, NULL, NULL, NULL));
        nvlist_free(nvroot);
@@ -2324,7 +2350,7 @@ ztest_spa_create_destroy(ztest_ds_t *zd, uint64_t id)
         * what's in the nvroot; we should fail with EEXIST.
         */
        (void) rw_enter(&ztest_name_lock, RW_READER);
-       nvroot = make_vdev_root("/dev/bogus", NULL, 0, 0, 0, 0, 0, 1);
+       nvroot = make_vdev_root("/dev/bogus", NULL, NULL, 0, 0, 0, 0, 0, 1);
        VERIFY3U(EEXIST, ==, spa_create(zo->zo_pool, nvroot, NULL, NULL, NULL));
        nvlist_free(nvroot);
        VERIFY3U(0, ==, spa_open(zo->zo_pool, &spa, FTAG));
@@ -2334,6 +2360,78 @@ ztest_spa_create_destroy(ztest_ds_t *zd, uint64_t id)
        (void) rw_exit(&ztest_name_lock);
 }
 
+/* ARGSUSED */
+void
+ztest_spa_upgrade(ztest_ds_t *zd, uint64_t id)
+{
+       spa_t *spa;
+       uint64_t initial_version = SPA_VERSION_INITIAL;
+       uint64_t version, newversion;
+       nvlist_t *nvroot, *props;
+       char *name;
+
+       mutex_enter(&ztest_vdev_lock);
+       name = kmem_asprintf("%s_upgrade", ztest_opts.zo_pool);
+
+       /*
+        * Clean up from previous runs.
+        */
+       (void) spa_destroy(name);
+
+       nvroot = make_vdev_root(NULL, NULL, name, ztest_opts.zo_vdev_size, 0,
+           0, ztest_opts.zo_raidz, ztest_opts.zo_mirrors, 1);
+
+       /*
+        * If we're configuring a RAIDZ device then make sure that the
+        * the initial version is capable of supporting that feature.
+        */
+       switch (ztest_opts.zo_raidz_parity) {
+       case 0:
+       case 1:
+               initial_version = SPA_VERSION_INITIAL;
+               break;
+       case 2:
+               initial_version = SPA_VERSION_RAIDZ2;
+               break;
+       case 3:
+               initial_version = SPA_VERSION_RAIDZ3;
+               break;
+       }
+
+       /*
+        * Create a pool with a spa version that can be upgraded. Pick
+        * a value between initial_version and SPA_VERSION_BEFORE_FEATURES.
+        */
+       do {
+               version = ztest_random_spa_version(initial_version);
+       } while (version > SPA_VERSION_BEFORE_FEATURES);
+
+       props = fnvlist_alloc();
+       fnvlist_add_uint64(props,
+           zpool_prop_to_name(ZPOOL_PROP_VERSION), version);
+       VERIFY3S(spa_create(name, nvroot, props, NULL, NULL), ==, 0);
+       fnvlist_free(nvroot);
+       fnvlist_free(props);
+
+       VERIFY3S(spa_open(name, &spa, FTAG), ==, 0);
+       VERIFY3U(spa_version(spa), ==, version);
+       newversion = ztest_random_spa_version(version + 1);
+
+       if (ztest_opts.zo_verbose >= 4) {
+               (void) printf("upgrading spa version from %llu to %llu\n",
+                   (u_longlong_t)version, (u_longlong_t)newversion);
+       }
+
+       spa_upgrade(spa, newversion);
+       VERIFY3U(spa_version(spa), >, version);
+       VERIFY3U(spa_version(spa), ==, fnvlist_lookup_uint64(spa->spa_config,
+           zpool_prop_to_name(ZPOOL_PROP_VERSION)));
+       spa_close(spa, FTAG);
+
+       strfree(name);
+       mutex_exit(&ztest_vdev_lock);
+}
+
 static vdev_t *
 vdev_lookup_by_path(vdev_t *vd, const char *path)
 {
@@ -2424,7 +2522,7 @@ ztest_vdev_add_remove(ztest_ds_t *zd, uint64_t id)
                /*
                 * Make 1/4 of the devices be log devices.
                 */
-               nvroot = make_vdev_root(NULL, NULL,
+               nvroot = make_vdev_root(NULL, NULL, NULL,
                    ztest_opts.zo_vdev_size, 0,
                    ztest_random(4) == 0, ztest_opts.zo_raidz,
                    zs->zs_mirrors, 1);
@@ -2503,7 +2601,7 @@ ztest_vdev_aux_add_remove(ztest_ds_t *zd, uint64_t id)
                /*
                 * Add a new device.
                 */
-               nvlist_t *nvroot = make_vdev_root(NULL, aux,
+               nvlist_t *nvroot = make_vdev_root(NULL, aux, NULL,
                    (ztest_opts.zo_vdev_size * 5) / 4, 0, 0, 0, 0, 1);
                error = spa_vdev_add(spa, nvroot);
                if (error != 0)
@@ -2776,7 +2874,7 @@ ztest_vdev_attach_detach(ztest_ds_t *zd, uint64_t id)
        /*
         * Build the nvlist describing newpath.
         */
-       root = make_vdev_root(newpath, NULL, newvd == NULL ? newsize : 0,
+       root = make_vdev_root(newpath, NULL, NULL, newvd == NULL ? newsize : 0,
            ashift, 0, 0, 0, 1);
 
        error = spa_vdev_attach(spa, oldguid, root, replacing);
@@ -5055,7 +5153,7 @@ ztest_reguid(ztest_ds_t *zd, uint64_t id)
        if (error != 0)
                return;
 
-       if (ztest_opts.zo_verbose >= 3) {
+       if (ztest_opts.zo_verbose >= 4) {
                (void) printf("Changed guid old %llu -> %llu\n",
                    (u_longlong_t)orig, (u_longlong_t)spa_guid(spa));
        }
@@ -5819,7 +5917,7 @@ ztest_init(ztest_shared_t *zs)
        ztest_shared->zs_vdev_next_leaf = 0;
        zs->zs_splits = 0;
        zs->zs_mirrors = ztest_opts.zo_mirrors;
-       nvroot = make_vdev_root(NULL, NULL, ztest_opts.zo_vdev_size, 0,
+       nvroot = make_vdev_root(NULL, NULL, NULL, ztest_opts.zo_vdev_size, 0,
            0, ztest_opts.zo_raidz, zs->zs_mirrors, 1);
        props = make_random_props();
        for (i = 0; i < SPA_FEATURES; i++) {
index 0a785f78a6cb51e7665d9fd80a59b7578699685c..5b6465f2ebb0a042c07008697e0e385f0b59f3f1 100644 (file)
@@ -5742,6 +5742,14 @@ spa_sync_config_object(spa_t *spa, dmu_tx_t *tx)
        config = spa_config_generate(spa, spa->spa_root_vdev,
            dmu_tx_get_txg(tx), B_FALSE);
 
+       /*
+        * If we're upgrading the spa version then make sure that
+        * the config object gets updated with the correct version.
+        */
+       if (spa->spa_ubsync.ub_version < spa->spa_uberblock.ub_version)
+               fnvlist_add_uint64(config, ZPOOL_CONFIG_VERSION,
+                   spa->spa_uberblock.ub_version);
+
        spa_config_exit(spa, SCL_STATE, FTAG);
 
        if (spa->spa_config_syncing)