Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 24 Nov 2012 13:23:16 +0000 (UTC)
From:      Andriy Gapon <avg@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r243502 - head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs
Message-ID:  <201211241323.qAODNGBA059312@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: avg
Date: Sat Nov 24 13:23:15 2012
New Revision: 243502
URL: http://svnweb.freebsd.org/changeset/base/243502

Log:
  zfs roopool: add support for multi-vdev configurations
  
  Tested by:	madpilot
  MFC after:	10 days

Modified:
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_geom.c

Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c	Sat Nov 24 13:16:49 2012	(r243501)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c	Sat Nov 24 13:23:15 2012	(r243502)
@@ -3755,54 +3755,120 @@ out:
 
 #else
 
-extern int
-vdev_geom_read_pool_label(const char *name, nvlist_t **config);
+extern int vdev_geom_read_pool_label(const char *name, nvlist_t ***configs,
+    uint64_t *count);
 
 static nvlist_t *
 spa_generate_rootconf(const char *name)
 {
+	nvlist_t **configs, **tops;
 	nvlist_t *config;
-	nvlist_t *nvtop, *nvroot;
+	nvlist_t *best_cfg, *nvtop, *nvroot;
+	uint64_t *holes;
+	uint64_t best_txg;
 	uint64_t nchildren;
 	uint64_t pgid;
+	uint64_t count;
+	uint64_t i;
+	uint_t   nholes;
 
-	if (vdev_geom_read_pool_label(name, &config) != 0)
+	if (vdev_geom_read_pool_label(name, &configs, &count) != 0)
 		return (NULL);
 
+	ASSERT3U(count, !=, 0);
+	best_txg = 0;
+	for (i = 0; i < count; i++) {
+		uint64_t txg;
+
+		VERIFY(nvlist_lookup_uint64(configs[i], ZPOOL_CONFIG_POOL_TXG,
+		    &txg) == 0);
+		if (txg > best_txg) {
+			best_txg = txg;
+			best_cfg = configs[i];
+		}
+	}
+
 	/*
 	 * Multi-vdev root pool configuration discovery is not supported yet.
 	 */
 	nchildren = 0;
-	nvlist_lookup_uint64(config, ZPOOL_CONFIG_VDEV_CHILDREN, &nchildren);
-	if (nchildren != 1) {
-		nvlist_free(config);
-		return (NULL);
+	VERIFY(nvlist_lookup_uint64(best_cfg, ZPOOL_CONFIG_VDEV_CHILDREN,
+	    &nchildren) == 0);
+	holes = NULL;
+	nvlist_lookup_uint64_array(best_cfg, ZPOOL_CONFIG_HOLE_ARRAY,
+	    &holes, &nholes);
+
+	tops = kmem_alloc(nchildren * sizeof(void *), KM_SLEEP | KM_ZERO);
+	for (i = 0; i < nchildren; i++) {
+		if (i >= count)
+			break;
+		if (configs[i] == NULL)
+			continue;
+		VERIFY(nvlist_lookup_nvlist(configs[i], ZPOOL_CONFIG_VDEV_TREE,
+		    &nvtop) == 0);
+		nvlist_dup(nvtop, &tops[i], KM_SLEEP);
+	}
+	for (i = 0; holes != NULL && i < nholes; i++) {
+		if (i >= nchildren)
+			continue;
+		if (tops[holes[i]] != NULL)
+			continue;
+		nvlist_alloc(&tops[holes[i]], NV_UNIQUE_NAME, KM_SLEEP);
+		VERIFY(nvlist_add_string(tops[holes[i]], ZPOOL_CONFIG_TYPE,
+		    VDEV_TYPE_HOLE) == 0);
+		VERIFY(nvlist_add_uint64(tops[holes[i]], ZPOOL_CONFIG_ID,
+		    holes[i]) == 0);
+		VERIFY(nvlist_add_uint64(tops[holes[i]], ZPOOL_CONFIG_GUID,
+		    0) == 0);
+	}
+	for (i = 0; i < nchildren; i++) {
+		if (tops[i] != NULL)
+			continue;
+		nvlist_alloc(&tops[i], NV_UNIQUE_NAME, KM_SLEEP);
+		VERIFY(nvlist_add_string(tops[i], ZPOOL_CONFIG_TYPE,
+		    VDEV_TYPE_MISSING) == 0);
+		VERIFY(nvlist_add_uint64(tops[i], ZPOOL_CONFIG_ID,
+		    i) == 0);
+		VERIFY(nvlist_add_uint64(tops[i], ZPOOL_CONFIG_GUID,
+		    0) == 0);
 	}
 
 	/*
-	 * Add this top-level vdev to the child array.
+	 * Create pool config based on the best vdev config.
 	 */
-	VERIFY(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
-	    &nvtop) == 0);
-	VERIFY(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
-	    &pgid) == 0);
+	nvlist_dup(best_cfg, &config, KM_SLEEP);
 
 	/*
 	 * Put this pool's top-level vdevs into a root vdev.
 	 */
