From 4eb30c68644c0aacbed9e10d94eff071b2cd76f8 Mon Sep 17 00:00:00 2001 From: Ned Bass Date: Thu, 23 Apr 2015 12:32:59 -0700 Subject: Serialize access to spa->spa_feat_stats nvlist The function spa_add_feature_stats() manipulates the shared nvlist spa->spa_feat_stats in an unsafe concurrent manner. Add a mutex to protect the list. Signed-off-by: Ned Bass Signed-off-by: Brian Behlendorf Closes #3335 --- include/sys/spa_impl.h | 1 + module/zfs/spa.c | 7 ++++++- module/zfs/spa_misc.c | 2 ++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/include/sys/spa_impl.h b/include/sys/spa_impl.h index 72e04e8cf..19ba11537 100644 --- a/include/sys/spa_impl.h +++ b/include/sys/spa_impl.h @@ -236,6 +236,7 @@ struct spa { uint64_t spa_feat_for_read_obj; /* required to read from pool */ uint64_t spa_feat_desc_obj; /* Feature descriptions */ 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 */ uint64_t spa_feat_refcount_cache[SPA_FEATURES]; diff --git a/module/zfs/spa.c b/module/zfs/spa.c index 8bee15094..998ec3e54 100644 --- a/module/zfs/spa.c +++ b/module/zfs/spa.c @@ -3264,10 +3264,13 @@ spa_feature_stats_from_cache(spa_t *spa, nvlist_t *features) static void spa_add_feature_stats(spa_t *spa, nvlist_t *config) { - nvlist_t *features = spa->spa_feat_stats; + 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 { @@ -3278,6 +3281,8 @@ spa_add_feature_stats(spa_t *spa, nvlist_t *config) VERIFY0(nvlist_add_nvlist(config, ZPOOL_CONFIG_FEATURE_STATS, features)); + + mutex_exit(&spa->spa_feat_stats_lock); } int diff --git a/module/zfs/spa_misc.c b/module/zfs/spa_misc.c index ec0c01959..7a96ea18b 100644 --- a/module/zfs/spa_misc.c +++ b/module/zfs/spa_misc.c @@ -531,6 +531,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_suspend_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_proc_cv, NULL, CV_DEFAULT, NULL); @@ -668,6 +669,7 @@ spa_remove(spa_t *spa) mutex_destroy(&spa->spa_scrub_lock); mutex_destroy(&spa->spa_suspend_lock); mutex_destroy(&spa->spa_vdev_top_lock); + mutex_destroy(&spa->spa_feat_stats_lock); kmem_free(spa, sizeof (spa_t)); } -- cgit v1.2.3