Illumos #3090 and #3102
[zfs.git] / module / zfs / spa.c
index 244f10d..59c43f4 100644 (file)
@@ -117,6 +117,8 @@ const zio_taskq_info_t zio_taskqs[ZIO_TYPES][ZIO_TASKQ_TYPES] = {
 
 static dsl_syncfunc_t spa_sync_version;
 static dsl_syncfunc_t spa_sync_props;
+static dsl_checkfunc_t spa_change_guid_check;
+static dsl_syncfunc_t spa_change_guid_sync;
 static boolean_t spa_has_active_shared_spare(spa_t *spa);
 static inline int spa_load_impl(spa_t *spa, uint64_t, nvlist_t *config,
     spa_load_state_t state, spa_import_type_t type, boolean_t mosconfig,
@@ -676,6 +678,47 @@ spa_prop_clear_bootfs(spa_t *spa, uint64_t dsobj, dmu_tx_t *tx)
        }
 }
 
+/*ARGSUSED*/
+static int
+spa_change_guid_check(void *arg1, void *arg2, dmu_tx_t *tx)
+{
+       spa_t *spa = arg1;
+       vdev_t *rvd = spa->spa_root_vdev;
+       uint64_t vdev_state;
+       ASSERTV(uint64_t *newguid = arg2);
+
+       spa_config_enter(spa, SCL_STATE, FTAG, RW_READER);
+       vdev_state = rvd->vdev_state;
+       spa_config_exit(spa, SCL_STATE, FTAG);
+
+       if (vdev_state != VDEV_STATE_HEALTHY)
+               return (ENXIO);
+
+       ASSERT3U(spa_guid(spa), !=, *newguid);
+
+       return (0);
+}
+
+static void
+spa_change_guid_sync(void *arg1, void *arg2, dmu_tx_t *tx)
+{
+       spa_t *spa = arg1;
+       uint64_t *newguid = arg2;
+       uint64_t oldguid;
+       vdev_t *rvd = spa->spa_root_vdev;
+
+       oldguid = spa_guid(spa);
+
+       spa_config_enter(spa, SCL_STATE, FTAG, RW_READER);
+       rvd->vdev_guid = *newguid;
+       rvd->vdev_guid_sum += (*newguid - oldguid);
+       vdev_config_dirty(rvd);
+       spa_config_exit(spa, SCL_STATE, FTAG);
+
+       spa_history_log_internal(LOG_POOL_GUID_CHANGE, spa, tx,
+           "old=%lld new=%lld", oldguid, *newguid);
+}
+
 /*
  * Change the GUID for the pool.  This is done so that we can later
  * re-import a pool built from a clone of our own vdevs.  We will modify
@@ -688,29 +731,23 @@ spa_prop_clear_bootfs(spa_t *spa, uint64_t dsobj, dmu_tx_t *tx)
 int
 spa_change_guid(spa_t *spa)
 {
-       uint64_t        oldguid, newguid;
-       uint64_t        txg;
-
-       if (!(spa_mode_global & FWRITE))
-               return (EROFS);
-
-       txg = spa_vdev_enter(spa);
-
-       if (spa->spa_root_vdev->vdev_state != VDEV_STATE_HEALTHY)
-               return (spa_vdev_exit(spa, NULL, txg, ENXIO));
+       int error;
+       uint64_t guid;
 
-       oldguid = spa_guid(spa);
-       newguid = spa_generate_guid(NULL);
-       ASSERT3U(oldguid, !=, newguid);
+       mutex_enter(&spa_namespace_lock);
+       guid = spa_generate_guid(NULL);
 
-       spa->spa_root_vdev->vdev_guid = newguid;
-       spa->spa_root_vdev->vdev_guid_sum += (newguid - oldguid);
+       error = dsl_sync_task_do(spa_get_dsl(spa), spa_change_guid_check,
+           spa_change_guid_sync, spa, &guid, 5);
 
-       vdev_config_dirty(spa->spa_root_vdev);
+       if (error == 0) {
+               spa_config_sync(spa, B_FALSE, B_TRUE);
+               spa_event_notify(spa, NULL, FM_EREPORT_ZFS_POOL_REGUID);
+       }
 
-       spa_event_notify(spa, NULL, FM_EREPORT_ZFS_POOL_REGUID);
+       mutex_exit(&spa_namespace_lock);
 
-       return (spa_vdev_exit(spa, NULL, txg, 0));
+       return (error);
 }
 
 /*
@@ -6083,6 +6120,9 @@ spa_sync(spa_t *spa, uint64_t txg)
                                    rvd->vdev_children, txg, B_TRUE);
                }
 
+               if (error == 0)
+                       spa->spa_last_synced_guid = rvd->vdev_guid;
+
                spa_config_exit(spa, SCL_STATE, FTAG);
 
                if (error == 0)