]> granicus.if.org Git - zfs/commitdiff
Add types to featureflags in zfs
authorPaul Dagnelie <paulcd2000@gmail.com>
Tue, 16 Oct 2018 18:15:04 +0000 (11:15 -0700)
committerMatthew Ahrens <mahrens@delphix.com>
Tue, 16 Oct 2018 18:15:04 +0000 (11:15 -0700)
The boolean featureflags in use thus far in ZFS are extremely useful,
but because they take advantage of the zap layer, more interesting data
than just a true/false value can be stored in a featureflag. In redacted
send/receive, this is used to store the list of redaction snapshots for
a redacted dataset.

This change adds the ability for ZFS to store types other than a boolean
in a featureflag. The only other implemented type is a uint64_t array.
It also modifies the interfaces around dataset features to accomodate
the new capabilities, and adds a few new functions to increase
encapsulation.

This functionality will be used by the Redacted Send/Receive feature.

Reviewed-by: Matthew Ahrens <mahrens@delphix.com>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Paul Dagnelie <pcd@delphix.com>
Closes #7981

cmd/zdb/zdb.c
include/sys/dsl_dataset.h
include/zfeature_common.h
module/zcommon/zfeature_common.c
module/zfs/dmu_object.c
module/zfs/dmu_objset.c
module/zfs/dmu_send.c
module/zfs/dnode_sync.c
module/zfs/dsl_crypt.c
module/zfs/dsl_dataset.c
module/zfs/dsl_destroy.c

