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,
}
}
+/*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
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);
}
/*
if (spa_version(spa) >= SPA_VERSION_FEATURES) {
boolean_t missing_feat_read = B_FALSE;
- nvlist_t *unsup_feat;
+ nvlist_t *unsup_feat, *enabled_feat;
if (spa_dir_prop(spa, DMU_POOL_FEATURES_FOR_READ,
&spa->spa_feat_for_read_obj) != 0) {
return (spa_vdev_err(rvd, VDEV_AUX_CORRUPT_DATA, EIO));
}
- VERIFY(nvlist_alloc(&unsup_feat, NV_UNIQUE_NAME, KM_SLEEP) ==
- 0);
+ enabled_feat = fnvlist_alloc();
+ unsup_feat = fnvlist_alloc();
if (!feature_is_supported(spa->spa_meta_objset,
spa->spa_feat_for_read_obj, spa->spa_feat_desc_obj,
- unsup_feat))
+ unsup_feat, enabled_feat))
missing_feat_read = B_TRUE;
if (spa_writeable(spa) || state == SPA_LOAD_TRYIMPORT) {
if (!feature_is_supported(spa->spa_meta_objset,
spa->spa_feat_for_write_obj, spa->spa_feat_desc_obj,
- unsup_feat))
+ unsup_feat, enabled_feat)) {
missing_feat_write = B_TRUE;
+ }
}
+ fnvlist_add_nvlist(spa->spa_load_info,
+ ZPOOL_CONFIG_ENABLED_FEAT, enabled_feat);
+
if (!nvlist_empty(unsup_feat)) {
- VERIFY(nvlist_add_nvlist(spa->spa_load_info,
- ZPOOL_CONFIG_UNSUP_FEAT, unsup_feat) == 0);
+ fnvlist_add_nvlist(spa->spa_load_info,
+ ZPOOL_CONFIG_UNSUP_FEAT, unsup_feat);
}
- nvlist_free(unsup_feat);
+ fnvlist_free(enabled_feat);
+ fnvlist_free(unsup_feat);
if (!missing_feat_read) {
fnvlist_add_boolean(spa->spa_load_info,
config = spa_config_generate(spa, spa->spa_root_vdev,
dmu_tx_get_txg(tx), B_FALSE);
+ /*
+ * If we're upgrading the spa version then make sure that
+ * the config object gets updated with the correct version.
+ */
+ if (spa->spa_ubsync.ub_version < spa->spa_uberblock.ub_version)
+ fnvlist_add_uint64(config, ZPOOL_CONFIG_VERSION,
+ spa->spa_uberblock.ub_version);
+
spa_config_exit(spa, SCL_STATE, FTAG);
if (spa->spa_config_syncing)
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)