ZFS/MFV: Use cached feature info in spa_add_feature_stats()
commit 417104bdd3c7ce07ec58674dd078f9891c3bc780 Author: Ned Bass <bass6@llnl.gov> Date: Thu Feb 26 12:24:11 2015 -0800 Use cached feature info in spa_add_feature_stats() Avoid issuing I/O to the pool when retrieving feature flags information. Trying to read the ZAPs from disk means that zpool clear would hang if the pool is suspended and recovery would require a reboot. To keep the feature stats resident in memory, we hang a cached nvlist off of the spa. It is built up from disk the first time spa_add_feature_stats() is called, and refreshed thereafter using the cached feature reference counts. spa_add_feature_stats() gets called at pool import time so we can be sure the cached nvlist will be available if the pool is later suspended. Signed-off-by: Ned Bass <bass6@llnl.gov> Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov> Closes #3082
This commit is contained in:
parent
ab9ed8a1bd
commit
90df93417e
@ -4371,18 +4371,14 @@ spa_add_l2cache(spa_t *spa, nvlist_t *config)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
spa_add_feature_stats(spa_t *spa, nvlist_t *config)
|
spa_feature_stats_from_disk(spa_t *spa, nvlist_t *features)
|
||||||
{
|
{
|
||||||
nvlist_t *features;
|
|
||||||
zap_cursor_t zc;
|
zap_cursor_t zc;
|
||||||
zap_attribute_t za;
|
zap_attribute_t za;
|
||||||
|
|
||||||
ASSERT(spa_config_held(spa, SCL_CONFIG, RW_READER));
|
|
||||||
VERIFY(nvlist_alloc(&features, NV_UNIQUE_NAME, KM_SLEEP) == 0);
|
|
||||||
|
|
||||||
/* We may be unable to read features if pool is suspended. */
|
/* We may be unable to read features if pool is suspended. */
|
||||||
if (spa_suspended(spa))
|
if (spa_suspended(spa))
|
||||||
goto out;
|
return;
|
||||||
|
|
||||||
if (spa->spa_feat_for_read_obj != 0) {
|
if (spa->spa_feat_for_read_obj != 0) {
|
||||||
for (zap_cursor_init(&zc, spa->spa_meta_objset,
|
for (zap_cursor_init(&zc, spa->spa_meta_objset,
|
||||||
@ -4391,7 +4387,7 @@ spa_add_feature_stats(spa_t *spa, nvlist_t *config)
|
|||||||
zap_cursor_advance(&zc)) {
|
zap_cursor_advance(&zc)) {
|
||||||
ASSERT(za.za_integer_length == sizeof (uint64_t) &&
|
ASSERT(za.za_integer_length == sizeof (uint64_t) &&
|
||||||
za.za_num_integers == 1);
|
za.za_num_integers == 1);
|
||||||
VERIFY3U(0, ==, nvlist_add_uint64(features, za.za_name,
|
VERIFY0(nvlist_add_uint64(features, za.za_name,
|
||||||
za.za_first_integer));
|
za.za_first_integer));
|
||||||
}
|
}
|
||||||
zap_cursor_fini(&zc);
|
zap_cursor_fini(&zc);
|
||||||
@ -4404,16 +4400,62 @@ spa_add_feature_stats(spa_t *spa, nvlist_t *config)
|
|||||||
zap_cursor_advance(&zc)) {
|
zap_cursor_advance(&zc)) {
|
||||||
ASSERT(za.za_integer_length == sizeof (uint64_t) &&
|
ASSERT(za.za_integer_length == sizeof (uint64_t) &&
|
||||||
za.za_num_integers == 1);
|
za.za_num_integers == 1);
|
||||||
VERIFY3U(0, ==, nvlist_add_uint64(features, za.za_name,
|
VERIFY0(nvlist_add_uint64(features, za.za_name,
|
||||||
za.za_first_integer));
|
za.za_first_integer));
|
||||||
}
|
}
|
||||||
zap_cursor_fini(&zc);
|
zap_cursor_fini(&zc);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
out:
|
static void
|
||||||
VERIFY(nvlist_add_nvlist(config, ZPOOL_CONFIG_FEATURE_STATS,
|
spa_feature_stats_from_cache(spa_t *spa, nvlist_t *features)
|
||||||
features) == 0);
|
{
|
||||||
nvlist_free(features);
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < SPA_FEATURES; i++) {
|
||||||
|
zfeature_info_t feature = spa_feature_table[i];
|
||||||
|
uint64_t refcount;
|
||||||
|
|
||||||
|
if (feature_get_refcount(spa, &feature, &refcount) != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
VERIFY0(nvlist_add_uint64(features, feature.fi_guid, refcount));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Store a list of pool features and their reference counts in the
|
||||||
|
* config.
|
||||||
|
*
|
||||||
|
* The first time this is called on a spa, allocate a new nvlist, fetch
|
||||||
|
* the pool features and reference counts from disk, then save the list
|
||||||
|
* in the spa. In subsequent calls on the same spa use the saved nvlist
|
||||||
|
* and refresh its values from the cached reference counts. This
|
||||||
|
* ensures we don't block here on I/O on a suspended pool so 'zpool
|
||||||
|
* clear' can resume the pool.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
spa_add_feature_stats(spa_t *spa, nvlist_t *config)
|
||||||
|
{
|
||||||
|
nvlist_t *features;
|
||||||
|
|
||||||
|
ASSERT(spa_config_held(spa, SCL_CONFIG, RW_READER));
|
||||||
|
|
||||||
|
mutex_enter(&spa->spa_feat_stats_lock);
|
||||||
|
features = spa->spa_feat_stats;
|
||||||
|
|
||||||
|
if (features != NULL) {
|
||||||
|
spa_feature_stats_from_cache(spa, features);
|
||||||
|
} else {
|
||||||
|
VERIFY0(nvlist_alloc(&features, NV_UNIQUE_NAME, KM_SLEEP));
|
||||||
|
spa->spa_feat_stats = features;
|
||||||
|
spa_feature_stats_from_disk(spa, features);
|
||||||
|
}
|
||||||
|
|
||||||
|
VERIFY0(nvlist_add_nvlist(config, ZPOOL_CONFIG_FEATURE_STATS,
|
||||||
|
features));
|
||||||
|
|
||||||
|
mutex_exit(&spa->spa_feat_stats_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -708,6 +708,7 @@ spa_add(const char *name, nvlist_t *config, const char *altroot)
|
|||||||
mutex_init(&spa->spa_scrub_lock, NULL, MUTEX_DEFAULT, NULL);
|
mutex_init(&spa->spa_scrub_lock, NULL, MUTEX_DEFAULT, NULL);
|
||||||
mutex_init(&spa->spa_suspend_lock, NULL, MUTEX_DEFAULT, NULL);
|
mutex_init(&spa->spa_suspend_lock, NULL, MUTEX_DEFAULT, NULL);
|
||||||
mutex_init(&spa->spa_vdev_top_lock, NULL, MUTEX_DEFAULT, NULL);
|
mutex_init(&spa->spa_vdev_top_lock, NULL, MUTEX_DEFAULT, NULL);
|
||||||
|
mutex_init(&spa->spa_feat_stats_lock, NULL, MUTEX_DEFAULT, NULL);
|
||||||
|
|
||||||
cv_init(&spa->spa_async_cv, NULL, CV_DEFAULT, NULL);
|
cv_init(&spa->spa_async_cv, NULL, CV_DEFAULT, NULL);
|
||||||
cv_init(&spa->spa_evicting_os_cv, NULL, CV_DEFAULT, NULL);
|
cv_init(&spa->spa_evicting_os_cv, NULL, CV_DEFAULT, NULL);
|
||||||
@ -881,6 +882,7 @@ spa_remove(spa_t *spa)
|
|||||||
|
|
||||||
nvlist_free(spa->spa_label_features);
|
nvlist_free(spa->spa_label_features);
|
||||||
nvlist_free(spa->spa_load_info);
|
nvlist_free(spa->spa_load_info);
|
||||||
|
nvlist_free(spa->spa_feat_stats);
|
||||||
spa_config_set(spa, NULL);
|
spa_config_set(spa, NULL);
|
||||||
|
|
||||||
#ifdef illumos
|
#ifdef illumos
|
||||||
@ -922,6 +924,7 @@ spa_remove(spa_t *spa)
|
|||||||
mutex_destroy(&spa->spa_scrub_lock);
|
mutex_destroy(&spa->spa_scrub_lock);
|
||||||
mutex_destroy(&spa->spa_suspend_lock);
|
mutex_destroy(&spa->spa_suspend_lock);
|
||||||
mutex_destroy(&spa->spa_vdev_top_lock);
|
mutex_destroy(&spa->spa_vdev_top_lock);
|
||||||
|
mutex_destroy(&spa->spa_feat_stats_lock);
|
||||||
|
|
||||||
kmem_free(spa, sizeof (spa_t));
|
kmem_free(spa, sizeof (spa_t));
|
||||||
}
|
}
|
||||||
|
@ -360,6 +360,8 @@ struct spa {
|
|||||||
uint64_t spa_feat_for_read_obj; /* required to read from pool */
|
uint64_t spa_feat_for_read_obj; /* required to read from pool */
|
||||||
uint64_t spa_feat_desc_obj; /* Feature descriptions */
|
uint64_t spa_feat_desc_obj; /* Feature descriptions */
|
||||||
uint64_t spa_feat_enabled_txg_obj; /* Feature enabled txg */
|
uint64_t spa_feat_enabled_txg_obj; /* Feature enabled txg */
|
||||||
|
kmutex_t spa_feat_stats_lock; /* protects spa_feat_stats */
|
||||||
|
nvlist_t *spa_feat_stats; /* Cache of enabled features */
|
||||||
/* cache feature refcounts */
|
/* cache feature refcounts */
|
||||||
uint64_t spa_feat_refcount_cache[SPA_FEATURES];
|
uint64_t spa_feat_refcount_cache[SPA_FEATURES];
|
||||||
#ifdef illumos
|
#ifdef illumos
|
||||||
|
@ -220,7 +220,7 @@ spa_features_check(spa_t *spa, boolean_t for_write,
|
|||||||
*
|
*
|
||||||
* Note: well-designed features will not need to use this; they should
|
* Note: well-designed features will not need to use this; they should
|
||||||
* use spa_feature_is_enabled() and spa_feature_is_active() instead.
|
* use spa_feature_is_enabled() and spa_feature_is_active() instead.
|
||||||
* However, this is non-static for zdb and zhack.
|
* However, this is non-static for zdb, zhack, and spa_add_feature_stats().
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
feature_get_refcount(spa_t *spa, zfeature_info_t *feature, uint64_t *res)
|
feature_get_refcount(spa_t *spa, zfeature_info_t *feature, uint64_t *res)
|
||||||
|
Loading…
Reference in New Issue
Block a user