diff options
author | Ned Bass <[email protected]> | 2015-02-26 12:24:11 -0800 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2015-03-05 14:11:10 -0800 |
commit | 417104bdd3c7ce07ec58674dd078f9891c3bc780 (patch) | |
tree | d1a19daa843375394ececb2cf8098d42adaae79d /module/zfs/spa.c | |
parent | 0e86d309ccc53e7d6093f8cf2bb09858f63267ac (diff) |
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 <[email protected]>
Signed-off-by: Brian Behlendorf <[email protected]>
Closes #3082
Diffstat (limited to 'module/zfs/spa.c')
-rw-r--r-- | module/zfs/spa.c | 58 |
1 files changed, 48 insertions, 10 deletions
diff --git a/module/zfs/spa.c b/module/zfs/spa.c index 81cef1952..8bee15094 100644 --- a/module/zfs/spa.c +++ b/module/zfs/spa.c @@ -3202,15 +3202,11 @@ spa_add_l2cache(spa_t *spa, nvlist_t *config) } 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_attribute_t za; - ASSERT(spa_config_held(spa, SCL_CONFIG, RW_READER)); - VERIFY(nvlist_alloc(&features, NV_UNIQUE_NAME, KM_SLEEP) == 0); - if (spa->spa_feat_for_read_obj != 0) { for (zap_cursor_init(&zc, spa->spa_meta_objset, spa->spa_feat_for_read_obj); @@ -3218,7 +3214,7 @@ spa_add_feature_stats(spa_t *spa, nvlist_t *config) zap_cursor_advance(&zc)) { ASSERT(za.za_integer_length == sizeof (uint64_t) && 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)); } zap_cursor_fini(&zc); @@ -3231,15 +3227,57 @@ spa_add_feature_stats(spa_t *spa, nvlist_t *config) zap_cursor_advance(&zc)) { ASSERT(za.za_integer_length == sizeof (uint64_t) && 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)); } zap_cursor_fini(&zc); } +} + +static void +spa_feature_stats_from_cache(spa_t *spa, nvlist_t *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 = spa->spa_feat_stats; + + ASSERT(spa_config_held(spa, SCL_CONFIG, RW_READER)); + + 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); + } - VERIFY(nvlist_add_nvlist(config, ZPOOL_CONFIG_FEATURE_STATS, - features) == 0); - nvlist_free(features); + VERIFY0(nvlist_add_nvlist(config, ZPOOL_CONFIG_FEATURE_STATS, + features)); } int |