+	VERIFY(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
+	    &pgid) == 0);
 	VERIFY(nvlist_alloc(&nvroot, NV_UNIQUE_NAME, KM_SLEEP) == 0);
 	VERIFY(nvlist_add_string(nvroot, ZPOOL_CONFIG_TYPE,
 	    VDEV_TYPE_ROOT) == 0);
 	VERIFY(nvlist_add_uint64(nvroot, ZPOOL_CONFIG_ID, 0ULL) == 0);
 	VERIFY(nvlist_add_uint64(nvroot, ZPOOL_CONFIG_GUID, pgid) == 0);
 	VERIFY(nvlist_add_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
-	    &nvtop, 1) == 0);
+	    tops, nchildren) == 0);
 
 	/*
 	 * Replace the existing vdev_tree with the new root vdev in
 	 * this pool's configuration (remove the old, add the new).
 	 */
 	VERIFY(nvlist_add_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, nvroot) == 0);
+
+	/*
+	 * Drop vdev config elements that should not be present at pool level.
+	 */
+	nvlist_remove(config, ZPOOL_CONFIG_GUID, DATA_TYPE_UINT64);
+	nvlist_remove(config, ZPOOL_CONFIG_TOP_GUID, DATA_TYPE_UINT64);
+
+	for (i = 0; i < count; i++)
+		nvlist_free(configs[i]);
+	kmem_free(configs, count * sizeof(void *));
+	for (i = 0; i < nchildren; i++)
+		nvlist_free(tops[i]);
+	kmem_free(tops, nchildren * sizeof(void *));
 	nvlist_free(nvroot);
 	return (config);
 }

Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_geom.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_geom.c	Sat Nov 24 13:16:49 2012	(r243501)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_geom.c	Sat Nov 24 13:23:15 2012	(r243502)
@@ -292,27 +292,74 @@ vdev_geom_read_config(struct g_consumer 
 	return (*config == NULL ? ENOENT : 0);
 }
 
-static int
-vdev_geom_check_config(nvlist_t *config, const char *name, uint64_t *best_txg)
+static void
+resize_configs(nvlist_t ***configs, uint64_t *count, uint64_t id)
 {
-	uint64_t vdev_guid;
-	uint64_t txg;
+	nvlist_t **new_configs;
+	uint64_t i;
+
+	if (id < *count)
+		return;
+	new_configs = kmem_alloc((id + 1) * sizeof(nvlist_t *),
+	    KM_SLEEP | KM_ZERO);
+	for (i = 0; i < *count; i++)
+		new_configs[i] = (*configs)[i];
+	if (*configs != NULL)
+		kmem_free(*configs, *count * sizeof(void *));
+	*configs = new_configs;
+	*count = id + 1;
+}
+
+static void
+process_vdev_config(nvlist_t ***configs, uint64_t *count, nvlist_t *cfg,
+    const char *name, uint64_t* known_pool_guid)
+{
+	nvlist_t *vdev_tree;
+	uint64_t pool_guid;
+	uint64_t vdev_guid, known_guid;
+	uint64_t id, txg, known_txg;
 	char *pname;
+	int i;
 
-	if (nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, &pname) != 0 ||
+	if (nvlist_lookup_string(cfg, ZPOOL_CONFIG_POOL_NAME, &pname) != 0 ||
 	    strcmp(pname, name) != 0)
-		return (ENOENT);
+		goto ignore;
 
-	ZFS_LOG(1, "found pool: %s", pname);
+	if (nvlist_lookup_uint64(cfg, ZPOOL_CONFIG_POOL_GUID, &pool_guid) != 0)
+		goto ignore;
 
-	txg = 0;
-	nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_TXG, &txg);
-	if (txg <= *best_txg)
-		return (ENOENT);
-	*best_txg = txg;
-	ZFS_LOG(1, "txg: %ju", (uintmax_t)*best_txg);
+	if (nvlist_lookup_uint64(cfg, ZPOOL_CONFIG_TOP_GUID, &vdev_guid) != 0)
+		goto ignore;
 
