usr/src/uts/common/fs/zfs/vdev.c
changeset 10974 32d689ba6466
parent 10922 e2081f502306
child 10982 34d62707fe9d
--- a/usr/src/uts/common/fs/zfs/vdev.c	Thu Nov 05 17:39:24 2009 -0800
+++ b/usr/src/uts/common/fs/zfs/vdev.c	Thu Nov 05 18:44:56 2009 -0800
@@ -491,6 +491,13 @@
 		    &vd->vdev_asize);
 	}
 
+	if (parent && !parent->vdev_parent) {
+		ASSERT(alloctype == VDEV_ALLOC_LOAD ||
+		    alloctype == VDEV_ALLOC_ADD);
+		vd->vdev_mg = metaslab_group_create(islog ?
+		    spa_log_class(spa) : spa_normal_class(spa), vd);
+	}
+
 	/*
 	 * If we're a leaf vdev, try to load the DTL object and other state.
 	 */
@@ -578,8 +585,10 @@
 	/*
 	 * Discard allocation state.
 	 */
-	if (vd == vd->vdev_top)
+	if (vd->vdev_mg != NULL) {
 		vdev_metaslab_fini(vd);
+		metaslab_group_destroy(vd->vdev_mg);
+	}
 
 	ASSERT3U(vd->vdev_stat.vs_space, ==, 0);
 	ASSERT3U(vd->vdev_stat.vs_dspace, ==, 0);
@@ -787,13 +796,14 @@
 {
 	spa_t *spa = vd->vdev_spa;
 	objset_t *mos = spa->spa_meta_objset;
-	metaslab_class_t *mc;
 	uint64_t m;
 	uint64_t oldc = vd->vdev_ms_count;
 	uint64_t newc = vd->vdev_asize >> vd->vdev_ms_shift;
 	metaslab_t **mspp;
 	int error;
 
+	ASSERT(txg == 0 || spa_config_held(spa, SCL_ALLOC, RW_WRITER));
+
 	/*
 	 * This vdev is not being allocated from yet or is a hole.
 	 */
@@ -813,14 +823,6 @@
 
 	ASSERT(oldc <= newc);
 
-	if (vd->vdev_islog)
-		mc = spa_log_class(spa);
-	else
-		mc = spa_normal_class(spa);
-
-	if (vd->vdev_mg == NULL)
-		vd->vdev_mg = metaslab_group_create(mc, vd);
-
 	mspp = kmem_zalloc(newc * sizeof (*mspp), KM_SLEEP);
 
 	if (oldc != 0) {
@@ -855,6 +857,15 @@
 		    m << vd->vdev_ms_shift, 1ULL << vd->vdev_ms_shift, txg);
 	}
 
+	if (txg == 0)
+		spa_config_enter(spa, SCL_ALLOC, FTAG, RW_WRITER);
+
+	if (oldc == 0)
+		metaslab_group_activate(vd->vdev_mg);
+
+	if (txg == 0)
+		spa_config_exit(spa, SCL_ALLOC, FTAG);
+
 	return (0);
 }
 
@@ -865,6 +876,7 @@
 	uint64_t count = vd->vdev_ms_count;
 
 	if (vd->vdev_ms != NULL) {
+		metaslab_group_passivate(vd->vdev_mg);
 		for (m = 0; m < count; m++)
 			if (vd->vdev_ms[m] != NULL)
 				metaslab_fini(vd->vdev_ms[m]);
@@ -2134,8 +2146,8 @@
 	return (error);
 }
 
-int
-vdev_offline(spa_t *spa, uint64_t guid, uint64_t flags)
+static int
+vdev_offline_locked(spa_t *spa, uint64_t guid, uint64_t flags)
 {
 	vdev_t *vd, *tvd;
 	int error = 0;
@@ -2178,7 +2190,7 @@
 			/*
 			 * Prevent any future allocations.
 			 */
-			metaslab_class_remove(spa->spa_log_class, mg);
+			metaslab_group_passivate(mg);
 			(void) spa_vdev_state_exit(spa, vd, 0);
 
 			error = vdev_offline_log(spa);
@@ -2189,7 +2201,7 @@
 			 * Check to see if the config has changed.
 			 */
 			if (error || generation != spa->spa_config_generation) {
-				metaslab_class_add(spa->spa_log_class, mg);
+				metaslab_group_activate(mg);
 				if (error)
 					return (spa_vdev_state_exit(spa,
 					    vd, error));
@@ -2220,7 +2232,7 @@
 		 * once we online the device it's open for business.
 		 */
 		if (tvd->vdev_islog && mg != NULL)
-			metaslab_class_add(spa->spa_log_class, mg);
+			metaslab_group_activate(mg);
 	}
 
 	vd->vdev_tmpoffline = !!(flags & ZFS_OFFLINE_TEMPORARY);
@@ -2228,6 +2240,18 @@
 	return (spa_vdev_state_exit(spa, vd, 0));
 }
 
+int
+vdev_offline(spa_t *spa, uint64_t guid, uint64_t flags)
+{
+	int error;
+
+	mutex_enter(&spa->spa_vdev_top_lock);
+	error = vdev_offline_locked(spa, guid, flags);
+	mutex_exit(&spa->spa_vdev_top_lock);
+
+	return (error);
+}
+
 /*
  * Clear the error counts associated with this vdev.  Unlike vdev_online() and
  * vdev_offline(), we assume the spa config is locked.  We also clear all