index 6072783c3527c1488059c5f8ebafabd2be778e12..ad4ebe00a65eee1ee9955ce5fe9a98e776de7637 100644 (file)
@@ -3219,7 +3219,7 @@ dump_one_dir(const char *dsname, void *arg)
                return (0);
 
        for (f = 0; f < SPA_FEATURES; f++) {
-               if (!dmu_objset_ds(os)->ds_feature_inuse[f])
+               if (!dsl_dataset_feature_is_active(dmu_objset_ds(os), f))
                        continue;
                ASSERT(spa_feature_table[f].fi_flags &
                    ZFEATURE_FLAG_PER_DATASET);
index 7eded35a185a85c6e5e828d032120ea0560aee99..47a46f07d3fed46845b8b95d3867dbdb4b02efbb 100644 (file)
@@ -20,7 +20,7 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, 2017 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2018 by Delphix. All rights reserved.
  * Copyright (c) 2013 Steven Hartland. All rights reserved.
  * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
  */
@@ -242,13 +242,13 @@ typedef struct dsl_dataset {
         * For ZFEATURE_FLAG_PER_DATASET features, set if this dataset
         * uses this feature.
         */
-       uint8_t ds_feature_inuse[SPA_FEATURES];
+       void *ds_feature[SPA_FEATURES];
 
        /*
         * Set if we need to activate the feature on this dataset this txg
         * (used only in syncing context).
         */
-       uint8_t ds_feature_activation_needed[SPA_FEATURES];
+       void *ds_feature_activation[SPA_FEATURES];
 
        /* Protected by ds_lock; keep at end of struct for better locality */
        char ds_snapname[ZFS_MAX_DATASET_NAME_LEN];
@@ -449,10 +449,13 @@ void dsl_dataset_create_remap_deadlist(dsl_dataset_t *ds, dmu_tx_t *tx);
 boolean_t dsl_dataset_remap_deadlist_exists(dsl_dataset_t *ds);
 void dsl_dataset_destroy_remap_deadlist(dsl_dataset_t *ds, dmu_tx_t *tx);
 
-void dsl_dataset_activate_feature(uint64_t dsobj,
-    spa_feature_t f, dmu_tx_t *tx);
-void dsl_dataset_deactivate_feature(uint64_t dsobj,
-    spa_feature_t f, dmu_tx_t *tx);
+void dsl_dataset_activate_feature(uint64_t dsobj, spa_feature_t f, void *arg,
+    dmu_tx_t *tx);
+void dsl_dataset_deactivate_feature(dsl_dataset_t *ds, spa_feature_t f,
+    dmu_tx_t *tx);
+boolean_t dsl_dataset_feature_is_active(dsl_dataset_t *ds, spa_feature_t f);
+boolean_t dsl_dataset_get_uint64_array_feature(dsl_dataset_t *ds,
+    spa_feature_t f, uint64_t *outlength, uint64_t **outp);
 
 #ifdef ZFS_DEBUG
 #define        dprintf_ds(ds, fmt, ...) do { \
index 84bc7f816734a17c73e6c655ab70d6b23d223549..3804d7b1abdda8d3e97350681c6b2ba7bde41741 100644 (file)
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright (c) 2011, 2017 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2018 by Delphix. All rights reserved.
  * Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
  * Copyright (c) 2013, Joyent, Inc. All rights reserved.
  * Copyright (c) 2017, Intel Corporation.
@@ -73,7 +73,10 @@ typedef enum spa_feature {
 typedef enum zfeature_flags {
        /* Can open pool readonly even if this feature is not supported. */
        ZFEATURE_FLAG_READONLY_COMPAT =         (1 << 0),
-       /* Is this feature necessary to read the MOS? */
+       /*
+        * Is this feature necessary to load the pool? i.e. do we need this
+        * feature to read the full feature list out of the MOS?
+        */
        ZFEATURE_FLAG_MOS =                     (1 << 1),
        /* Activate this feature at the same time it is enabled. */
        ZFEATURE_FLAG_ACTIVATE_ON_ENABLE =      (1 << 2),
@@ -81,6 +84,12 @@ typedef enum zfeature_flags {
        ZFEATURE_FLAG_PER_DATASET =             (1 << 3)
 } zfeature_flags_t;
 
+typedef enum zfeature_type {
+       ZFEATURE_TYPE_BOOLEAN,
+       ZFEATURE_TYPE_UINT64_ARRAY,
+       ZFEATURE_NUM_TYPES
+} zfeature_type_t;
+
 typedef struct zfeature_info {
        spa_feature_t fi_feature;
        const char *fi_uname;   /* User-facing feature name */
@@ -88,6 +97,7 @@ typedef struct zfeature_info {
        const char *fi_desc;    /* Feature description */
        zfeature_flags_t fi_flags;
        boolean_t fi_zfs_mod_supported; /* supported by running zfs module */
+       zfeature_type_t fi_type; /* Only relevant for PER_DATASET features */
        /* array of dependencies, terminated by SPA_FEATURE_NONE */
        const spa_feature_t *fi_depends;
 } zfeature_info_t;
index e630481cbff31e55b121002e2823cede8982365e..a0ad108c50f1cdc59bb0c41062ede36335bd6f44 100644 (file)
@@ -203,7 +203,8 @@ zfs_mod_supported_feature(const char *name)
 
 static void
 zfeature_register(spa_feature_t fid, const char *guid, const char *name,
-    const char *desc, zfeature_flags_t flags, const spa_feature_t *deps)
+    const char *desc, zfeature_flags_t flags, zfeature_type_t type,
+    const spa_feature_t *deps)
 {
        zfeature_info_t *feature = &spa_feature_table[fid];
        static spa_feature_t nodeps[] = { SPA_FEATURE_NONE };
@@ -226,6 +227,7 @@ zfeature_register(spa_feature_t fid, const char *guid, const char *name,
        feature->fi_uname = name;
        feature->fi_desc = desc;
        feature->fi_flags = flags;
+       feature->fi_type = type;
        feature->fi_depends = deps;
        feature->fi_zfs_mod_supported = zfs_mod_supported_feature(guid);
 }
@@ -236,32 +238,32 @@ zpool_feature_init(void)
        zfeature_register(SPA_FEATURE_ASYNC_DESTROY,
            "com.delphix:async_destroy", "async_destroy",
            "Destroy filesystems asynchronously.",
-           ZFEATURE_FLAG_READONLY_COMPAT, NULL);
+           ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL);
 
        zfeature_register(SPA_FEATURE_EMPTY_BPOBJ,
            "com.delphix:empty_bpobj", "empty_bpobj",
            "Snapshots use less space.",
-           ZFEATURE_FLAG_READONLY_COMPAT, NULL);
+           ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL);
 
        zfeature_register(SPA_FEATURE_LZ4_COMPRESS,
            "org.illumos:lz4_compress", "lz4_compress",
            "LZ4 compression algorithm support.",
-           ZFEATURE_FLAG_ACTIVATE_ON_ENABLE, NULL);
+           ZFEATURE_FLAG_ACTIVATE_ON_ENABLE, ZFEATURE_TYPE_BOOLEAN, NULL);
 
        zfeature_register(SPA_FEATURE_MULTI_VDEV_CRASH_DUMP,
            "com.joyent:multi_vdev_crash_dump", "multi_vdev_crash_dump",
            "Crash dumps to multiple vdev pools.",
-           0, NULL);
+           0, ZFEATURE_TYPE_BOOLEAN, NULL);
 
        zfeature_register(SPA_FEATURE_SPACEMAP_HISTOGRAM,
            "com.delphix:spacemap_histogram", "spacemap_histogram",
            "Spacemaps maintain space histograms.",
-           ZFEATURE_FLAG_READONLY_COMPAT, NULL);
+           ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL);
 
        zfeature_register(SPA_FEATURE_ENABLED_TXG,
            "com.delphix:enabled_txg", "enabled_txg",
            "Record txg at which a feature is enabled",
-           ZFEATURE_FLAG_READONLY_COMPAT, NULL);
+           ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL);
 
        {
        static const spa_feature_t hole_birth_deps[] = {
@@ -272,24 +274,24 @@ zpool_feature_init(void)
            "com.delphix:hole_birth", "hole_birth",
            "Retain hole birth txg for more precise zfs send",
            ZFEATURE_FLAG_MOS | ZFEATURE_FLAG_ACTIVATE_ON_ENABLE,
-           hole_birth_deps);
+           ZFEATURE_TYPE_BOOLEAN, hole_birth_deps);
        }
 
        zfeature_register(SPA_FEATURE_POOL_CHECKPOINT,
            "com.delphix:zpool_checkpoint", "zpool_checkpoint",
            "Pool state can be checkpointed, allowing rewind later.",
-           ZFEATURE_FLAG_READONLY_COMPAT, NULL);
+           ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL);
 
        zfeature_register(SPA_FEATURE_SPACEMAP_V2,
            "com.delphix:spacemap_v2", "spacemap_v2",
            "Space maps representing large segments are more efficient.",
            ZFEATURE_FLAG_READONLY_COMPAT | ZFEATURE_FLAG_ACTIVATE_ON_ENABLE,
-           NULL);
+           ZFEATURE_TYPE_BOOLEAN, NULL);
 
        zfeature_register(SPA_FEATURE_EXTENSIBLE_DATASET,
            "com.delphix:extensible_dataset", "extensible_dataset",
            "Enhanced dataset functionality, used by other features.",
-           0, NULL);
+           0, ZFEATURE_TYPE_BOOLEAN, NULL);
 
        {
        static const spa_feature_t bookmarks_deps[] = {
@@ -300,7 +302,8 @@ zpool_feature_init(void)
        zfeature_register(SPA_FEATURE_BOOKMARKS,
            "com.delphix:bookmarks", "bookmarks",
            "\"zfs bookmark\" command",
-           ZFEATURE_FLAG_READONLY_COMPAT, bookmarks_deps);
+           ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN,
+           bookmarks_deps);
        }
 
        {
@@ -311,14 +314,15 @@ zpool_feature_init(void)
        zfeature_register(SPA_FEATURE_FS_SS_LIMIT,
            "com.joyent:filesystem_limits", "filesystem_limits",
            "Filesystem and snapshot limits.",
-           ZFEATURE_FLAG_READONLY_COMPAT, filesystem_limits_deps);
+           ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN,
+           filesystem_limits_deps);
        }
 
        zfeature_register(SPA_FEATURE_EMBEDDED_DATA,
            "com.delphix:embedded_data", "embedded_data",
            "Blocks which compress very well use even less space.",
            ZFEATURE_FLAG_MOS | ZFEATURE_FLAG_ACTIVATE_ON_ENABLE,
-           NULL);
+           ZFEATURE_TYPE_BOOLEAN, NULL);
 
        {
        static const spa_feature_t large_blocks_deps[] = {
@@ -328,7 +332,8 @@ zpool_feature_init(void)
        zfeature_register(SPA_FEATURE_LARGE_BLOCKS,
            "org.open-zfs:large_blocks", "large_blocks",
            "Support for blocks larger than 128KB.",
-           ZFEATURE_FLAG_PER_DATASET, large_blocks_deps);
+           ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN,
+           large_blocks_deps);
        }
 
        {
@@ -339,7 +344,8 @@ zpool_feature_init(void)
        zfeature_register(SPA_FEATURE_LARGE_DNODE,
            "org.zfsonlinux:large_dnode", "large_dnode",
            "Variable on-disk size of dnodes.",
-           ZFEATURE_FLAG_PER_DATASET, large_dnode_deps);
+           ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN,
+           large_dnode_deps);
        }
 
        {
@@ -350,8 +356,10 @@ zpool_feature_init(void)
        zfeature_register(SPA_FEATURE_SHA512,
            "org.illumos:sha512", "sha512",
            "SHA-512/256 hash algorithm.",
-           ZFEATURE_FLAG_PER_DATASET, sha512_deps);
+           ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN,
+           sha512_deps);
        }