-	return (0);
+	if (nvlist_lookup_nvlist(cfg, ZPOOL_CONFIG_VDEV_TREE, &vdev_tree) != 0)
+		goto ignore;
+
+	if (nvlist_lookup_uint64(vdev_tree, ZPOOL_CONFIG_ID, &id) != 0)
+		goto ignore;
+
+	VERIFY(nvlist_lookup_uint64(cfg, ZPOOL_CONFIG_POOL_TXG, &txg) == 0);
+
+	if (*known_pool_guid != 0) {
+		if (pool_guid != *known_pool_guid)
+			goto ignore;
+	} else
+		*known_pool_guid = pool_guid;
+
+	resize_configs(configs, count, id);
+
+	if ((*configs)[id] != NULL) {
+		VERIFY(nvlist_lookup_uint64((*configs)[id],
+		    ZPOOL_CONFIG_POOL_TXG, &known_txg) == 0);
+		if (txg <= known_txg)
+			goto ignore;
+		nvlist_free((*configs)[id]);
+	}
+
+	(*configs)[id] = cfg;
+	return;
+
+ignore:
+	nvlist_free(cfg);
 }
 
 static int
@@ -339,14 +386,15 @@ vdev_geom_detach_taster(struct g_consume
 }
 
 int
-vdev_geom_read_pool_label(const char *name, nvlist_t **config)
+vdev_geom_read_pool_label(const char *name,
+    nvlist_t ***configs, uint64_t *count)
 {
 	struct g_class *mp;
 	struct g_geom *gp, *zgp;
 	struct g_provider *pp;
 	struct g_consumer *zcp;
 	nvlist_t *vdev_cfg;
-	uint64_t best_txg;
+	uint64_t pool_guid;
 	int error;
 
 	DROP_GIANT();
@@ -357,8 +405,9 @@ vdev_geom_read_pool_label(const char *na
 	zgp->orphan = vdev_geom_taste_orphan;
 	zcp = g_new_consumer(zgp);
 
-	best_txg = 0;
-	*config = NULL;
+	*configs = NULL;
+	*count = 0;
+	pool_guid = 0;
 	LIST_FOREACH(mp, &g_classes, class) {
 		if (mp == &zfs_vdev_class)
 			continue;
@@ -378,14 +427,8 @@ vdev_geom_read_pool_label(const char *na
 					continue;
 				ZFS_LOG(1, "successfully read vdev config");
 
-				error = vdev_geom_check_config(vdev_cfg, name,
-				    &best_txg);
-				if (error != 0) {
-					nvlist_free(vdev_cfg);
-					continue;
-				}
-				nvlist_free(*config);
-				*config = vdev_cfg;
+				process_vdev_config(configs, count,
+				    vdev_cfg, name, &pool_guid);
 			}
 		}
 	}
@@ -394,7 +437,8 @@ vdev_geom_read_pool_label(const char *na
 	g_destroy_geom(zgp);
 	g_topology_unlock();
 	PICKUP_GIANT();
-	return (*config == NULL ? ENOENT : 0);
+
+	return (*count > 0 ? 0 : ENOENT);
 }
 
 static uint64_t



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201211241323.qAODNGBA059312>