summaryrefslogtreecommitdiffstats
path: root/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfeature.c
diff options
context:
space:
mode:
authordelphij <delphij@FreeBSD.org>2014-03-19 23:55:03 +0000
committerdelphij <delphij@FreeBSD.org>2014-03-19 23:55:03 +0000
commitede49d4106ad9e6d34a2592322e48604f72605bd (patch)
tree0012bcb04d95eaf4e65ed2f983e9d51d47236888 /sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfeature.c
parent8e41bb96f82aa123d5f4c625c68f95b253640b28 (diff)
downloadFreeBSD-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.c111
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);
+}
OpenPOWER on IntegriCloud