PSARC 2006/206 zpool upgrade
6399930 want 'zpool upgrade' to control change of version number
6400742 'zpool destroy' not clean inuse tag that have to need '-f' to use them again
--- a/usr/src/cmd/fs.d/zfs/fstyp/fstyp.c Thu Apr 06 19:27:51 2006 -0700
+++ b/usr/src/cmd/fs.d/zfs/fstyp/fstyp.c Thu Apr 06 20:12:27 2006 -0700
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -112,6 +111,7 @@
int c, fd;
int verbose = 0;
nvlist_t *config;
+ uint64_t state;
(void) setlocale(LC_ALL, "");
@@ -145,6 +145,10 @@
if ((config = zpool_read_label(fd)) == NULL)
return (1);
+ if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
+ &state) != 0 || state == POOL_STATE_DESTROYED)
+ return (1);
+
(void) printf("zfs\n");
if (verbose)
--- a/usr/src/cmd/truss/codes.c Thu Apr 06 19:27:51 2006 -0700
+++ b/usr/src/cmd/truss/codes.c Thu Apr 06 20:12:27 2006 -0700
@@ -869,8 +869,6 @@
"zfs_cmd_t" },
{ (uint_t)ZFS_IOC_POOL_CONFIGS, "ZFS_IOC_POOL_CONFIGS",
"zfs_cmd_t" },
- { (uint_t)ZFS_IOC_POOL_GUID, "ZFS_IOC_POOL_GUID",
- "zfs_cmd_t" },
{ (uint_t)ZFS_IOC_POOL_STATS, "ZFS_IOC_POOL_STATS",
"zfs_cmd_t" },
{ (uint_t)ZFS_IOC_POOL_TRYIMPORT, "ZFS_IOC_POOL_TRYIMPORT",
@@ -879,6 +877,8 @@
"zfs_cmd_t" },
{ (uint_t)ZFS_IOC_POOL_FREEZE, "ZFS_IOC_POOL_FREEZE",
"zfs_cmd_t" },
+ { (uint_t)ZFS_IOC_POOL_UPGRADE, "ZFS_IOC_POOL_UPGRADE",
+ "zfs_cmd_t" },
{ (uint_t)ZFS_IOC_VDEV_ADD, "ZFS_IOC_VDEV_ADD",
"zfs_cmd_t" },
{ (uint_t)ZFS_IOC_VDEV_REMOVE, "ZFS_IOC_VDEV_REMOVE",
--- a/usr/src/cmd/zpool/zpool_main.c Thu Apr 06 19:27:51 2006 -0700
+++ b/usr/src/cmd/zpool/zpool_main.c Thu Apr 06 20:12:27 2006 -0700
@@ -69,6 +69,8 @@
static int zpool_do_import(int, char **);
static int zpool_do_export(int, char **);
+static int zpool_do_upgrade(int, char **);
+
/*
* These libumem hooks provide a reasonable set of defaults for the allocator's
* debugging facilities.
@@ -100,7 +102,8 @@
HELP_ONLINE,
HELP_REPLACE,
HELP_SCRUB,
- HELP_STATUS
+ HELP_STATUS,
+ HELP_UPGRADE
} zpool_help_t;
@@ -141,6 +144,7 @@
{ NULL },
{ "import", zpool_do_import, HELP_IMPORT },
{ "export", zpool_do_export, HELP_EXPORT },
+ { "upgrade", zpool_do_upgrade, HELP_UPGRADE }
};
#define NCOMMAND (sizeof (command_table) / sizeof (command_table[0]))
@@ -188,6 +192,10 @@
return (gettext("\tscrub [-s] <pool> ...\n"));
case HELP_STATUS:
return (gettext("\tstatus [-vx] [pool] ...\n"));
+ case HELP_UPGRADE:
+ return (gettext("\tupgrade\n"
+ "\tupgrade -v\n"
+ "\tupgrade <-a | pool>\n"));
}
abort();
@@ -793,6 +801,10 @@
(void) printf(gettext("insufficient replicas"));
break;
+ case VDEV_AUX_VERSION_NEWER:
+ (void) printf(gettext("newer version"));
+ break;
+
default:
(void) printf(gettext("corrupted data"));
break;
@@ -882,6 +894,16 @@
"corrupted.\n"));
break;
+ case ZPOOL_STATUS_VERSION_OLDER:
+ (void) printf(gettext("status: The pool is formatted using an "
+ "older on-disk version.\n"));
+ break;
+
+ case ZPOOL_STATUS_VERSION_NEWER:
+ (void) printf(gettext("status: The pool is formatted using an "
+ "incompatible version.\n"));
+ break;
+
default:
/*
* No other status can be seen when importing pools.
@@ -893,40 +915,48 @@
* Print out an action according to the overall state of the pool.
*/
if (strcmp(health, gettext("ONLINE")) == 0) {
- (void) printf(gettext("action: The pool can be imported"
- " using its name or numeric identifier."));
- if (pool_state == POOL_STATE_DESTROYED)
- (void) printf(gettext(" The\n\tpool was destroyed, "
- "but can be imported using the '-Df' flags.\n"));
- else if (pool_state != POOL_STATE_EXPORTED)
- (void) printf(gettext(" The\n\tpool may be active on "
- "on another system, but can be imported using\n\t"
- "the '-f' flag.\n"));
+ if (reason == ZPOOL_STATUS_VERSION_OLDER)
+ (void) printf(gettext("action: The pool can be "
+ "imported using its name or numeric identifier, "
+ "though\n\tsome features will not be available "
+ "without an explicit 'zpool upgrade'.\n"));
else
- (void) printf("\n");
+ (void) printf(gettext("action: The pool can be "
+ "imported using its name or numeric "
+ "identifier.\n"));
} else if (strcmp(health, gettext("DEGRADED")) == 0) {
(void) printf(gettext("action: The pool can be imported "
"despite missing or damaged devices. The\n\tfault "
- "tolerance of the pool may be compromised if imported."));
- if (pool_state == POOL_STATE_DESTROYED)
- (void) printf(gettext(" The\n\tpool was destroyed, "
- "but can be imported using the '-Df' flags.\n"));
- else if (pool_state != POOL_STATE_EXPORTED)
- (void) printf(gettext(" The\n\tpool may be active on "
- "on another system, but can be imported using\n\t"
- "the '-f' flag.\n"));
- else
- (void) printf("\n");
+ "tolerance of the pool may be compromised if imported.\n"));
} else {
- if (reason == ZPOOL_STATUS_MISSING_DEV_R ||
- reason == ZPOOL_STATUS_MISSING_DEV_NR ||
- reason == ZPOOL_STATUS_BAD_GUID_SUM)
+ switch (reason) {
+ case ZPOOL_STATUS_VERSION_NEWER:
+ (void) printf(gettext("action: The pool cannot be "
+ "imported. Access the pool on a system running "
+ "newer\n\tsoftware, or recreate the pool from "
+ "backup.\n"));
+ break;
+ case ZPOOL_STATUS_MISSING_DEV_R:
+ case ZPOOL_STATUS_MISSING_DEV_NR:
+ case ZPOOL_STATUS_BAD_GUID_SUM:
(void) printf(gettext("action: The pool cannot be "
"imported. Attach the missing\n\tdevices and try "
"again.\n"));
- else
+ break;
+ default:
(void) printf(gettext("action: The pool cannot be "
"imported due to damaged devices or data.\n"));
+ }
+ }
+
+ if (strcmp(health, gettext("FAULTED")) != 0) {
+ if (pool_state == POOL_STATE_DESTROYED)
+ (void) printf(gettext("\tThe pool was destroyed, "
+ "but can be imported using the '-Df' flags.\n"));
+ else if (pool_state != POOL_STATE_EXPORTED)
+ (void) printf(gettext("\tThe pool may be active on "
+ "on another system, but can be imported using\n\t"
+ "the '-f' flag.\n"));
}
if (msgid != NULL)
@@ -959,13 +989,20 @@
zpool_handle_t *zhp;
char *name;
uint64_t state;
+ uint64_t version;
verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
&name) == 0);
verify(nvlist_lookup_uint64(config,
ZPOOL_CONFIG_POOL_STATE, &state) == 0);
- if (state != POOL_STATE_EXPORTED && !force) {
+ verify(nvlist_lookup_uint64(config,
+ ZPOOL_CONFIG_VERSION, &version) == 0);
+ if (version > ZFS_VERSION) {
+ (void) fprintf(stderr, gettext("cannot import '%s': pool "
+ "is formatted using a newer ZFS version\n"), name);
+ return (1);
+ } else if (state != POOL_STATE_EXPORTED && !force) {
(void) fprintf(stderr, gettext("cannot import '%s': pool "
"may be in use from other system\n"), name);
(void) fprintf(stderr, gettext("use '-f' to import anyway\n"));
@@ -2324,6 +2361,10 @@
(void) printf(gettext("insufficient replicas"));
break;
+ case VDEV_AUX_VERSION_NEWER:
+ (void) printf(gettext("newer version"));
+ break;
+
default:
(void) printf(gettext("corrupted data"));
break;
@@ -2529,6 +2570,24 @@
"from a backup source.\n"));
break;
+ case ZPOOL_STATUS_VERSION_OLDER:
+ (void) printf(gettext("status: The pool is formatted using an "
+ "older on-disk format. The pool can\n\tstill be used, but "
+ "some features are unavailable.\n"));
+ (void) printf(gettext("action: Upgrade the pool using 'zpool "
+ "upgrade'. Once this is done, the\n\tpool will no longer "
+ "be accessible on older software versions.\n"));
+ break;
+
+ case ZPOOL_STATUS_VERSION_NEWER:
+ (void) printf(gettext("status: The pool has been upgraded to a "
+ "newer, incompatible on-disk version.\n\tThe pool cannot "
+ "be accessed on this system.\n"));
+ (void) printf(gettext("action: Access the pool from a system "
+ "running more recent software, or\n\trestore the pool from "
+ "backup.\n"));
+ break;
+
default:
/*
* The remaining errors can't actually be generated, yet.
@@ -2644,6 +2703,191 @@
return (ret);
}
+typedef struct upgrade_cbdata {
+ int cb_all;
+ int cb_first;
+ int cb_newer;
+} upgrade_cbdata_t;
+
+static int
+upgrade_cb(zpool_handle_t *zhp, void *arg)
+{
+ upgrade_cbdata_t *cbp = arg;
+ nvlist_t *config;
+ uint64_t version;
+ int ret = 0;
+
+ config = zpool_get_config(zhp, NULL);
+ verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
+ &version) == 0);
+
+ if (!cbp->cb_newer && version < ZFS_VERSION) {
+ if (!cbp->cb_all) {
+ if (cbp->cb_first) {
+ (void) printf(gettext("The following pools are "
+ "out of date, and can be upgraded. After "
+ "being\nupgraded, these pools will no "
+ "longer be accessible by older software "
+ "versions.\n\n"));
+ (void) printf(gettext("VER POOL\n"));
+ (void) printf(gettext("--- ------------\n"));
+ cbp->cb_first = FALSE;
+ }
+
+ (void) printf("%2llu %s\n", version,
+ zpool_get_name(zhp));
+ } else {
+ cbp->cb_first = FALSE;
+ ret = zpool_upgrade(zhp);
+ if (ret == 0)
+ (void) printf(gettext("Successfully upgraded "
+ "'%s'\n"), zpool_get_name(zhp));
+ }
+ } else if (cbp->cb_newer && version > ZFS_VERSION) {
+ assert(!cbp->cb_all);
+
+ if (cbp->cb_first) {
+ (void) printf(gettext("The following pools are "
+ "formatted using a newer software version and\n"
+ "cannot be accessed on the current system.\n\n"));
+ (void) printf(gettext("VER POOL\n"));
+ (void) printf(gettext("--- ------------\n"));
+ cbp->cb_first = FALSE;
+ }
+
+ (void) printf("%2llu %s\n", version,
+ zpool_get_name(zhp));
+ }
+
+ zpool_close(zhp);
+ return (ret);
+}
+
+/* ARGSUSED */
+static int
+upgrade_one(zpool_handle_t *zhp, void *unused)
+{
+ nvlist_t *config;
+ uint64_t version;
+ int ret;
+
+ config = zpool_get_config(zhp, NULL);
+ verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
+ &version) == 0);
+
+ if (version == ZFS_VERSION) {
+ (void) printf(gettext("Pool '%s' is already formatted "
+ "using the current version.\n"), zpool_get_name(zhp));
+ return (0);
+ }
+
+ ret = zpool_upgrade(zhp);
+ if (ret == 0)
+ (void) printf(gettext("Successfully upgraded '%s'\n"),
+ zpool_get_name(zhp));
+
+ return (ret != 0);
+}
+
+/*
+ * zpool upgrade
+ * zpool upgrade -v
+ * zpool upgrade <-a | pool>
+ *
+ * With no arguments, display downrev'd ZFS pool available for upgrade.
+ * Individual pools can be upgraded by specifying the pool, and '-a' will
+ * upgrade all pools.
+ */
+int
+zpool_do_upgrade(int argc, char **argv)
+{
+ int c;
+ upgrade_cbdata_t cb = { 0 };
+ int ret = 0;
+ boolean_t showversions = B_FALSE;
+
+ /* check options */
+ while ((c = getopt(argc, argv, "av")) != -1) {
+ switch (c) {
+ case 'a':
+ cb.cb_all = TRUE;
+ break;
+ case 'v':
+ showversions = B_TRUE;
+ break;
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(FALSE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (showversions) {
+ if (cb.cb_all || argc != 0) {
+ (void) fprintf(stderr, gettext("-v option is "
+ "incompatible with other arguments\n"));
+ usage(FALSE);
+ }
+ } else if (cb.cb_all) {
+ if (argc != 0) {
+ (void) fprintf(stderr, gettext("-a option is "
+ "incompatible with other arguments\n"));
+ usage(FALSE);
+ }
+ }
+
+ (void) printf(gettext("This system is currently running ZFS version "
+ "%llu.\n\n"), ZFS_VERSION);
+ cb.cb_first = TRUE;
+ if (showversions) {
+ (void) printf(gettext("The following versions are "
+ "suppored:\n\n"));
+ (void) printf(gettext("VER DESCRIPTION\n"));
+ (void) printf("--- -----------------------------------------"
+ "---------------\n");
+ (void) printf(gettext(" 1 Initial ZFS version.\n\n"));
+ (void) printf(gettext("For more information on a particular "
+ "version, including supported releases, see:\n\n"));
+ (void) printf("http://www.opensolaris.org/os/community/zfs/"
+ "version/N\n\n");
+ (void) printf(gettext("Where 'N' is the version number.\n"));
+ } else if (argc == 0) {
+ int notfound;
+
+ ret = zpool_iter(upgrade_cb, &cb);
+ notfound = cb.cb_first;
+
+ if (!cb.cb_all && ret == 0) {
+ if (!cb.cb_first)
+ (void) printf("\n");
+ cb.cb_first = B_TRUE;
+ cb.cb_newer = B_TRUE;
+ ret = zpool_iter(upgrade_cb, &cb);
+ if (!cb.cb_first) {
+ notfound = B_FALSE;
+ (void) printf("\n");
+ }
+ }
+
+ if (ret == 0) {
+ if (notfound)
+ (void) printf(gettext("All pools are formatted "
+ "using this version.\n"));
+ else if (!cb.cb_all)
+ (void) printf(gettext("Use 'zpool upgrade -v' "
+ "for a list of available versions and "
+ "their associated\nfeatures.\n"));
+ }
+ } else {
+ ret = for_each_pool(argc, argv, FALSE, upgrade_one, NULL);
+ }
+
+ return (ret);
+}
+
int
main(int argc, char **argv)
{
--- a/usr/src/lib/libzfs/common/libzfs.h Thu Apr 06 19:27:51 2006 -0700
+++ b/usr/src/lib/libzfs/common/libzfs.h Thu Apr 06 20:12:27 2006 -0700
@@ -108,13 +108,14 @@
ZPOOL_STATUS_CORRUPT_POOL, /* pool metadata is corrupted */
ZPOOL_STATUS_CORRUPT_DATA, /* data errors in user (meta)data */
ZPOOL_STATUS_FAILING_DEV, /* device experiencing errors */
- ZPOOL_STATUS_VERSION_MISMATCH, /* bad on-disk version */
+ ZPOOL_STATUS_VERSION_NEWER, /* newer on-disk version */
/*
* The following are not faults per se, but still an error possibly
* requiring administrative attention. There is no corresponding
* message ID.
*/
+ ZPOOL_STATUS_VERSION_OLDER, /* older on-disk version */
ZPOOL_STATUS_RESILVERING, /* device being resilvered */
ZPOOL_STATUS_OFFLINE_DEV, /* device online */
@@ -153,6 +154,7 @@
* Miscellaneous pool functions
*/
extern char *zpool_vdev_name(zpool_handle_t *, nvlist_t *);
+extern int zpool_upgrade(zpool_handle_t *);
/*
* Basic handle manipulations. These functions do not create or destroy the
--- a/usr/src/lib/libzfs/common/libzfs_import.c Thu Apr 06 19:27:51 2006 -0700
+++ b/usr/src/lib/libzfs/common/libzfs_import.c Thu Apr 06 20:12:27 2006 -0700
@@ -293,6 +293,26 @@
}
/*
+ * Returns true if the named pool matches the given GUID.
+ */
+boolean_t
+pool_active(const char *name, uint64_t guid)
+{
+ zpool_handle_t *zhp;
+ uint64_t theguid;
+
+ if ((zhp = zpool_open_silent(name)) == NULL)
+ return (B_FALSE);
+
+ verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_POOL_GUID,
+ &theguid) == 0);
+
+ zpool_close(zhp);
+
+ return (theguid == guid);
+}
+
+/*
* Convert our list of pools into the definitive set of configurations. We
* start by picking the best config for each toplevel vdev. Once that's done,
* we assemble the toplevel vdevs into a full config for the pool. We make a
@@ -481,9 +501,7 @@
verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
&guid) == 0);
- (void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
- if (zfs_ioctl(ZFS_IOC_POOL_GUID, &zc) == 0 &&
- guid == zc.zc_guid) {
+ if (pool_active(name, guid)) {
nvlist_free(config);
continue;
}
@@ -706,7 +724,6 @@
nvlist_t *config;
char *name;
int ret;
- zfs_cmd_t zc = { 0 };
uint64_t guid, vdev_guid;
zpool_handle_t *zhp;
nvlist_t *pool_config;
@@ -732,16 +749,12 @@
case POOL_STATE_ACTIVE:
/*
* For an active pool, we have to determine if it's really part
- * of an active pool (in which case the pool will exist and the
- * guid will be the same), or whether it's part of an active
- * pool that was disconnected without being explicitly exported.
- *
- * We use the direct ioctl() first to avoid triggering an error
- * message if the pool cannot be opened.
+ * of a currently active pool (in which case the pool will exist
+ * and the guid will be the same), or whether it's part of an
+ * active pool that was disconnected without being explicitly
+ * exported.
*/
- (void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
- if (zfs_ioctl(ZFS_IOC_POOL_GUID, &zc) == 0 &&
- guid == zc.zc_guid) {
+ if (pool_active(name, guid)) {
/*
* Because the device may have been removed while
* offlined, we only report it as active if the vdev is
--- a/usr/src/lib/libzfs/common/libzfs_pool.c Thu Apr 06 19:27:51 2006 -0700
+++ b/usr/src/lib/libzfs/common/libzfs_pool.c Thu Apr 06 20:12:27 2006 -0700
@@ -1590,3 +1590,28 @@
return (0);
}
+
+/*
+ * Upgrade a ZFS pool to the latest on-disk version.
+ */
+int
+zpool_upgrade(zpool_handle_t *zhp)
+{
+ zfs_cmd_t zc = { 0 };
+
+ (void) strcpy(zc.zc_name, zhp->zpool_name);
+ if (zfs_ioctl(ZFS_IOC_POOL_UPGRADE, &zc) != 0) {
+ switch (errno) {
+ case EPERM:
+ zfs_error(dgettext(TEXT_DOMAIN, "cannot upgrade '%s': "
+ "permission denied"), zhp->zpool_name);
+ break;
+ default:
+ zfs_baderror(errno);
+ }
+
+ return (-1);
+ }
+
+ return (0);
+}
--- a/usr/src/lib/libzfs/common/libzfs_status.c Thu Apr 06 19:27:51 2006 -0700
+++ b/usr/src/lib/libzfs/common/libzfs_status.c Thu Apr 06 20:12:27 2006 -0700
@@ -177,13 +177,23 @@
vdev_stat_t *vs;
uint_t vsc;
uint64_t nerr;
+ uint64_t version;
+ verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
+ &version) == 0);
verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
&nvroot) == 0);
verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
(uint64_t **)&vs, &vsc) == 0);
/*
+ * Newer on-disk version.
+ */
+ if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
+ vs->vs_aux == VDEV_AUX_VERSION_NEWER)
+ return (ZPOOL_STATUS_VERSION_NEWER);
+
+ /*
* Check that the config is complete.
*/
if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
@@ -244,11 +254,10 @@
return (ZPOOL_STATUS_RESILVERING);
/*
- * We currently have no way to detect the following errors:
- *
- * CORRUPT_CACHE
- * VERSION_MISMATCH
+ * Outdated, but usable, version
*/
+ if (version < ZFS_VERSION)
+ return (ZPOOL_STATUS_VERSION_OLDER);
return (ZPOOL_STATUS_OK);
}
--- a/usr/src/lib/libzfs/spec/libzfs.spec Thu Apr 06 19:27:51 2006 -0700
+++ b/usr/src/lib/libzfs/spec/libzfs.spec Thu Apr 06 20:12:27 2006 -0700
@@ -328,6 +328,10 @@
version SUNWprivate_1.1
end
+function zpool_upgrade
+version SUNWprivate_1.1
+end
+
function zpool_vdev_online
version SUNWprivate_1.1
end
--- a/usr/src/lib/libzfs_jni/common/libzfs_jni_pool.c Thu Apr 06 19:27:51 2006 -0700
+++ b/usr/src/lib/libzfs_jni/common/libzfs_jni_pool.c Thu Apr 06 20:12:27 2006 -0700
@@ -129,8 +129,10 @@
{ ZPOOL_STATUS_CORRUPT_POOL, "ZPOOL_STATUS_CORRUPT_POOL" },
{ ZPOOL_STATUS_CORRUPT_DATA, "ZPOOL_STATUS_CORRUPT_DATA" },
{ ZPOOL_STATUS_FAILING_DEV, "ZPOOL_STATUS_FAILING_DEV" },
- { ZPOOL_STATUS_VERSION_MISMATCH,
- "ZPOOL_STATUS_VERSION_MISMATCH" },
+ { ZPOOL_STATUS_VERSION_OLDER,
+ "ZPOOL_STATUS_VERSION_OLDER" },
+ { ZPOOL_STATUS_VERSION_NEWER,
+ "ZPOOL_STATUS_VERSION_NEWER" },
{ ZPOOL_STATUS_RESILVERING, "ZPOOL_STATUS_RESILVERING" },
{ ZPOOL_STATUS_OFFLINE_DEV, "ZPOOL_STATUS_OFFLINE_DEV" },
{ ZPOOL_STATUS_OK, "ZPOOL_STATUS_OK" },
--- a/usr/src/uts/common/fs/zfs/spa.c Thu Apr 06 19:27:51 2006 -0700
+++ b/usr/src/uts/common/fs/zfs/spa.c Thu Apr 06 20:12:27 2006 -0700
@@ -326,6 +326,8 @@
* If we weren't able to find a single valid uberblock, return failure.
*/
if (ub->ub_txg == 0) {
+ vdev_set_state(rvd, B_TRUE, VDEV_STATE_CANT_OPEN,
+ VDEV_AUX_CORRUPT_DATA);
error = ENXIO;
goto out;
}
@@ -333,7 +335,9 @@
/*
* If the pool is newer than the code, we can't open it.
*/
- if (ub->ub_version > UBERBLOCK_VERSION) {
+ if (ub->ub_version > ZFS_VERSION) {
+ vdev_set_state(rvd, B_TRUE, VDEV_STATE_CANT_OPEN,
+ VDEV_AUX_VERSION_NEWER);
error = ENOTSUP;
goto out;
}
@@ -729,6 +733,7 @@
spa_activate(spa);
spa->spa_uberblock.ub_txg = txg - 1;
+ spa->spa_uberblock.ub_version = ZFS_VERSION;
spa->spa_ubsync = spa->spa_uberblock;
/*
@@ -2267,3 +2272,21 @@
{
return (vdev_lookup_by_guid(spa->spa_root_vdev, guid));
}
+
+void
+spa_upgrade(spa_t *spa)
+{
+ spa_config_enter(spa, RW_WRITER, FTAG);
+
+ /*
+ * This should only be called for a non-faulted pool, and since a
+ * future version would result in an unopenable pool, this shouldn't be
+ * possible.
+ */
+ ASSERT(spa->spa_uberblock.ub_version <= ZFS_VERSION);
+
+ spa->spa_uberblock.ub_version = ZFS_VERSION;
+ vdev_config_dirty(spa->spa_root_vdev);
+
+ spa_config_exit(spa, FTAG);
+}
--- a/usr/src/uts/common/fs/zfs/spa_config.c Thu Apr 06 19:27:51 2006 -0700
+++ b/usr/src/uts/common/fs/zfs/spa_config.c Thu Apr 06 20:12:27 2006 -0700
@@ -279,7 +279,7 @@
VERIFY(nvlist_alloc(&config, NV_UNIQUE_NAME, KM_SLEEP) == 0);
VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_VERSION,
- UBERBLOCK_VERSION) == 0);
+ spa->spa_uberblock.ub_version) == 0);
VERIFY(nvlist_add_string(config, ZPOOL_CONFIG_POOL_NAME,
spa_name(spa)) == 0);
VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_POOL_STATE,
--- a/usr/src/uts/common/fs/zfs/sys/spa.h Thu Apr 06 19:27:51 2006 -0700
+++ b/usr/src/uts/common/fs/zfs/sys/spa.h Thu Apr 06 20:12:27 2006 -0700
@@ -397,6 +397,7 @@
extern uint64_t spa_get_random(uint64_t range);
extern void sprintf_blkptr(char *buf, int len, blkptr_t *bp);
extern void spa_freeze(spa_t *spa);
+extern void spa_upgrade(spa_t *spa);
extern void spa_evict_all(void);
extern vdev_t *spa_lookup_by_guid(spa_t *spa, uint64_t guid);
--- a/usr/src/uts/common/fs/zfs/sys/uberblock_impl.h Thu Apr 06 19:27:51 2006 -0700
+++ b/usr/src/uts/common/fs/zfs/sys/uberblock_impl.h Thu Apr 06 20:12:27 2006 -0700
@@ -45,12 +45,11 @@
* expect the magic number in the first word won't work.
*/
#define UBERBLOCK_MAGIC 0x00bab10c /* oo-ba-bloc! */
-#define UBERBLOCK_VERSION 1ULL
#define UBERBLOCK_SHIFT 10 /* up to 1K */
struct uberblock {
uint64_t ub_magic; /* UBERBLOCK_MAGIC */
- uint64_t ub_version; /* UBERBLOCK_VERSION */
+ uint64_t ub_version; /* ZFS_VERSION */
uint64_t ub_txg; /* txg of last sync */
uint64_t ub_guid_sum; /* sum of all vdev guids */
uint64_t ub_timestamp; /* UTC time of last sync */
--- a/usr/src/uts/common/fs/zfs/sys/zfs_znode.h Thu Apr 06 19:27:51 2006 -0700
+++ b/usr/src/uts/common/fs/zfs/sys/zfs_znode.h Thu Apr 06 20:12:27 2006 -0700
@@ -58,7 +58,7 @@
#define ZFS_FSID "FSID"
#define ZFS_DELETE_QUEUE "DELETE_QUEUE"
#define ZFS_ROOT_OBJ "ROOT"
-#define ZFS_VERSION_OBJ "VERSION"
+#define ZPL_VERSION_OBJ "VERSION"
#define ZFS_PROP_BLOCKPERPAGE "BLOCKPERPAGE"
#define ZFS_PROP_NOGROWBLOCKS "NOGROWBLOCKS"
@@ -66,11 +66,11 @@
#define ZFS_FLAG_NOGROWBLOCKS 0x2
/*
- * ZFS version - rev'd whenever an incompatible on-disk format change
+ * ZPL version - rev'd whenever an incompatible on-disk format change
* occurs. Independent of SPA/DMU/ZAP versioning.
*/
-#define ZFS_VERSION 1ULL
+#define ZPL_VERSION 1ULL
#define ZFS_MAX_BLOCKSIZE (SPA_MAXBLOCKSIZE)
--- a/usr/src/uts/common/fs/zfs/uberblock.c Thu Apr 06 19:27:51 2006 -0700
+++ b/usr/src/uts/common/fs/zfs/uberblock.c Thu Apr 06 20:12:27 2006 -0700
@@ -50,8 +50,11 @@
{
ASSERT(ub->ub_txg < txg);
+ /*
+ * We explicitly do not set ub_version here, so that older versions
+ * continue to be written with the previous uberblock version.
+ */
ub->ub_magic = UBERBLOCK_MAGIC;
- ub->ub_version = UBERBLOCK_VERSION;
ub->ub_txg = txg;
ub->ub_guid_sum = rvd->vdev_guid_sum;
ub->ub_timestamp = gethrestime_sec();
--- a/usr/src/uts/common/fs/zfs/zfs_ioctl.c Thu Apr 06 19:27:51 2006 -0700
+++ b/usr/src/uts/common/fs/zfs/zfs_ioctl.c Thu Apr 06 20:12:27 2006 -0700
@@ -424,20 +424,6 @@
}
static int
-zfs_ioc_pool_guid(zfs_cmd_t *zc)
-{
- spa_t *spa;
- int error;
-
- error = spa_open(zc->zc_name, &spa, FTAG);
- if (error == 0) {
- zc->zc_guid = spa_guid(spa);
- spa_close(spa, FTAG);
- }
- return (error);
-}
-
-static int
zfs_ioc_pool_stats(zfs_cmd_t *zc)
{
nvlist_t *config;
@@ -545,6 +531,20 @@
}
static int
+zfs_ioc_pool_upgrade(zfs_cmd_t *zc)
+{
+ spa_t *spa;
+ int error;
+
+ error = spa_open(zc->zc_name, &spa, FTAG);
+ if (error == 0) {
+ spa_upgrade(spa);
+ spa_close(spa, FTAG);
+ }
+ return (error);
+}
+
+static int
zfs_ioc_vdev_add(zfs_cmd_t *zc)
{
spa_t *spa;
@@ -1182,11 +1182,11 @@
{ zfs_ioc_pool_import, zfs_secpolicy_config, pool_name },
{ zfs_ioc_pool_export, zfs_secpolicy_config, pool_name },
{ zfs_ioc_pool_configs, zfs_secpolicy_none, no_name },
- { zfs_ioc_pool_guid, zfs_secpolicy_read, pool_name },
{ zfs_ioc_pool_stats, zfs_secpolicy_read, pool_name },
{ zfs_ioc_pool_tryimport, zfs_secpolicy_config, no_name },
{ zfs_ioc_pool_scrub, zfs_secpolicy_config, pool_name },
{ zfs_ioc_pool_freeze, zfs_secpolicy_config, no_name },
+ { zfs_ioc_pool_upgrade, zfs_secpolicy_config, pool_name },
{ zfs_ioc_vdev_add, zfs_secpolicy_config, pool_name },
{ zfs_ioc_vdev_remove, zfs_secpolicy_config, pool_name },
{ zfs_ioc_vdev_online, zfs_secpolicy_config, pool_name },
--- a/usr/src/uts/common/fs/zfs/zfs_znode.c Thu Apr 06 19:27:51 2006 -0700
+++ b/usr/src/uts/common/fs/zfs/zfs_znode.c Thu Apr 06 20:12:27 2006 -0700
@@ -235,7 +235,7 @@
objset_t *os = zfsvfs->z_os;
uint64_t zoid;
- uint64_t version = ZFS_VERSION;
+ uint64_t version = ZPL_VERSION;
int i, error;
dmu_object_info_t doi;
dmu_objset_stats_t *stats;
@@ -258,15 +258,15 @@
dmu_tx_commit(tx);
}
- error = zap_lookup(os, MASTER_NODE_OBJ, ZFS_VERSION_OBJ, 8, 1,
+ error = zap_lookup(os, MASTER_NODE_OBJ, ZPL_VERSION_OBJ, 8, 1,
&version);
if (error) {
return (error);
- } else if (version != ZFS_VERSION) {
+ } else if (version != ZPL_VERSION) {
(void) printf("Mismatched versions: File system "
"is version %lld on-disk format, which is "
"incompatible with this software version %lld!",
- (u_longlong_t)version, ZFS_VERSION);
+ (u_longlong_t)version, ZPL_VERSION);
return (ENOTSUP);
}
@@ -942,7 +942,7 @@
{
zfsvfs_t zfsvfs;
uint64_t moid, doid, roid = 0;
- uint64_t version = ZFS_VERSION;
+ uint64_t version = ZPL_VERSION;
int error;
znode_t *rootzp = NULL;
vnode_t *vp;
@@ -964,7 +964,7 @@
* Set starting attributes.
*/
- error = zap_update(os, moid, ZFS_VERSION_OBJ, 8, 1, &version, tx);
+ error = zap_update(os, moid, ZPL_VERSION_OBJ, 8, 1, &version, tx);
ASSERT(error == 0);
/*
--- a/usr/src/uts/common/sys/fs/zfs.h Thu Apr 06 19:27:51 2006 -0700
+++ b/usr/src/uts/common/sys/fs/zfs.h Thu Apr 06 20:12:27 2006 -0700
@@ -107,6 +107,11 @@
uint64_t zfs_prop_default_numeric(zfs_prop_t);
/*
+ * On-disk format version.
+ */
+#define ZFS_VERSION 1ULL
+
+/*
* The following are configuration names used in the nvlist describing a pool's
* configuration.
*/
@@ -183,7 +188,9 @@
VDEV_AUX_NO_REPLICAS, /* insufficient number of replicas */
VDEV_AUX_BAD_GUID_SUM, /* vdev guid sum doesn't match */
VDEV_AUX_TOO_SMALL, /* vdev size is too small */
- VDEV_AUX_BAD_LABEL /* the label is OK but invalid */
+ VDEV_AUX_BAD_LABEL, /* the label is OK but invalid */
+ VDEV_AUX_VERSION_NEWER, /* on-disk version is too new */
+ VDEV_AUX_VERSION_OLDER /* on-disk version is too old */
} vdev_aux_t;
/*
@@ -279,11 +286,11 @@
ZFS_IOC_POOL_IMPORT,
ZFS_IOC_POOL_EXPORT,
ZFS_IOC_POOL_CONFIGS,
- ZFS_IOC_POOL_GUID,
ZFS_IOC_POOL_STATS,
ZFS_IOC_POOL_TRYIMPORT,
ZFS_IOC_POOL_SCRUB,
ZFS_IOC_POOL_FREEZE,
+ ZFS_IOC_POOL_UPGRADE,
ZFS_IOC_VDEV_ADD,
ZFS_IOC_VDEV_REMOVE,
ZFS_IOC_VDEV_ONLINE,