+
        {
        static const spa_feature_t skein_deps[] = {
                SPA_FEATURE_EXTENSIBLE_DATASET,
@@ -360,7 +368,8 @@ zpool_feature_init(void)
        zfeature_register(SPA_FEATURE_SKEIN,
            "org.illumos:skein", "skein",
            "Skein hash algorithm.",
-           ZFEATURE_FLAG_PER_DATASET, skein_deps);
+           ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN,
+           skein_deps);
        }
 
        {
@@ -371,12 +380,15 @@ zpool_feature_init(void)
        zfeature_register(SPA_FEATURE_EDONR,
            "org.illumos:edonr", "edonr",
            "Edon-R hash algorithm.",
-           ZFEATURE_FLAG_PER_DATASET, edonr_deps);
+           ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN,
+           edonr_deps);
        }
+
        zfeature_register(SPA_FEATURE_DEVICE_REMOVAL,
            "com.delphix:device_removal", "device_removal",
            "Top-level vdevs can be removed, reducing logical pool size.",
-           ZFEATURE_FLAG_MOS, NULL);
+           ZFEATURE_FLAG_MOS, ZFEATURE_TYPE_BOOLEAN, NULL);
+
        {
        static const spa_feature_t obsolete_counts_deps[] = {
                SPA_FEATURE_EXTENSIBLE_DATASET,
@@ -387,8 +399,10 @@ zpool_feature_init(void)
            "com.delphix:obsolete_counts", "obsolete_counts",
            "Reduce memory used by removed devices when their blocks are "
            "freed or remapped.",
-           ZFEATURE_FLAG_READONLY_COMPAT, obsolete_counts_deps);
+           ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN,
+           obsolete_counts_deps);
        }
