aboutsummaryrefslogtreecommitdiffstats
path: root/module/zfs
diff options
context:
space:
mode:
authorNed Bass <[email protected]>2015-02-26 12:24:11 -0800
committerBrian Behlendorf <[email protected]>2015-03-05 14:11:10 -0800
commit417104bdd3c7ce07ec58674dd078f9891c3bc780 (patch)
treed1a19daa843375394ececb2cf8098d42adaae79d /module/zfs
parent0e86d309ccc53e7d6093f8cf2bb09858f63267ac (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')
-rw-r--r--module/zfs/spa.c58
-rw-r--r--module/zfs/spa_misc.c1
-rw-r--r--module/zfs/zfeature.c2
3 files changed, 50 insertions, 11 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
diff --git a/module/zfs/spa_misc.c b/module/zfs/spa_misc.c
index ce6f02dc4..ec0c01959 100644
--- a/module/zfs/spa_misc.c
+++ b/module/zfs/spa_misc.c
@@ -643,6 +643,7 @@ spa_remove(spa_t *spa)
nvlist_free(spa->spa_label_features);
nvlist_free(spa->spa_load_info);
+ nvlist_free(spa->spa_feat_stats);
spa_config_set(spa, NULL);
refcount_destroy(&spa->spa_refcount);
diff --git a/module/zfs/zfeature.c b/module/zfs/zfeature.c
index e6cab2c03..352376f22 100644
--- a/module/zfs/zfeature.c
+++ b/module/zfs/zfeature.c
@@ -228,7 +228,7 @@ spa_features_check(spa_t *spa, boolean_t for_write,
*
* Note: well-designed features will not need to use this; they should
* 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
feature_get_refcount(spa_t *spa, zfeature_info_t *feature, uint64_t *res)