svn commit: r332426 - in head: cddl/contrib/opensolaris/cmd/zpool cddl/contrib/opensolaris/lib/libzfs/common sys/cddl/contrib/opensolaris/common/zfs sys/cddl/contrib/opensolaris/uts/common/fs/zfs s...

Andriy Gapon avg at FreeBSD.org
Thu Apr 12 10:37:27 UTC 2018


Author: avg
Date: Thu Apr 12 10:37:26 2018
New Revision: 332426
URL: https://svnweb.freebsd.org/changeset/base/332426

Log:
  allow ZFS pool to have temporary name for duration of current import
  
  The change adds -t <name> option to zpool create and -t option to zpool
  import in its form with an old name and a new name.  This allows to
  import (or create) a pool under a name that's different from its real,
  permanent name without affecting that name.  This is useful when working
  with VM images or images of other physical systems if they happen to
  have a ZFS pool with the same name as the host system.
  
  The changes come from ZoL with some small tweaks.
  The porting has been done by julian.
  
  The change is being submitted to OpenZFS:
  https://github.com/openzfs/openzfs/pull/600
  
  Submitted by:	julian
  Reviewed by:	smh
  MFC after:	2 weeks
  Sponsored by:	Panzura (porting)
  Differential Revision: https://reviews.freebsd.org/D14972

Modified:
  head/cddl/contrib/opensolaris/cmd/zpool/zpool.8
  head/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c
  head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c
  head/sys/cddl/contrib/opensolaris/common/zfs/zpool_prop.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa_config.c
  head/sys/cddl/contrib/opensolaris/uts/common/sys/fs/zfs.h

Modified: head/cddl/contrib/opensolaris/cmd/zpool/zpool.8
==============================================================================
--- head/cddl/contrib/opensolaris/cmd/zpool/zpool.8	Thu Apr 12 07:39:24 2018	(r332425)
+++ head/cddl/contrib/opensolaris/cmd/zpool/zpool.8	Thu Apr 12 10:37:26 2018	(r332426)
@@ -62,6 +62,7 @@
 .Ar ...
 .Op Fl m Ar mountpoint
 .Op Fl R Ar root
+.Op Fl t Ar tempname
 .Ar pool vdev ...
 .Nm
 .Cm destroy
@@ -115,6 +116,7 @@
 .Op Fl m
 .Op Fl N
 .Op Fl R Ar root
+.Op Fl t
 .Op Fl F Op Fl n
 .Ar pool | id
 .Op Ar newpool
@@ -961,6 +963,7 @@ do not actually discard any transactions.
 .Ar ...
 .Op Fl m Ar mountpoint
 .Op Fl R Ar root
+.Op Fl t Ar tempname
 .Ar pool vdev ...
 .Xc
 .Pp
@@ -1062,6 +1065,18 @@ or
 .Qq Cm none .
 For more information on dataset mount points, see
 .Xr zfs 8 .
+.It Fl t Ar tempname
+Sets the in-core pool name to
+.Pa tempname
+while the on-disk name will be the name specified as the pool name
+.Pa pool .
+This will set the default
+.Sy cachefile
+property to
+.Sy none .
+This is intended to handle name space collisions when creating pools
+for other systems, such as virtual machines or physical machines
+whose pools live on network block devices.
 .El
 .It Xo
 .Nm
@@ -1316,6 +1331,7 @@ Searches for and imports all pools found.
 .Op Fl m
 .Op Fl N
 .Op Fl R Ar root
+.Op Fl t
 .Op Fl F Op Fl n
 .Ar pool | id
 .Op Ar newpool
@@ -1375,6 +1391,20 @@ Import the pool without mounting any file systems.
 .It Fl R Ar root
 Equivalent to
 .Qq Fl o Cm cachefile=none,altroot= Ns Pa root
+.It Fl t
+Used with
+.Ar newpool .
+Specifies that
+.Ar newpool
+is temporary.
+Temporary pool names last until export.
+Ensures that the original pool name will be used in all label updates and
+therefore is retained upon export.
+Will also set
+.Sy cachefile
+property to
+.Sy none
+when not explicitly specified.
 .It Fl F
 Recovery mode for a non-importable pool. Attempt to return the pool to an
 importable state by discarding the last few transactions. Not all damaged pools