+
        {
        static const spa_feature_t userobj_accounting_deps[] = {
                SPA_FEATURE_EXTENSIBLE_DATASET,
@@ -398,7 +412,7 @@ zpool_feature_init(void)
            "org.zfsonlinux:userobj_accounting", "userobj_accounting",
            "User/Group object accounting.",
            ZFEATURE_FLAG_READONLY_COMPAT | ZFEATURE_FLAG_PER_DATASET,
-           userobj_accounting_deps);
+           ZFEATURE_TYPE_BOOLEAN, userobj_accounting_deps);
        }
 
        {
@@ -409,7 +423,8 @@ zpool_feature_init(void)
        zfeature_register(SPA_FEATURE_ENCRYPTION,
            "com.datto:encryption", "encryption",
            "Support for dataset level encryption",
-           ZFEATURE_FLAG_PER_DATASET, encryption_deps);
+           ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN,
+           encryption_deps);
        }
 
        {
@@ -421,14 +436,14 @@ zpool_feature_init(void)
            "org.zfsonlinux:project_quota", "project_quota",
            "space/object accounting based on project ID.",
            ZFEATURE_FLAG_READONLY_COMPAT | ZFEATURE_FLAG_PER_DATASET,
-           project_quota_deps);
+           ZFEATURE_TYPE_BOOLEAN, project_quota_deps);
        }
 
        {
        zfeature_register(SPA_FEATURE_ALLOCATION_CLASSES,
            "org.zfsonlinux:allocation_classes", "allocation_classes",
            "Support for separate allocation classes.",
-           ZFEATURE_FLAG_READONLY_COMPAT, NULL);
+           ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL);
        }
 }
 
