diff options
author | delphij <delphij@FreeBSD.org> | 2014-03-19 23:55:03 +0000 |
---|---|---|
committer | delphij <delphij@FreeBSD.org> | 2014-03-19 23:55:03 +0000 |
commit | ede49d4106ad9e6d34a2592322e48604f72605bd (patch) | |
tree | 0012bcb04d95eaf4e65ed2f983e9d51d47236888 /sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfeature.c | |
parent | 8e41bb96f82aa123d5f4c625c68f95b253640b28 (diff) | |
download | FreeBSD-src-ede49d4106ad9e6d34a2592322e48604f72605bd.zip FreeBSD-src-ede49d4106ad9e6d34a2592322e48604f72605bd.tar.gz |
MFC r260150: MFV r259170:
4370 avoid transmitting holes during zfs send
4371 DMU code clean up
illumos/illumos-gate@43466aae47bfcd2ad9bf501faec8e75c08095e4f
NOTE: Make sure the boot code is updated if a zpool upgrade is
done on boot zpool.
Diffstat (limited to 'sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfeature.c')
-rw-r--r-- | sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfeature.c | 111 |
1 files changed, 103 insertions, 8 deletions
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfeature.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfeature.c index 62a8871..e69fcd3 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfeature.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfeature.c @@ -216,6 +216,8 @@ spa_features_check(spa_t *spa, boolean_t for_write, } /* + * Use an in-memory cache of feature refcounts for quick retrieval. + * * 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. @@ -223,6 +225,24 @@ spa_features_check(spa_t *spa, boolean_t for_write, int feature_get_refcount(spa_t *spa, zfeature_info_t *feature, uint64_t *res) { + ASSERT(VALID_FEATURE_FID(feature->fi_feature)); + if (spa->spa_feat_refcount_cache[feature->fi_feature] == + SPA_FEATURE_DISABLED) { + return (SET_ERROR(ENOTSUP)); + } + *res = spa->spa_feat_refcount_cache[feature->fi_feature]; + return (0); +} + +/* + * 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. + */ +int +feature_get_refcount_from_disk(spa_t *spa, zfeature_info_t *feature, + uint64_t *res) +{ int err; uint64_t refcount; uint64_t zapobj = feature->fi_can_readonly ? @@ -247,6 +267,26 @@ feature_get_refcount(spa_t *spa, zfeature_info_t *feature, uint64_t *res) return (0); } + +static int +feature_get_enabled_txg(spa_t *spa, zfeature_info_t *feature, uint64_t *res) { + uint64_t enabled_txg_obj = spa->spa_feat_enabled_txg_obj; + + ASSERT(zfeature_depends_on(feature->fi_feature, + SPA_FEATURE_ENABLED_TXG)); + + if (!spa_feature_is_enabled(spa, feature->fi_feature)) { + return (SET_ERROR(ENOTSUP)); + } + + ASSERT(enabled_txg_obj != 0); + + VERIFY0(zap_lookup(spa->spa_meta_objset, spa->spa_feat_enabled_txg_obj, + feature->fi_guid, sizeof (uint64_t), 1, res)); + + return (0); +} + /* * This function is non-static for zhack; it should otherwise not be used * outside this file. @@ -255,16 +295,31 @@ void feature_sync(spa_t *spa, zfeature_info_t *feature, uint64_t refcount, dmu_tx_t *tx) { + ASSERT(VALID_FEATURE_OR_NONE(feature->fi_feature)); uint64_t zapobj = feature->fi_can_readonly ? spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj; VERIFY0(zap_update(spa->spa_meta_objset, zapobj, feature->fi_guid, sizeof (uint64_t), 1, &refcount, tx)); + /* + * feature_sync is called directly from zhack, allowing the + * creation of arbitrary features whose fi_feature field may + * be greater than SPA_FEATURES. When called from zhack, the + * zfeature_info_t object's fi_feature field will be set to + * SPA_FEATURE_NONE. + */ + if (feature->fi_feature != SPA_FEATURE_NONE) { + uint64_t *refcount_cache = + &spa->spa_feat_refcount_cache[feature->fi_feature]; + VERIFY3U(*refcount_cache, ==, + atomic_swap_64(refcount_cache, refcount)); + } + if (refcount == 0) spa_deactivate_mos_feature(spa, feature->fi_guid); else if (feature->fi_mos) - spa_activate_mos_feature(spa, feature->fi_guid); + spa_activate_mos_feature(spa, feature->fi_guid, tx); } /* @@ -274,6 +329,7 @@ feature_sync(spa_t *spa, zfeature_info_t *feature, uint64_t refcount, void feature_enable_sync(spa_t *spa, zfeature_info_t *feature, dmu_tx_t *tx) { + uint64_t initial_refcount = feature->fi_activate_on_enable ? 1 : 0; uint64_t zapobj = feature->fi_can_readonly ? spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj; @@ -293,7 +349,24 @@ feature_enable_sync(spa_t *spa, zfeature_info_t *feature, dmu_tx_t *tx) VERIFY0(zap_update(spa->spa_meta_objset, spa->spa_feat_desc_obj, feature->fi_guid, 1, strlen(feature->fi_desc) + 1, feature->fi_desc, tx)); - feature_sync(spa, feature, 0, tx); + + feature_sync(spa, feature, initial_refcount, tx); + + if (spa_feature_is_enabled(spa, SPA_FEATURE_ENABLED_TXG)) { + uint64_t enabling_txg = dmu_tx_get_txg(tx); + + if (spa->spa_feat_enabled_txg_obj == 0ULL) { + spa->spa_feat_enabled_txg_obj = + zap_create_link(spa->spa_meta_objset, + DMU_OTN_ZAP_METADATA, DMU_POOL_DIRECTORY_OBJECT, + DMU_POOL_FEATURE_ENABLED_TXG, tx); + } + spa_feature_incr(spa, SPA_FEATURE_ENABLED_TXG, tx); + + VERIFY0(zap_add(spa->spa_meta_objset, + spa->spa_feat_enabled_txg_obj, feature->fi_guid, + sizeof (uint64_t), 1, &enabling_txg, tx)); + } } static void @@ -305,15 +378,14 @@ feature_do_action(spa_t *spa, spa_feature_t fid, feature_action_t action, uint64_t zapobj = feature->fi_can_readonly ? spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj; - ASSERT3U(fid, <, SPA_FEATURES); + ASSERT(VALID_FEATURE_FID(fid)); ASSERT(0 != zapobj); ASSERT(zfeature_is_valid_guid(feature->fi_guid)); ASSERT(dmu_tx_is_syncing(tx)); ASSERT3U(spa_version(spa), >=, SPA_VERSION_FEATURES); - VERIFY0(zap_lookup(spa->spa_meta_objset, zapobj, feature->fi_guid, - sizeof (uint64_t), 1, &refcount)); + VERIFY3U(feature_get_refcount(spa, feature, &refcount), !=, ENOTSUP); switch (action) { case FEATURE_ACTION_INCR: @@ -360,7 +432,7 @@ void spa_feature_enable(spa_t *spa, spa_feature_t fid, dmu_tx_t *tx) { ASSERT3U(spa_version(spa), >=, SPA_VERSION_FEATURES); - ASSERT3U(fid, <, SPA_FEATURES); + ASSERT(VALID_FEATURE_FID(fid)); feature_enable_sync(spa, &spa_feature_table[fid], tx); } @@ -382,7 +454,7 @@ spa_feature_is_enabled(spa_t *spa, spa_feature_t fid) int err; uint64_t refcount; - ASSERT3U(fid, <, SPA_FEATURES); + ASSERT(VALID_FEATURE_FID(fid)); if (spa_version(spa) < SPA_VERSION_FEATURES) return (B_FALSE); @@ -397,7 +469,7 @@ spa_feature_is_active(spa_t *spa, spa_feature_t fid) int err; uint64_t refcount; - ASSERT3U(fid, <, SPA_FEATURES); + ASSERT(VALID_FEATURE_FID(fid)); if (spa_version(spa) < SPA_VERSION_FEATURES) return (B_FALSE); @@ -405,3 +477,26 @@ spa_feature_is_active(spa_t *spa, spa_feature_t fid) ASSERT(err == 0 || err == ENOTSUP); return (err == 0 && refcount > 0); } + +/* + * For the feature specified by fid (which must depend on + * SPA_FEATURE_ENABLED_TXG), return the TXG at which it was enabled in the + * OUT txg argument. + * + * Returns B_TRUE if the feature is enabled, in which case txg will be filled + * with the transaction group in which the specified feature was enabled. + * Returns B_FALSE otherwise (i.e. if the feature is not enabled). + */ +boolean_t +spa_feature_enabled_txg(spa_t *spa, spa_feature_t fid, uint64_t *txg) { + int err; + + ASSERT(VALID_FEATURE_FID(fid)); + if (spa_version(spa) < SPA_VERSION_FEATURES) + return (B_FALSE); + + err = feature_get_enabled_txg(spa, &spa_feature_table[fid], txg); + ASSERT(err == 0 || err == ENOTSUP); + + return (err == 0); +} |