Modified: head/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c
==============================================================================
--- head/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c	Thu Apr 12 07:39:24 2018	(r332425)
+++ head/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c	Thu Apr 12 10:37:26 2018	(r332426)
@@ -220,8 +220,9 @@ get_usage(zpool_help_t idx)
 	case HELP_CREATE:
 		return (gettext("\tcreate [-fnd] [-B] "
 		    "[-o property=value] ... \n"
-		    "\t    [-O file-system-property=value] ... \n"
-		    "\t    [-m mountpoint] [-R root] <pool> <vdev> ...\n"));
+		    "\t    [-O file-system-property=value] ...\n"
+		    "\t    [-m mountpoint] [-R root] [-t tempname] "
+		    "<pool> <vdev> ...\n"));
 	case HELP_CHECKPOINT:
 		return (gettext("\tcheckpoint [--discard] <pool> ...\n"));
 	case HELP_DESTROY:
@@ -239,7 +240,7 @@ get_usage(zpool_help_t idx)
 		    "[-R root] [-F [-n]] -a\n"
 		    "\timport [-o mntopts] [-o property=value] ... \n"
 		    "\t    [-d dir | -c cachefile] [-D] [-f] [-m] [-N] "
-		    "[-R root] [-F [-n]]\n"
+		    "[-R root] [-F [-n]] [-t]\n"
 		    "\t    [--rewind-to-checkpoint] <pool | id> [newpool]\n"));
 	case HELP_IOSTAT:
 		return (gettext("\tiostat [-v] [-T d|u] [pool] ... [interval "
@@ -489,6 +490,21 @@ add_prop_list(const char *propname, char *propval, nvl
 }
 
 /*
+ * Set a default property pair (name, string-value) in a property nvlist
+ */
+static int
+add_prop_list_default(const char *propname, char *propval, nvlist_t **props,
+    boolean_t poolprop)
+{
+	char *pval;
+
+	if (nvlist_lookup_string(*props, propname, &pval) == 0)
+		return (0);
+
+	return (add_prop_list(propname, propval, props, poolprop));
+}
+
+/*
  * zpool add [-fn] <pool> <vdev> ...
  *
  *	-f	Force addition of devices, even if they appear in use
@@ -850,15 +866,16 @@ errout:
 /*
  * zpool create [-fnd] [-B] [-o property=value] ...
  *		[-O file-system-property=value] ...
- *		[-R root] [-m mountpoint] <pool> <dev> ...
+ *		[-R root] [-m mountpoint] [-t tempname] <pool> <dev> ...
  *
  *	-B	Create boot partition.
  *	-f	Force creation, even if devices appear in use
  *	-n	Do not create the pool, but display the resulting layout if it
  *		were to be created.
- *      -R	Create a pool under an alternate root
- *      -m	Set default mountpoint for the root dataset.  By default it's
+ *	-R	Create a pool under an alternate root
+ *	-m	Set default mountpoint for the root dataset.  By default it's
  *		'/<pool>'
+ *	-t	Use the temporary name until the pool is exported.
  *	-o	Set property=value.
  *	-d	Don't automatically enable all supported pool features
  *		(individual features can be enabled with -o).
@@ -882,6 +899,7 @@ zpool_do_create(int argc, char **argv)
 	int c;
 	nvlist_t *nvroot = NULL;
 	char *poolname;
+	char *tname = NULL;
 	int ret = 1;
 	char *altroot = NULL;
 	char *mountpoint = NULL;
@@ -890,7 +908,7 @@ zpool_do_create(int argc, char **argv)
 	char *propval;
 
 	/* check options */
-	while ((c = getopt(argc, argv, ":fndBR:m:o:O:")) != -1) {
+	while ((c = getopt(argc, argv, ":fndBR:m:o:O:t:")) != -1) {
 		switch (c) {
 		case 'f':
 			force = B_TRUE;
@@ -922,11 +940,7 @@ zpool_do_create(int argc, char **argv)
 			if (add_prop_list(zpool_prop_to_name(
 			    ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
 				goto errout;
-			if (nvlist_lookup_string(props,
-			    zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
-			    &propval) == 0)
-				break;
-			if (add_prop_list(zpool_prop_to_name(
+			if (add_prop_list_default(zpool_prop_to_name(
 			    ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
 				goto errout;
 			break;
@@ -999,6 +1013,27 @@ zpool_do_create(int argc, char **argv)
 				goto errout;
 			}
 			break;
+		case 't':
+			/*
+			 * Sanity check temporary pool name.
+			 */
+			if (strchr(optarg, '/') != NULL) {
+				(void) fprintf(stderr, gettext("cannot create "
+				    "'%s': invalid character '/' in temporary "
+				    "name\n"), optarg);
+				(void) fprintf(stderr, gettext("use 'zfs "
+				    "create' to create a dataset\n"));
+				goto errout;
+			}
+
+			if (add_prop_list(zpool_prop_to_name(
+			    ZPOOL_PROP_TNAME), optarg, &props, B_TRUE))
+				goto errout;
+			if (add_prop_list_default(zpool_prop_to_name(
+			    ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
+				goto errout;
+			tname = optarg;
+			break;
 		case ':':
 			(void) fprintf(stderr, gettext("missing argument for "
 			    "'%c' option\n"), optopt);
@@ -1205,8 +1240,8 @@ zpool_do_create(int argc, char **argv)
 		ret = 1;
 		if (zpool_create(g_zfs, poolname,
 		    nvroot, props, fsprops) == 0) {
-			zfs_handle_t *pool = zfs_open(g_zfs, poolname,
-			    ZFS_TYPE_FILESYSTEM);
+			zfs_handle_t *pool = zfs_open(g_zfs,
+			    tname ? tname : poolname, ZFS_TYPE_FILESYSTEM);
 			if (pool != NULL) {
 				if (zfs_mount(pool, NULL, 0) == 0)
 					ret = zfs_shareall(pool);
@@ -2162,7 +2197,8 @@ zpool_do_checkpoint(int argc, char **argv)
  *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
  *              [-d dir | -c cachefile] [-f] -a
  *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
- *              [-d dir | -c cachefile] [-f] [-n] [-F] <pool | id> [newpool]
+ *              [-d dir | -c cachefile] [-f] [-n] [-F] [-t]
+ *              <pool | id> [newpool]
  *
  *	 -c	Read pool information from a cachefile instead of searching
  *		devices.
@@ -2191,6 +2227,9 @@ zpool_do_checkpoint(int argc, char **argv)
  *
  *       -N     Import the pool but don't mount datasets.
  *
+ *       -t     Use newpool as a temporary pool name instead of renaming
+ *       	the pool.
+ *
  *       -T     Specify a starting txg to use for import. This option is
  *       	intentionally undocumented option for testing purposes.
  *
@@ -2241,7 +2280,7 @@ zpool_do_import(int argc, char **argv)
 	};
 
 	/* check options */
-	while ((c = getopt_long(argc, argv, ":aCc:d:DEfFmnNo:rR:T:VX",
+	while ((c = getopt_long(argc, argv, ":aCc:d:DEfFmnNo:rR:tT:VX",
 	    long_options, NULL)) != -1) {
 		switch (c) {
 		case 'a':
@@ -2296,14 +2335,16 @@ zpool_do_import(int argc, char **argv)
 			if (add_prop_list(zpool_prop_to_name(
 			    ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
 				goto error;
-			if (nvlist_lookup_string(props,
-			    zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
-			    &propval) == 0)
-				break;
-			if (add_prop_list(zpool_prop_to_name(
+			if (add_prop_list_default(zpool_prop_to_name(
 			    ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
 				goto error;
 			break;
+		case 't':
+			flags |= ZFS_IMPORT_TEMP_NAME;
+			if (add_prop_list_default(zpool_prop_to_name(
+			    ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
+				goto error;
+			break;
 		case 'T':
 			errno = 0;
 			txg = strtoull(optarg, &endptr, 0);
@@ -2439,9 +2480,9 @@ zpool_do_import(int argc, char **argv)
 		(void) fprintf(stderr, gettext("cannot import '%s': "
 		    "a pool with that name already exists\n"),
 		    argv[0]);
-		(void) fprintf(stderr, gettext("use the form '%s "
-		    "<pool | id> <newpool>' to give it a new name\n"),
-		    "zpool import");
+		(void) fprintf(stderr, gettext("use the form 'zpool import "
+		    "[-t] <pool | id> <newpool>' to give it a new temporary "
+		    "or permanent name\n"));
 		err = 1;
 	} else if (pools == NULL && idata.exists) {
 		(void) fprintf(stderr, gettext("cannot import '%s': "

Modified: head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c
==============================================================================
--- head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c	Thu Apr 12 07:39:24 2018	(r332425)
+++ head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c	Thu Apr 12 10:37:26 2018	(r332426)
@@ -644,11 +644,22 @@ zpool_valid_proplist(libzfs_handle_t *hdl, const char 
 				goto error;
 			}
 			break;
+
 		case ZPOOL_PROP_READONLY:
 			if (!flags.import) {
 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 				    "property '%s' can only be set at "
 				    "import time"), propname);
+				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+				goto error;
+			}
+			break;
+
+		case ZPOOL_PROP_TNAME:
+			if (!flags.create) {
+				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+				    "property '%s' can only be set at "
+				    "creation time"), propname);
 				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
 				goto error;
 			}

Modified: head/sys/cddl/contrib/opensolaris/common/zfs/zpool_prop.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/common/zfs/zpool_prop.c	Thu Apr 12 07:39:24 2018	(r332425)
+++ head/sys/cddl/contrib/opensolaris/common/zfs/zpool_prop.c	Thu Apr 12 10:37:26 2018	(r332426)
@@ -136,6 +136,8 @@ zpool_prop_init(void)
 	    PROP_READONLY, ZFS_TYPE_POOL, "NAME");
 	zprop_register_hidden(ZPOOL_PROP_MAXBLOCKSIZE, "maxblocksize",
 	    PROP_TYPE_NUMBER, PROP_READONLY, ZFS_TYPE_POOL, "MAXBLOCKSIZE");
+	zprop_register_hidden(ZPOOL_PROP_TNAME, "tname", PROP_TYPE_STRING,
+	    PROP_ONETIME, ZFS_TYPE_POOL, "TNAME");
 }
 
 /*

Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c	Thu Apr 12 07:39:24 2018	(r332425)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c	Thu Apr 12 10:37:26 2018	(r332426)
@@ -4666,12 +4666,18 @@ spa_create(const char *pool, nvlist_t *nvroot, nvlist_
 	uint_t nspares, nl2cache;
 	uint64_t version, obj;
 	boolean_t has_features;
+	char *poolname;
+	nvlist_t *nvl;
 
+	if (nvlist_lookup_string(props,
+	    zpool_prop_to_name(ZPOOL_PROP_TNAME), &poolname) != 0)
+		poolname = (char *)pool;
+
 	/*
 	 * If this pool already exists, return failure.
 	 */
 	mutex_enter(&spa_namespace_lock);
-	if (spa_lookup(pool) != NULL) {
+	if (spa_lookup(poolname) != NULL) {
 		mutex_exit(&spa_namespace_lock);
 		return (SET_ERROR(EEXIST));
 	}
@@ -4679,9 +4685,12 @@ spa_create(const char *pool, nvlist_t *nvroot, nvlist_
 	/*
 	 * Allocate a new spa_t structure.
 	 */
+	nvl = fnvlist_alloc();
+	fnvlist_add_string(nvl, ZPOOL_CONFIG_POOL_NAME, pool);
 	(void) nvlist_lookup_string(props,
 	    zpool_prop_to_name(ZPOOL_PROP_ALTROOT), &altroot);
-	spa = spa_add(pool, NULL, altroot);
+	spa = spa_add(poolname, nvl, altroot);
+	fnvlist_free(nvl);
 	spa_activate(spa, spa_mode_global);
 
 	if (props && (error = spa_prop_validate(spa, props))) {
@@ -4690,6 +4699,12 @@ spa_create(const char *pool, nvlist_t *nvroot, nvlist_
 		mutex_exit(&spa_namespace_lock);
 		return (error);
 	}
+
+	/*
+	 * Temporary pool names should never be written to disk.
+	 */
+	if (poolname != pool)
+		spa->spa_import_flags |= ZFS_IMPORT_TEMP_NAME;
 
 	has_features = B_FALSE;
 	for (nvpair_t *elem = nvlist_next_nvpair(props, NULL);

Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa_config.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa_config.c	Thu Apr 12 07:39:24 2018	(r332425)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa_config.c	Thu Apr 12 10:37:26 2018	(r332426)
@@ -226,6 +226,7 @@ spa_write_cachefile(spa_t *target, boolean_t removing,
 	nvlist_t *nvl;
 	boolean_t ccw_failure;
 	int error;
+	char *pool_name;
 
 	ASSERT(MUTEX_HELD(&spa_namespace_lock));
 
@@ -274,11 +275,18 @@ spa_write_cachefile(spa_t *target, boolean_t removing,
 			if (nvl == NULL)
 				nvl = fnvlist_alloc();
 
-			fnvlist_add_nvlist(nvl, spa->spa_name,
+			if (spa->spa_import_flags & ZFS_IMPORT_TEMP_NAME) {
+				pool_name = fnvlist_lookup_string(spa->spa_config,
+					ZPOOL_CONFIG_POOL_NAME);
+			} else {
+				pool_name = spa_name(spa);
+			}
+
+			fnvlist_add_nvlist(nvl, pool_name,
 			    spa->spa_config);
 			mutex_exit(&spa->spa_props_lock);
 
-			if (nvlist_lookup_nvlist(nvl, spa->spa_name, &nvroot) == 0)
+			if (nvlist_lookup_nvlist(nvl, pool_name, &nvroot) == 0)
 				spa_config_clean(nvroot);
 		}
 
@@ -382,6 +390,7 @@ spa_config_generate(spa_t *spa, vdev_t *vd, uint64_t t
 	unsigned long hostid = 0;
 	boolean_t locked = B_FALSE;
 	uint64_t split_guid;
+	char *pool_name;
 
 	if (vd == NULL) {
 		vd = rvd;
@@ -398,10 +407,27 @@ spa_config_generate(spa_t *spa, vdev_t *vd, uint64_t t
 	if (txg == -1ULL)
 		txg = spa->spa_config_txg;
 
+	/*
+	 * Originally, users had to handle spa namespace collisions by either
+	 * exporting the already imported pool or by specifying a new name for
+	 * the pool with a conflicting name. In the case of root pools from
+	 * virtual guests, neither approach to collision resolution is
+	 * reasonable. This is addressed by extending the new name syntax with
+	 * an option to specify that the new name is temporary. When specified,
+	 * ZFS_IMPORT_TEMP_NAME will be set in spa->spa_import_flags to tell us
+	 * to use the previous name, which we do below.
+	 */
+	if (spa->spa_import_flags & ZFS_IMPORT_TEMP_NAME) {
+		pool_name = fnvlist_lookup_string(spa->spa_config,
+			ZPOOL_CONFIG_POOL_NAME);
+	} else {
+		pool_name = spa_name(spa);
+	}
+
 	config = fnvlist_alloc();
 
 	fnvlist_add_uint64(config, ZPOOL_CONFIG_VERSION, spa_version(spa));
-	fnvlist_add_string(config, ZPOOL_CONFIG_POOL_NAME, spa_name(spa));
+	fnvlist_add_string(config, ZPOOL_CONFIG_POOL_NAME, pool_name);
 	fnvlist_add_uint64(config, ZPOOL_CONFIG_POOL_STATE, spa_state(spa));
 	fnvlist_add_uint64(config, ZPOOL_CONFIG_POOL_TXG, txg);
 	fnvlist_add_uint64(config, ZPOOL_CONFIG_POOL_GUID, spa_guid(spa));

Modified: head/sys/cddl/contrib/opensolaris/uts/common/sys/fs/zfs.h
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/sys/fs/zfs.h	Thu Apr 12 07:39:24 2018	(r332425)
+++ head/sys/cddl/contrib/opensolaris/uts/common/sys/fs/zfs.h	Thu Apr 12 10:37:26 2018	(r332426)
@@ -214,6 +214,7 @@ typedef enum {
 	ZPOOL_PROP_MAXBLOCKSIZE,
 	ZPOOL_PROP_BOOTSIZE,
 	ZPOOL_PROP_CHECKPOINT,
+	ZPOOL_PROP_TNAME,
 	ZPOOL_NUM_PROPS
 } zpool_prop_t;
 
@@ -1047,6 +1048,7 @@ typedef enum {
 #define	ZFS_IMPORT_MISSING_LOG	0x4
 #define	ZFS_IMPORT_ONLY		0x8
 #define	ZFS_IMPORT_CHECKPOINT	0x10
+#define	ZFS_IMPORT_TEMP_NAME	0x20
 
 /*
  * Channel program argument/return nvlist keys and defaults.


More information about the svn-src-head mailing list