index afee869b6d767bacead69dc4f4d443b919b795af..9b5cf125f397b724f87b925b2424ec6fbaa2c76a 100644 (file)
@@ -337,7 +337,8 @@ dmu_object_next(objset_t *os, uint64_t *objectp, boolean_t hole, uint64_t txg)
 
        if (*objectp == 0) {
                start_obj = 1;
-       } else if (ds && ds->ds_feature_inuse[SPA_FEATURE_LARGE_DNODE]) {
+       } else if (ds && dsl_dataset_feature_is_active(ds,
+           SPA_FEATURE_LARGE_DNODE)) {
                uint64_t i = *objectp + 1;
                uint64_t last_obj = *objectp | (DNODES_PER_BLOCK - 1);
                dmu_object_info_t doi;
index 7ad1d618aad275f8661b2b4d9ccf74a1b2307be8..a8304c18df28dbf7c400cd6e13263d13c3b9cbbb 100644 (file)
@@ -21,7 +21,7 @@
 
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2017 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2018 by Delphix. All rights reserved.
  * Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
  * Copyright (c) 2013, Joyent, Inc. All rights reserved.
  * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
@@ -1073,14 +1073,14 @@ dmu_objset_create_impl_dnstats(spa_t *spa, dsl_dataset_t *ds, blkptr_t *bp,
            (!os->os_encrypted || !dmu_objset_is_receiving(os))) {
                os->os_phys->os_flags |= OBJSET_FLAG_USERACCOUNTING_COMPLETE;
                if (dmu_objset_userobjused_enabled(os)) {
-                       ds->ds_feature_activation_needed[
-                           SPA_FEATURE_USEROBJ_ACCOUNTING] = B_TRUE;
+                       ds->ds_feature_activation[
+                           SPA_FEATURE_USEROBJ_ACCOUNTING] = (void *)B_TRUE;
                        os->os_phys->os_flags |=
                            OBJSET_FLAG_USEROBJACCOUNTING_COMPLETE;
                }
                if (dmu_objset_projectquota_enabled(os)) {
-                       ds->ds_feature_activation_needed[
-                           SPA_FEATURE_PROJECT_QUOTA] = B_TRUE;
+                       ds->ds_feature_activation[
+                           SPA_FEATURE_PROJECT_QUOTA] = (void *)B_TRUE;
                        os->os_phys->os_flags |=
                            OBJSET_FLAG_PROJECTQUOTA_COMPLETE;
                }
@@ -2377,11 +2377,11 @@ dmu_objset_id_quota_upgrade_cb(objset_t *os)
            dmu_objset_userobjspace_present(os))
                return (SET_ERROR(ENOTSUP));
 
-       dmu_objset_ds(os)->ds_feature_activation_needed[
-           SPA_FEATURE_USEROBJ_ACCOUNTING] = B_TRUE;
+       dmu_objset_ds(os)->ds_feature_activation[
+           SPA_FEATURE_USEROBJ_ACCOUNTING] = (void *)B_TRUE;
        if (dmu_objset_projectquota_enabled(os))
-               dmu_objset_ds(os)->ds_feature_activation_needed[
-                   SPA_FEATURE_PROJECT_QUOTA] = B_TRUE;
+               dmu_objset_ds(os)->ds_feature_activation[
+                   SPA_FEATURE_PROJECT_QUOTA] = (void *)B_TRUE;
 
        err = dmu_objset_space_upgrade(os);
        if (err)
index 24f663d3f103a2c8f2f37721ae773954da15b4c6..9c0ad406b13647e8e846e16ff6fca9ed8ee1a099 100644 (file)
@@ -1022,9 +1022,9 @@ dmu_send_impl(void *tag, dsl_pool_t *dp, dsl_dataset_t *to_ds,
 
        /* raw sends imply large_block_ok */
        if ((large_block_ok || rawok) &&
-           to_ds->ds_feature_inuse[SPA_FEATURE_LARGE_BLOCKS])
+           dsl_dataset_feature_is_active(to_ds, SPA_FEATURE_LARGE_BLOCKS))
                featureflags |= DMU_BACKUP_FEATURE_LARGE_BLOCKS;
-       if (to_ds->ds_feature_inuse[SPA_FEATURE_LARGE_DNODE])
+       if (dsl_dataset_feature_is_active(to_ds, SPA_FEATURE_LARGE_DNODE))
                featureflags |= DMU_BACKUP_FEATURE_LARGE_DNODE;
 
        /* encrypted datasets will not have embedded blocks */
index e42f337edbd2de7eff25c27e8c47cab6c4f53050..c4062beb3173590d7e011ad95582340befea69ba 100644 (file)
@@ -753,8 +753,8 @@ dnode_sync(dnode_t *dn, dmu_tx_t *tx)
        if (dn->dn_num_slots > DNODE_MIN_SLOTS) {
                dsl_dataset_t *ds = dn->dn_objset->os_dsl_dataset;
                mutex_enter(&ds->ds_lock);
-               ds->ds_feature_activation_needed[SPA_FEATURE_LARGE_DNODE] =
-                   B_TRUE;
+               ds->ds_feature_activation[SPA_FEATURE_LARGE_DNODE] =
+                   (void *)B_TRUE;
                mutex_exit(&ds->ds_lock);
        }
 
index 0eeb260c378fbc2c85c4ec0feb89bf45c46f12e0..d2545c6fa41b5b6f90bbc5fb1749d5d1d1f9aa8e 100644 (file)
@@ -15,6 +15,7 @@
 
 /*
  * Copyright (c) 2017, Datto, Inc. All rights reserved.
+ * Copyright (c) 2018 by Delphix. All rights reserved.
  */
 
 #include <sys/dsl_crypt.h>
@@ -1938,7 +1939,8 @@ dsl_dataset_create_crypt_sync(uint64_t dsobj, dsl_dir_t *dd,
        VERIFY0(zap_add(dp->dp_meta_objset, dd->dd_object,
            DD_FIELD_CRYPTO_KEY_OBJ, sizeof (uint64_t), 1, &dd->dd_crypto_obj,
            tx));
-       dsl_dataset_activate_feature(dsobj, SPA_FEATURE_ENCRYPTION, tx);
+       dsl_dataset_activate_feature(dsobj, SPA_FEATURE_ENCRYPTION,
+           (void *)B_TRUE, tx);
 
        /*
         * If we inherited the wrapping key we release our reference now.
@@ -2249,8 +2251,8 @@ dsl_crypto_recv_raw_key_sync(dsl_dataset_t *ds, nvlist_t *nvl, dmu_tx_t *tx)
                    sizeof (uint64_t), 1, &version, tx));
 
                dsl_dataset_activate_feature(ds->ds_object,
-                   SPA_FEATURE_ENCRYPTION, tx);
-               ds->ds_feature_inuse[SPA_FEATURE_ENCRYPTION] = B_TRUE;
+                   SPA_FEATURE_ENCRYPTION, (void *)B_TRUE, tx);
+               ds->ds_feature[SPA_FEATURE_ENCRYPTION] = (void *)B_TRUE;
 
                /* save the dd_crypto_obj on disk */
                VERIFY0(zap_add(mos, dd->dd_object, DD_FIELD_CRYPTO_KEY_OBJ,
index 5d98f460a4965c17a142cebad7ebfad87c70dab7..168aea861637d7c72800989385455ac0ccb62bed 100644 (file)
@@ -21,7 +21,7 @@
 
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, 2017 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2018 by Delphix. All rights reserved.
  * Copyright (c) 2014, Joyent, Inc. All rights reserved.
  * Copyright (c) 2014 RackTop Systems.
  * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
@@ -89,6 +89,8 @@ static void dsl_dataset_set_remap_deadlist_object(dsl_dataset_t *ds,
 static void dsl_dataset_unset_remap_deadlist_object(dsl_dataset_t *ds,
     dmu_tx_t *tx);
 
+static void unload_zfeature(dsl_dataset_t *ds, spa_feature_t f);
+
 extern int spa_asize_inflation;
 
 static zil_header_t zero_zil;
@@ -149,13 +151,16 @@ dsl_dataset_block_born(dsl_dataset_t *ds, const blkptr_t *bp, dmu_tx_t *tx)
        dsl_dataset_phys(ds)->ds_unique_bytes += used;
 
        if (BP_GET_LSIZE(bp) > SPA_OLD_MAXBLOCKSIZE) {
-               ds->ds_feature_activation_needed[SPA_FEATURE_LARGE_BLOCKS] =
-                   B_TRUE;
+               ds->ds_feature_activation[SPA_FEATURE_LARGE_BLOCKS] =
+                   (void *)B_TRUE;
        }
 
        spa_feature_t f = zio_checksum_to_feature(BP_GET_CHECKSUM(bp));
-       if (f != SPA_FEATURE_NONE)
-               ds->ds_feature_activation_needed[f] = B_TRUE;
+       if (f != SPA_FEATURE_NONE) {
+               ASSERT3S(spa_feature_table[f].fi_type, ==,
+                   ZFEATURE_TYPE_BOOLEAN);
+               ds->ds_feature_activation[f] = (void *)B_TRUE;
+       }
 
        mutex_exit(&ds->ds_lock);
        dsl_dir_diduse_space(ds->ds_dir, DD_USED_HEAD, delta,
@@ -291,6 +296,72 @@ dsl_dataset_block_kill(dsl_dataset_t *ds, const blkptr_t *bp, dmu_tx_t *tx,
        return (used);
 }
 
+struct feature_type_uint64_array_arg {
+       uint64_t length;
+       uint64_t *array;
+};
+
+static void
+unload_zfeature(dsl_dataset_t *ds, spa_feature_t f)
+{
+       switch (spa_feature_table[f].fi_type) {
+       case ZFEATURE_TYPE_BOOLEAN:
+               break;
+       case ZFEATURE_TYPE_UINT64_ARRAY:
+       {
+               struct feature_type_uint64_array_arg *ftuaa = ds->ds_feature[f];
+               kmem_free(ftuaa->array, ftuaa->length * sizeof (uint64_t));
+               kmem_free(ftuaa, sizeof (*ftuaa));
+               break;
+       }
+       default:
+               panic("Invalid zfeature type %d", spa_feature_table[f].fi_type);
+       }
+}
+
+static int
+load_zfeature(objset_t *mos, dsl_dataset_t *ds, spa_feature_t f)
+{
+       int err = 0;
+       switch (spa_feature_table[f].fi_type) {
+       case ZFEATURE_TYPE_BOOLEAN:
+               err = zap_contains(mos, ds->ds_object,
+                   spa_feature_table[f].fi_guid);
+               if (err == 0) {
+                       ds->ds_feature[f] = (void *)B_TRUE;
+               } else {
+                       ASSERT3U(err, ==, ENOENT);
+                       err = 0;
+               }
+               break;
+       case ZFEATURE_TYPE_UINT64_ARRAY:
+       {
+               uint64_t int_size, num_int;
+               uint64_t *data;
+               err = zap_length(mos, ds->ds_object,
+                   spa_feature_table[f].fi_guid, &int_size, &num_int);
+               if (err != 0) {
+                       ASSERT3U(err, ==, ENOENT);
+                       err = 0;
+                       break;
+               }
+               ASSERT3U(int_size, ==, sizeof (uint64_t));
+               data = kmem_alloc(int_size * num_int, KM_SLEEP);
+               VERIFY0(zap_lookup(mos, ds->ds_object,
+                   spa_feature_table[f].fi_guid, int_size, num_int, data));
+               struct feature_type_uint64_array_arg *ftuaa =
+                   kmem_alloc(sizeof (*ftuaa), KM_SLEEP);
+               ftuaa->length = num_int;
+               ftuaa->array = data;
+               ds->ds_feature[f] = ftuaa;
+               break;
+       }
+       default:
+               panic("Invalid zfeature type %d", spa_feature_table[f].fi_type);
+       }
+       return (err);
+}
+
 /*
  * We have to release the fsid syncronously or we risk that a subsequent
  * mount of the same dataset will fail to unique_insert the fsid.  This
@@ -334,6 +405,11 @@ dsl_dataset_evict_async(void *dbu)
 
        ASSERT(!list_link_active(&ds->ds_synced_link));
 
+       for (spa_feature_t f = 0; f < SPA_FEATURES; f++) {
+               if (dsl_dataset_feature_is_active(ds, f))
+                       unload_zfeature(ds, f);
+       }
+
        list_destroy(&ds->ds_prop_cbs);
        mutex_destroy(&ds->ds_lock);
        mutex_destroy(&ds->ds_opening_lock);
@@ -501,14 +577,7 @@ dsl_dataset_hold_obj(dsl_pool_t *dp, uint64_t dsobj, void *tag,
                                if (!(spa_feature_table[f].fi_flags &
                                    ZFEATURE_FLAG_PER_DATASET))
                                        continue;
-                               err = zap_contains(mos, dsobj,
-                                   spa_feature_table[f].fi_guid);
-                               if (err == 0) {
-                                       ds->ds_feature_inuse[f] = B_TRUE;
-                               } else {
-                                       ASSERT3U(err, ==, ENOENT);
-                                       err = 0;
-                               }
+                               err = load_zfeature(mos, ds, f);
                        }
                }
 
@@ -872,8 +941,55 @@ dsl_dataset_has_owner(dsl_dataset_t *ds)
        return (rv);
 }
 
+static boolean_t
+zfeature_active(spa_feature_t f, void *arg)
+{
+       switch (spa_feature_table[f].fi_type) {
+       case ZFEATURE_TYPE_BOOLEAN: {
+               boolean_t val = (boolean_t)arg;
+               ASSERT(val == B_FALSE || val == B_TRUE);
+               return (val);
+       }
+       case ZFEATURE_TYPE_UINT64_ARRAY:
+               /*
+                * In this case, arg is a uint64_t array.  The feature is active
+                * if the array is non-null.
+                */
+               return (arg != NULL);
+       default:
+               panic("Invalid zfeature type %d", spa_feature_table[f].fi_type);
+               return (B_FALSE);
+       }
+}
+
+boolean_t
+dsl_dataset_feature_is_active(dsl_dataset_t *ds, spa_feature_t f)
+{
+       return (zfeature_active(f, ds->ds_feature[f]));
+}
+
+/*
+ * The buffers passed out by this function are references to internal buffers;
+ * they should not be freed by callers of this function, and they should not be
+ * used after the dataset has been released.
+ */
+boolean_t
+dsl_dataset_get_uint64_array_feature(dsl_dataset_t *ds, spa_feature_t f,
+    uint64_t *outlength, uint64_t **outp)
+{
+       VERIFY(spa_feature_table[f].fi_type & ZFEATURE_TYPE_UINT64_ARRAY);
+       if (!dsl_dataset_feature_is_active(ds, f)) {
+               return (B_FALSE);
+       }
+       struct feature_type_uint64_array_arg *ftuaa = ds->ds_feature[f];
+       *outp = ftuaa->array;
+       *outlength = ftuaa->length;
+       return (B_TRUE);
+}
+
 void
-dsl_dataset_activate_feature(uint64_t dsobj, spa_feature_t f, dmu_tx_t *tx)
+dsl_dataset_activate_feature(uint64_t dsobj, spa_feature_t f, void *arg,
+    dmu_tx_t *tx)
 {
        spa_t *spa = dmu_tx_pool(tx)->dp_spa;
        objset_t *mos = dmu_tx_pool(tx)->dp_meta_objset;
@@ -884,20 +1000,44 @@ dsl_dataset_activate_feature(uint64_t dsobj, spa_feature_t f, dmu_tx_t *tx)
        spa_feature_incr(spa, f, tx);
        dmu_object_zapify(mos, dsobj, DMU_OT_DSL_DATASET, tx);
 
-       VERIFY0(zap_add(mos, dsobj, spa_feature_table[f].fi_guid,
-           sizeof (zero), 1, &zero, tx));
+       switch (spa_feature_table[f].fi_type) {
+       case ZFEATURE_TYPE_BOOLEAN:
+               ASSERT3S((boolean_t)arg, ==, B_TRUE);
+               VERIFY0(zap_add(mos, dsobj, spa_feature_table[f].fi_guid,
+                   sizeof (zero), 1, &zero, tx));
+               break;
+       case ZFEATURE_TYPE_UINT64_ARRAY:
+       {
+               struct feature_type_uint64_array_arg *ftuaa = arg;
+               VERIFY0(zap_add(mos, dsobj, spa_feature_table[f].fi_guid,
+                   sizeof (uint64_t), ftuaa->length, ftuaa->array, tx));
+               break;
+       }
+       default:
+               panic("Invalid zfeature type %d", spa_feature_table[f].fi_type);
+       }
 }
 
 void
-dsl_dataset_deactivate_feature(uint64_t dsobj, spa_feature_t f, dmu_tx_t *tx)
+dsl_dataset_deactivate_feature_impl(dsl_dataset_t *ds, spa_feature_t f,
+    dmu_tx_t *tx)
 {
        spa_t *spa = dmu_tx_pool(tx)->dp_spa;
        objset_t *mos = dmu_tx_pool(tx)->dp_meta_objset;
+       uint64_t dsobj = ds->ds_object;
 
        VERIFY(spa_feature_table[f].fi_flags & ZFEATURE_FLAG_PER_DATASET);
 
        VERIFY0(zap_remove(mos, dsobj, spa_feature_table[f].fi_guid, tx));
        spa_feature_decr(spa, f, tx);
+       ds->ds_feature[f] = NULL;
+}
+
+void
+dsl_dataset_deactivate_feature(dsl_dataset_t *ds, spa_feature_t f, dmu_tx_t *tx)
+{
+       unload_zfeature(ds, f);
+       dsl_dataset_deactivate_feature_impl(ds, f, tx);
 }
 
 uint64_t
@@ -961,8 +1101,10 @@ dsl_dataset_create_sync_dd(dsl_dir_t *dd, dsl_dataset_t *origin,
                    (DS_FLAG_INCONSISTENT | DS_FLAG_CI_DATASET);
 
                for (spa_feature_t f = 0; f < SPA_FEATURES; f++) {
-                       if (origin->ds_feature_inuse[f])
-                               dsl_dataset_activate_feature(dsobj, f, tx);
+                       if (zfeature_active(f, origin->ds_feature[f])) {
+                               dsl_dataset_activate_feature(dsobj, f,
+                                   origin->ds_feature[f], tx);
+                       }
                }
 
                dmu_buf_will_dirty(origin->ds_dbuf, tx);
@@ -1492,8 +1634,10 @@ dsl_dataset_snapshot_sync_impl(dsl_dataset_t *ds, const char *snapname,
        dmu_buf_rele(dbuf, FTAG);
 
        for (spa_feature_t f = 0; f < SPA_FEATURES; f++) {
-               if (ds->ds_feature_inuse[f])
-                       dsl_dataset_activate_feature(dsobj, f, tx);
+               if (zfeature_active(f, ds->ds_feature[f])) {
+                       dsl_dataset_activate_feature(dsobj, f,
+                           ds->ds_feature[f], tx);
+               }
        }
 
        ASSERT3U(ds->ds_prev != 0, ==,
@@ -1808,11 +1952,12 @@ dsl_dataset_sync(dsl_dataset_t *ds, zio_t *zio, dmu_tx_t *tx)
        dmu_objset_sync(ds->ds_objset, zio, tx);
 
        for (spa_feature_t f = 0; f < SPA_FEATURES; f++) {
-               if (ds->ds_feature_activation_needed[f]) {
-                       if (ds->ds_feature_inuse[f])
+               if (zfeature_active(f, ds->ds_feature_activation[f])) {
+                       if (zfeature_active(f, ds->ds_feature[f]))
                                continue;
-                       dsl_dataset_activate_feature(ds->ds_object, f, tx);
-                       ds->ds_feature_inuse[f] = B_TRUE;
+                       dsl_dataset_activate_feature(ds->ds_object, f,
+                           ds->ds_feature_activation[f], tx);
+                       ds->ds_feature[f] = ds->ds_feature_activation[f];
                }
        }
 }
@@ -3530,31 +3675,31 @@ dsl_dataset_clone_swap_sync_impl(dsl_dataset_t *clone,
        for (spa_feature_t f = 0; f < SPA_FEATURES; f++) {
                if (!(spa_feature_table[f].fi_flags &
                    ZFEATURE_FLAG_PER_DATASET)) {
-                       ASSERT(!clone->ds_feature_inuse[f]);
-                       ASSERT(!origin_head->ds_feature_inuse[f]);
+                       ASSERT(!dsl_dataset_feature_is_active(clone, f));
+                       ASSERT(!dsl_dataset_feature_is_active(origin_head, f));
                        continue;
                }
 
-               boolean_t clone_inuse = clone->ds_feature_inuse[f];
-               boolean_t origin_head_inuse = origin_head->ds_feature_inuse[f];
+               boolean_t clone_inuse = dsl_dataset_feature_is_active(clone, f);
+               void *clone_feature = clone->ds_feature[f];
+               boolean_t origin_head_inuse =
+                   dsl_dataset_feature_is_active(origin_head, f);
+               void *origin_head_feature = origin_head->ds_feature[f];
+
+               if (clone_inuse)
+                       dsl_dataset_deactivate_feature_impl(clone, f, tx);
+               if (origin_head_inuse)
+                       dsl_dataset_deactivate_feature_impl(origin_head, f, tx);
 
                if (clone_inuse) {
-                       dsl_dataset_deactivate_feature(clone->ds_object, f, tx);
-                       clone->ds_feature_inuse[f] = B_FALSE;
-               }
-               if (origin_head_inuse) {
-                       dsl_dataset_deactivate_feature(origin_head->ds_object,
-                           f, tx);
-                       origin_head->ds_feature_inuse[f] = B_FALSE;
-               }
-               if (clone_inuse) {
-                       dsl_dataset_activate_feature(origin_head->ds_object,
-                           f, tx);
-                       origin_head->ds_feature_inuse[f] = B_TRUE;
+                       dsl_dataset_activate_feature(origin_head->ds_object, f,
+                           clone_feature, tx);
+                       origin_head->ds_feature[f] = clone_feature;
                }
                if (origin_head_inuse) {
-                       dsl_dataset_activate_feature(clone->ds_object, f, tx);
-                       clone->ds_feature_inuse[f] = B_TRUE;
+                       dsl_dataset_activate_feature(clone->ds_object, f,
+                           origin_head_feature, tx);
+                       clone->ds_feature[f] = origin_head_feature;
                }
        }
 
index b80d3467243f750e91fdc44f1abbc46badcd0c74..97d7befbd0bf1acb0e8696346436ae68631e8ea3 100644 (file)
@@ -20,7 +20,7 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2017 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2018 by Delphix. All rights reserved.
  * Copyright (c) 2013 Steven Hartland. All rights reserved.
  * Copyright (c) 2013 by Joyent, Inc. All rights reserved.
  * Copyright (c) 2016 Actifio, Inc. All rights reserved.
@@ -315,10 +315,8 @@ dsl_destroy_snapshot_sync_impl(dsl_dataset_t *ds, boolean_t defer, dmu_tx_t *tx)
        obj = ds->ds_object;
 
        for (spa_feature_t f = 0; f < SPA_FEATURES; f++) {
-               if (ds->ds_feature_inuse[f]) {
-                       dsl_dataset_deactivate_feature(obj, f, tx);
-                       ds->ds_feature_inuse[f] = B_FALSE;
-               }
+               if (dsl_dataset_feature_is_active(ds, f))
+                       dsl_dataset_deactivate_feature(ds, f, tx);
        }
        if (dsl_dataset_phys(ds)->ds_prev_snap_obj != 0) {
                ASSERT3P(ds->ds_prev, ==, NULL);
@@ -869,10 +867,8 @@ dsl_destroy_head_sync_impl(dsl_dataset_t *ds, dmu_tx_t *tx)
        obj = ds->ds_object;
 
        for (spa_feature_t f = 0; f < SPA_FEATURES; f++) {
-               if (ds->ds_feature_inuse[f]) {
-                       dsl_dataset_deactivate_feature(obj, f, tx);
-                       ds->ds_feature_inuse[f] = B_FALSE;
-               }
+               if (dsl_dataset_feature_is_active(ds, f))
+                       dsl_dataset_deactivate_feature(ds, f, tx);
        }
 
        dsl_scan_ds_destroyed(ds, tx);