summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoreschrock <none@none>2006-04-06 20:12:27 -0700
committereschrock <none@none>2006-04-06 20:12:27 -0700
commiteaca9bbd5f5d1e4e554da4c7108e8a03c8c33481 (patch)
treeef2b3aaeb726ac88394c9747efa5d31fd70b9509
parent2b490d7cbf676bb735e581d0d9a4d058cca612b7 (diff)
downloadillumos-gate-eaca9bbd5f5d1e4e554da4c7108e8a03c8c33481.tar.gz
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
-rw-r--r--usr/src/cmd/fs.d/zfs/fstyp/fstyp.c12
-rw-r--r--usr/src/cmd/truss/codes.c4
-rw-r--r--usr/src/cmd/zpool/zpool_main.c296
-rw-r--r--usr/src/lib/libzfs/common/libzfs.h4
-rw-r--r--usr/src/lib/libzfs/common/libzfs_import.c39
-rw-r--r--usr/src/lib/libzfs/common/libzfs_pool.c25
-rw-r--r--usr/src/lib/libzfs/common/libzfs_status.c17
-rw-r--r--usr/src/lib/libzfs/spec/libzfs.spec4
-rw-r--r--usr/src/lib/libzfs_jni/common/libzfs_jni_pool.c6
-rw-r--r--usr/src/uts/common/fs/zfs/spa.c25
-rw-r--r--usr/src/uts/common/fs/zfs/spa_config.c2
-rw-r--r--usr/src/uts/common/fs/zfs/sys/spa.h1
-rw-r--r--usr/src/uts/common/fs/zfs/sys/uberblock_impl.h3
-rw-r--r--usr/src/uts/common/fs/zfs/sys/zfs_znode.h6
-rw-r--r--usr/src/uts/common/fs/zfs/uberblock.c5
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_ioctl.c30
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_znode.c12
-rw-r--r--usr/src/uts/common/sys/fs/zfs.h11
18 files changed, 419 insertions, 83 deletions
diff --git a/usr/src/cmd/fs.d/zfs/fstyp/fstyp.c b/usr/src/cmd/fs.d/zfs/fstyp/fstyp.c
index 90de2fe5a6..26376e36a6 100644
--- a/usr/src/cmd/fs.d/zfs/fstyp/fstyp.c
+++ b/usr/src/cmd/fs.d/zfs/fstyp/fstyp.c
@@ -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 @@ main(int argc, char **argv)
int c, fd;
int verbose = 0;
nvlist_t *config;
+ uint64_t state;
(void) setlocale(LC_ALL, "");
@@ -145,6 +145,10 @@ main(int argc, char **argv)
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)
diff --git a/usr/src/cmd/truss/codes.c b/usr/src/cmd/truss/codes.c
index 3fdbace8b7..4e808b8e48 100644
--- a/usr/src/cmd/truss/codes.c
+++ b/usr/src/cmd/truss/codes.c
@@ -869,8 +869,6 @@ const struct ioc {
"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 @@ const struct ioc {
"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",
diff --git a/usr/src/cmd/zpool/zpool_main.c b/usr/src/cmd/zpool/zpool_main.c
index 2b17abc2b7..2cbecad212 100644
--- a/usr/src/cmd/zpool/zpool_main.c
+++ b/usr/src/cmd/zpool/zpool_main.c
@@ -69,6 +69,8 @@ static int zpool_do_scrub(int, char **);
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 @@ typedef enum {
HELP_ONLINE,
HELP_REPLACE,
HELP_SCRUB,
- HELP_STATUS
+ HELP_STATUS,
+ HELP_UPGRADE
} zpool_help_t;
@@ -141,6 +144,7 @@ static zpool_command_t command_table[] = {
{ 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 @@ get_usage(zpool_help_t idx) {
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 @@ print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth)
(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 @@ show_import(nvlist_t *config)
"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 @@ show_import(nvlist_t *config)
* 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 @@ do_import(nvlist_t *config, const char *newname, const char *mntopts,
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 @@ print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
(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 @@ status_callback(zpool_handle_t *zhp, void *data)
"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 @@ zpool_do_status(int argc, char **argv)
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)
{
diff --git a/usr/src/lib/libzfs/common/libzfs.h b/usr/src/lib/libzfs/common/libzfs.h
index 1d8a4b1ccc..0044ccd7c9 100644
--- a/usr/src/lib/libzfs/common/libzfs.h
+++ b/usr/src/lib/libzfs/common/libzfs.h
@@ -108,13 +108,14 @@ typedef enum {
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 @@ extern nvlist_t *zpool_find_import(int, char **);
* 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
diff --git a/usr/src/lib/libzfs/common/libzfs_import.c b/usr/src/lib/libzfs/common/libzfs_import.c
index a06c94af6d..98519c3aae 100644
--- a/usr/src/lib/libzfs/common/libzfs_import.c
+++ b/usr/src/lib/libzfs/common/libzfs_import.c
@@ -293,6 +293,26 @@ add_config(pool_list_t *pl, const char *path, nvlist_t *config)
}
/*
+ * 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 @@ get_configs(pool_list_t *pl)
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 @@ zpool_in_use(int fd, pool_state_t *state, char **namestr)
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 @@ zpool_in_use(int fd, pool_state_t *state, char **namestr)
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
diff --git a/usr/src/lib/libzfs/common/libzfs_pool.c b/usr/src/lib/libzfs/common/libzfs_pool.c
index 1165497e72..2889725027 100644
--- a/usr/src/lib/libzfs/common/libzfs_pool.c
+++ b/usr/src/lib/libzfs/common/libzfs_pool.c
@@ -1590,3 +1590,28 @@ zpool_get_errlog(zpool_handle_t *zhp, nvlist_t ***list, size_t *nelem)
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);
+}
diff --git a/usr/src/lib/libzfs/common/libzfs_status.c b/usr/src/lib/libzfs/common/libzfs_status.c
index 314e452076..258b2e2f7d 100644
--- a/usr/src/lib/libzfs/common/libzfs_status.c
+++ b/usr/src/lib/libzfs/common/libzfs_status.c
@@ -177,13 +177,23 @@ check_status(nvlist_t *config, int isimport)
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 @@ check_status(nvlist_t *config, int isimport)
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);
}
diff --git a/usr/src/lib/libzfs/spec/libzfs.spec b/usr/src/lib/libzfs/spec/libzfs.spec
index fd87619578..1789122711 100644
--- a/usr/src/lib/libzfs/spec/libzfs.spec
+++ b/usr/src/lib/libzfs/spec/libzfs.spec
@@ -328,6 +328,10 @@ function zpool_remove_zvol_links
version SUNWprivate_1.1
end
+function zpool_upgrade
+version SUNWprivate_1.1
+end
+
function zpool_vdev_online
version SUNWprivate_1.1
end
diff --git a/usr/src/lib/libzfs_jni/common/libzfs_jni_pool.c b/usr/src/lib/libzfs_jni/common/libzfs_jni_pool.c
index 4a4e76c160..d9d09804ec 100644
--- a/usr/src/lib/libzfs_jni/common/libzfs_jni_pool.c
+++ b/usr/src/lib/libzfs_jni/common/libzfs_jni_pool.c
@@ -129,8 +129,10 @@ static zjni_field_mapping_t zpool_status_map[] = {
{ 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" },
diff --git a/usr/src/uts/common/fs/zfs/spa.c b/usr/src/uts/common/fs/zfs/spa.c
index 7a581ba102..f4ecf519cd 100644
--- a/usr/src/uts/common/fs/zfs/spa.c
+++ b/usr/src/uts/common/fs/zfs/spa.c
@@ -326,6 +326,8 @@ spa_load(spa_t *spa, nvlist_t *config, spa_load_state_t state, int mosconfig)
* 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 @@ spa_load(spa_t *spa, nvlist_t *config, spa_load_state_t state, int mosconfig)
/*
* 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_create(const char *pool, nvlist_t *nvroot, const char *altroot)
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 @@ spa_lookup_by_guid(spa_t *spa, uint64_t guid)
{
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);
+}
diff --git a/usr/src/uts/common/fs/zfs/spa_config.c b/usr/src/uts/common/fs/zfs/spa_config.c
index acdac7ba62..906f2e5470 100644
--- a/usr/src/uts/common/fs/zfs/spa_config.c
+++ b/usr/src/uts/common/fs/zfs/spa_config.c
@@ -279,7 +279,7 @@ spa_config_generate(spa_t *spa, vdev_t *vd, uint64_t txg, int getstats)
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,
diff --git a/usr/src/uts/common/fs/zfs/sys/spa.h b/usr/src/uts/common/fs/zfs/sys/spa.h
index 21e7ad7938..cbe8257953 100644
--- a/usr/src/uts/common/fs/zfs/sys/spa.h
+++ b/usr/src/uts/common/fs/zfs/sys/spa.h
@@ -397,6 +397,7 @@ extern void spa_strfree(char *);
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);
diff --git a/usr/src/uts/common/fs/zfs/sys/uberblock_impl.h b/usr/src/uts/common/fs/zfs/sys/uberblock_impl.h
index 86d9877010..ab0f2dcf8c 100644
--- a/usr/src/uts/common/fs/zfs/sys/uberblock_impl.h
+++ b/usr/src/uts/common/fs/zfs/sys/uberblock_impl.h
@@ -45,12 +45,11 @@ extern "C" {
* 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 */
diff --git a/usr/src/uts/common/fs/zfs/sys/zfs_znode.h b/usr/src/uts/common/fs/zfs/sys/zfs_znode.h
index 3c05c5ff79..4d069b5209 100644
--- a/usr/src/uts/common/fs/zfs/sys/zfs_znode.h
+++ b/usr/src/uts/common/fs/zfs/sys/zfs_znode.h
@@ -58,7 +58,7 @@ extern "C" {
#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 @@ extern "C" {
#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)
diff --git a/usr/src/uts/common/fs/zfs/uberblock.c b/usr/src/uts/common/fs/zfs/uberblock.c
index b6d3fe9595..34d7e0c3ac 100644
--- a/usr/src/uts/common/fs/zfs/uberblock.c
+++ b/usr/src/uts/common/fs/zfs/uberblock.c
@@ -50,8 +50,11 @@ uberblock_update(uberblock_t *ub, vdev_t *rvd, uint64_t txg)
{
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();
diff --git a/usr/src/uts/common/fs/zfs/zfs_ioctl.c b/usr/src/uts/common/fs/zfs/zfs_ioctl.c
index 422b24a993..cd7e79a8be 100644
--- a/usr/src/uts/common/fs/zfs/zfs_ioctl.c
+++ b/usr/src/uts/common/fs/zfs/zfs_ioctl.c
@@ -424,20 +424,6 @@ zfs_ioc_pool_configs(zfs_cmd_t *zc)
}
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 @@ zfs_ioc_pool_freeze(zfs_cmd_t *zc)
}
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 @@ static zfs_ioc_vec_t zfs_ioc_vec[] = {
{ 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 },
diff --git a/usr/src/uts/common/fs/zfs/zfs_znode.c b/usr/src/uts/common/fs/zfs/zfs_znode.c
index cff45752c0..74e5c97cc5 100644
--- a/usr/src/uts/common/fs/zfs/zfs_znode.c
+++ b/usr/src/uts/common/fs/zfs/zfs_znode.c
@@ -235,7 +235,7 @@ zfs_init_fs(zfsvfs_t *zfsvfs, znode_t **zpp, cred_t *cr)
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 @@ zfs_init_fs(zfsvfs_t *zfsvfs, znode_t **zpp, cred_t *cr)
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 @@ zfs_create_fs(objset_t *os, cred_t *cr, dmu_tx_t *tx)
{
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 @@ zfs_create_fs(objset_t *os, cred_t *cr, dmu_tx_t *tx)
* 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);
/*
diff --git a/usr/src/uts/common/sys/fs/zfs.h b/usr/src/uts/common/sys/fs/zfs.h
index 0fa884dcaa..f1a331051d 100644
--- a/usr/src/uts/common/sys/fs/zfs.h
+++ b/usr/src/uts/common/sys/fs/zfs.h
@@ -107,6 +107,11 @@ const char *zfs_prop_default_string(zfs_prop_t);
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 @@ typedef enum vdev_aux {
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 @@ typedef enum zfs_ioc {
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,