]> git.proxmox.com Git - mirror_zfs.git/commitdiff
Illumos 5959 - clean up per-dataset feature count code
authorMatthew Ahrens <mahrens@delphix.com>
Fri, 24 Jul 2015 16:53:55 +0000 (09:53 -0700)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Fri, 4 Dec 2015 22:20:20 +0000 (14:20 -0800)
5959 clean up per-dataset feature count code
Reviewed by: Toomas Soome <tsoome@me.com>
Reviewed by: George Wilson <george@delphix.com>
Reviewed by: Alex Reece <alex@delphix.com>
Approved by: Richard Lowe <richlowe@richlowe.net>

References:
  https://www.illumos.org/issues/5959
  https://github.com/illumos/illumos-gate/commit/ca0cc39

Porting notes:

illumos code doesn't check for feature_get_refcount() returning
ENOTSUP (which means feature is disabled) in zdb. zfsonlinux added
a check in https://github.com/zfsonlinux/zfs/commit/784652c
due to #3468. The check was reintroduced here.

Ported-by: Witaut Bajaryn <vitaut.bayaryn@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #3965

cmd/zdb/zdb.c
cmd/zhack/zhack.c
cmd/zpool/zpool_main.c
include/sys/dsl_dataset.h
include/zfeature_common.h
module/zfs/dbuf.c
module/zfs/dmu_send.c
module/zfs/dsl_dataset.c
module/zfs/dsl_destroy.c
module/zfs/zfeature.c
module/zfs/zfeature_common.c

index f050f36e21fb3f8ea087cbdcfa46f88be52399dd..6b5ec4201994b6ddd7af0a84b14c0a22e0831738 100644 (file)
@@ -21,7 +21,7 @@
 
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
  * Copyright (c) 2015, Intel Corporation.
  */
 
@@ -2274,7 +2274,7 @@ dump_label(const char *dev)
        (void) close(fd);
 }
 
-static uint64_t num_large_blocks;
+static uint64_t dataset_feature_count[SPA_FEATURES];
 
 /*ARGSUSED*/
 static int
@@ -2282,14 +2282,22 @@ dump_one_dir(const char *dsname, void *arg)
 {
        int error;
        objset_t *os;
+       spa_feature_t f;
 
        error = dmu_objset_own(dsname, DMU_OST_ANY, B_TRUE, FTAG, &os);
        if (error) {
                (void) printf("Could not open %s, error %d\n", dsname, error);
                return (0);
        }
-       if (dmu_objset_ds(os)->ds_large_blocks)
-               num_large_blocks++;
+
+       for (f = 0; f < SPA_FEATURES; f++) {
+               if (!dmu_objset_ds(os)->ds_feature_inuse[f])
+                       continue;
+               ASSERT(spa_feature_table[f].fi_flags &
+                   ZFEATURE_FLAG_PER_DATASET);
+               dataset_feature_count[f]++;
+       }
+
        dump_dir(os);
        dmu_objset_disown(os, FTAG);
        fuid_table_destroy();
@@ -3094,7 +3102,7 @@ dump_zpool(spa_t *spa)
                dump_metaslab_groups(spa);
 
        if (dump_opt['d'] || dump_opt['i']) {
-               uint64_t refcount;
+               spa_feature_t f;
 
                dump_dir(dp->dp_meta_objset);
                if (dump_opt['d'] >= 3) {
@@ -3117,18 +3125,28 @@ dump_zpool(spa_t *spa)
                (void) dmu_objset_find(spa_name(spa), dump_one_dir,
                    NULL, DS_FIND_SNAPSHOTS | DS_FIND_CHILDREN);
 
-               if (feature_get_refcount(spa,
-                   &spa_feature_table[SPA_FEATURE_LARGE_BLOCKS],
-                   &refcount) != ENOTSUP) {
-                       if (num_large_blocks != refcount) {
-                               (void) printf("large_blocks feature refcount "
-                                   "mismatch: expected %lld != actual %lld\n",
-                                   (longlong_t)num_large_blocks,
+               for (f = 0; f < SPA_FEATURES; f++) {
+                       uint64_t refcount;
+
+                       if (!(spa_feature_table[f].fi_flags &
+                           ZFEATURE_FLAG_PER_DATASET)) {
+                               ASSERT0(dataset_feature_count[f]);
+                               continue;
+                       }
+                       if (feature_get_refcount(spa, &spa_feature_table[f],
+                           &refcount) == ENOTSUP)
+                               continue;
+                       if (dataset_feature_count[f] != refcount) {
+                               (void) printf("%s feature refcount mismatch: "
+                                   "%lld datasets != %lld refcount\n",
+                                   spa_feature_table[f].fi_uname,
+                                   (longlong_t)dataset_feature_count[f],
                                    (longlong_t)refcount);
                                rc = 2;
                        } else {
-                               (void) printf("Verified large_blocks feature "
-                                   "refcount is correct (%llu)\n",
+                               (void) printf("Verified %s feature refcount "
+                                   "of %llu is correct\n",
+                                   spa_feature_table[f].fi_uname,
                                    (longlong_t)refcount);
                        }
                }
index 3f86714fe31da34b523bd33bd28b5ae5addb352c..a7da371c8a846f2c95f20bc99eb571f200d8c84d 100644 (file)
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright (c) 2011, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
  * Copyright (c) 2013 Steven Hartland. All rights reserved.
  */
 
@@ -294,8 +294,8 @@ zhack_feature_enable_sync(void *arg, dmu_tx_t *tx)
        feature_enable_sync(spa, feature, tx);
 
        spa_history_log_internal(spa, "zhack enable feature", tx,
-           "name=%s can_readonly=%u",
-           feature->fi_guid, feature->fi_can_readonly);
+           "name=%s flags=%u",
+           feature->fi_guid, feature->fi_flags);
 }
 
 static void
@@ -314,9 +314,7 @@ zhack_do_feature_enable(int argc, char **argv)
         */
        desc = NULL;
        feature.fi_uname = "zhack";
-       feature.fi_mos = B_FALSE;
-       feature.fi_can_readonly = B_FALSE;
-       feature.fi_activate_on_enable = B_FALSE;
+       feature.fi_flags = 0;
        feature.fi_depends = nodeps;
        feature.fi_feature = SPA_FEATURE_NONE;
 
@@ -324,7 +322,7 @@ zhack_do_feature_enable(int argc, char **argv)
        while ((c = getopt(argc, argv, "rmd:")) != -1) {
                switch (c) {
                case 'r':
-                       feature.fi_can_readonly = B_TRUE;
+                       feature.fi_flags |= ZFEATURE_FLAG_READONLY_COMPAT;
                        break;
                case 'd':
                        desc = strdup(optarg);
@@ -413,7 +411,7 @@ zhack_do_feature_ref(int argc, char **argv)
         * disk later.
         */
        feature.fi_uname = "zhack";
-       feature.fi_mos = B_FALSE;
+       feature.fi_flags = 0;
        feature.fi_desc = NULL;
        feature.fi_depends = nodeps;
        feature.fi_feature = SPA_FEATURE_NONE;
@@ -422,7 +420,7 @@ zhack_do_feature_ref(int argc, char **argv)
        while ((c = getopt(argc, argv, "md")) != -1) {
                switch (c) {
                case 'm':
-                       feature.fi_mos = B_TRUE;
+                       feature.fi_flags |= ZFEATURE_FLAG_MOS;
                        break;
                case 'd':
                        decr = B_TRUE;
@@ -455,10 +453,10 @@ zhack_do_feature_ref(int argc, char **argv)
 
        if (0 == zap_contains(mos, spa->spa_feat_for_read_obj,
            feature.fi_guid)) {
-               feature.fi_can_readonly = B_FALSE;
+               feature.fi_flags &= ~ZFEATURE_FLAG_READONLY_COMPAT;
        } else if (0 == zap_contains(mos, spa->spa_feat_for_write_obj,
            feature.fi_guid)) {
-               feature.fi_can_readonly = B_TRUE;
+               feature.fi_flags |= ZFEATURE_FLAG_READONLY_COMPAT;
        } else {
                fatal(spa, FTAG, "feature is not enabled: %s", feature.fi_guid);
        }
index f32efcef27d7723490017e401ddfffee8186ac33..8cb9c861cb3678bcf531f934ad5f4546a7f630b9 100644 (file)
@@ -22,7 +22,7 @@
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
- * Copyright (c) 2011, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
  * Copyright (c) 2012 by Frederik Wessels. All rights reserved.
  * Copyright (c) 2012 by Cyril Plisko. All rights reserved.
  * Copyright (c) 2013 by Prasad Joshi (sTec). All rights reserved.
@@ -5105,7 +5105,8 @@ zpool_do_upgrade(int argc, char **argv)
                    "---------------\n");
                for (i = 0; i < SPA_FEATURES; i++) {
                        zfeature_info_t *fi = &spa_feature_table[i];
-                       const char *ro = fi->fi_can_readonly ?
+                       const char *ro =
+                           (fi->fi_flags & ZFEATURE_FLAG_READONLY_COMPAT) ?
                            " (read-only compatible)" : "";
 
                        (void) printf("%-37s%s\n", fi->fi_uname, ro);
index d6da5dcfdb9f8472ae3eff9f6d3bb09c7dce5688..25622263e6319dbd40af0cf1c25798d967b168a9 100644 (file)
@@ -20,7 +20,7 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
  * Copyright (c) 2013, Joyent, Inc. All rights reserved.
  * Copyright (c) 2013 Steven Hartland. All rights reserved.
  * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
@@ -38,6 +38,7 @@
 #include <sys/zfs_context.h>
 #include <sys/dsl_deadlist.h>
 #include <sys/refcount.h>
+#include <zfeature_common.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -145,8 +146,6 @@ typedef struct dsl_dataset {
        /* only used in syncing context, only valid for non-snapshots: */
        struct dsl_dataset *ds_prev;
        uint64_t ds_bookmarks;  /* DMU_OTN_ZAP_METADATA */
-       boolean_t ds_large_blocks;
-       boolean_t ds_need_large_blocks;
 
        /* has internal locking: */
        dsl_deadlist_t ds_deadlist;
@@ -185,6 +184,18 @@ typedef struct dsl_dataset {
        kmutex_t ds_sendstream_lock;
        list_t ds_sendstreams;
 
+       /*
+        * For ZFEATURE_FLAG_PER_DATASET features, set if this dataset
+        * uses this feature.
+        */
+       uint8_t ds_feature_inuse[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];
+
        /* Protected by ds_lock; keep at end of struct for better locality */
        char ds_snapname[MAXNAMELEN];
 } dsl_dataset_t;
@@ -264,8 +275,6 @@ int dsl_dataset_space_written(dsl_dataset_t *oldsnap, dsl_dataset_t *new,
 int dsl_dataset_space_wouldfree(dsl_dataset_t *firstsnap, dsl_dataset_t *last,
     uint64_t *usedp, uint64_t *compp, uint64_t *uncompp);
 boolean_t dsl_dataset_is_dirty(dsl_dataset_t *ds);
-int dsl_dataset_activate_large_blocks(const char *dsname);
-void dsl_dataset_activate_large_blocks_sync_impl(uint64_t dsobj, dmu_tx_t *tx);
 
 int dsl_dsobj_to_dsname(char *pname, uint64_t obj, char *buf);
 
@@ -305,6 +314,9 @@ void dsl_dataset_set_refreservation_sync_impl(dsl_dataset_t *ds,
 void dsl_dataset_zapify(dsl_dataset_t *ds, dmu_tx_t *tx);
 int dsl_dataset_rollback(const char *fsname, void *owner, nvlist_t *result);
 
+void dsl_dataset_deactivate_feature(uint64_t dsobj,
+    spa_feature_t f, dmu_tx_t *tx);
+
 #ifdef ZFS_DEBUG
 #define        dprintf_ds(ds, fmt, ...) do { \
        if (zfs_flags & ZFS_DEBUG_DPRINTF) { \
index e383c4ff7887a7bb6b0d585e3fe47174d4379882..d481a28a8ffe1b8a90c89e1696ea8aa54e75fc0d 100644 (file)
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
  * Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
  */
 
@@ -55,15 +55,23 @@ typedef enum spa_feature {
 
 #define        SPA_FEATURE_DISABLED    (-1ULL)
 
+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? */
+       ZFEATURE_FLAG_MOS =                     (1 << 1),
+       /* Activate this feature at the same time it is enabled. */
+       ZFEATURE_FLAG_ACTIVATE_ON_ENABLE =      (1 << 2),
+       /* Each dataset has a field set if it has ever used this feature. */
+       ZFEATURE_FLAG_PER_DATASET =             (1 << 3)
+} zfeature_flags_t;
+
 typedef struct zfeature_info {
        spa_feature_t fi_feature;
        const char *fi_uname;   /* User-facing feature name */
        const char *fi_guid;    /* On-disk feature identifier */
        const char *fi_desc;    /* Feature description */
-       boolean_t fi_can_readonly; /* Can open pool readonly w/o support? */
-       boolean_t fi_mos;       /* Is the feature necessary to read the MOS? */
-       /* Activate this feature at the same time it is enabled */
-       boolean_t fi_activate_on_enable;
+       zfeature_flags_t fi_flags;
        /* array of dependencies, terminated by SPA_FEATURE_NONE */
        const spa_feature_t *fi_depends;
 } zfeature_info_t;
index d340da821fc50f0e65bf34acea66383b0be42804..31242d60154e77872db0217b0a8c3339ce8e1e65 100644 (file)
@@ -1615,6 +1615,11 @@ dmu_buf_write_embedded(dmu_buf_t *dbuf, void *data,
        struct dirty_leaf *dl;
        dmu_object_type_t type;
 
+       if (etype == BP_EMBEDDED_TYPE_DATA) {
+               ASSERT(spa_feature_is_active(dmu_objset_spa(db->db_objset),
+                   SPA_FEATURE_EMBEDDED_DATA));
+       }
+
        DB_DNODE_ENTER(db);
        type = DB_DNODE(db)->dn_type;
        DB_DNODE_EXIT(db);
index b2d844eb42561523037f47451ff2a4a50db20c38..8e79dc70db50d538ea33fdf8fa80e5a213d2c5d8 100644 (file)
@@ -20,7 +20,7 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
  * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
  * Copyright (c) 2014, Joyent, Inc. All rights reserved.
  * Copyright (c) 2011, 2014 by Delphix. All rights reserved.
@@ -611,7 +611,7 @@ dmu_send_impl(void *tag, dsl_pool_t *dp, dsl_dataset_t *ds,
        }
 #endif
 
-       if (large_block_ok && ds->ds_large_blocks)
+       if (large_block_ok && ds->ds_feature_inuse[SPA_FEATURE_LARGE_BLOCKS])
                featureflags |= DMU_BACKUP_FEATURE_LARGE_BLOCKS;
        if (embedok &&
            spa_feature_is_active(dp->dp_spa, SPA_FEATURE_EMBEDDED_DATA)) {
@@ -1226,13 +1226,6 @@ dmu_recv_begin_sync(void *arg, dmu_tx_t *tx)
        }
        VERIFY0(dsl_dataset_own_obj(dp, dsobj, dmu_recv_tag, &newds));
 
-       if ((DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo) &
-           DMU_BACKUP_FEATURE_LARGE_BLOCKS) &&
-           !newds->ds_large_blocks) {
-               dsl_dataset_activate_large_blocks_sync_impl(dsobj, tx);
-               newds->ds_large_blocks = B_TRUE;
-       }
-
        dmu_buf_will_dirty(newds->ds_dbuf, tx);
        dsl_dataset_phys(newds)->ds_flags |= DS_FLAG_INCONSISTENT;
 
index 2168f28941ed826bb10ce29eadac63b3d6d5578c..829452b1d22a185a730f25386e8691c29c3533fa 100644 (file)
@@ -20,7 +20,7 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2015 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.
@@ -126,8 +126,10 @@ dsl_dataset_block_born(dsl_dataset_t *ds, const blkptr_t *bp, dmu_tx_t *tx)
        dsl_dataset_phys(ds)->ds_compressed_bytes += compressed;
        dsl_dataset_phys(ds)->ds_uncompressed_bytes += uncompressed;
        dsl_dataset_phys(ds)->ds_unique_bytes += used;
-       if (BP_GET_LSIZE(bp) > SPA_OLD_MAXBLOCKSIZE)
-               ds->ds_need_large_blocks = B_TRUE;
+       if (BP_GET_LSIZE(bp) > SPA_OLD_MAXBLOCKSIZE) {
+               ds->ds_feature_activation_needed[SPA_FEATURE_LARGE_BLOCKS] =
+                   B_TRUE;
+       }
        mutex_exit(&ds->ds_lock);
        dsl_dir_diduse_space(ds->ds_dir, DD_USED_HEAD, delta,
            compressed, uncompressed, tx);
@@ -432,19 +434,25 @@ dsl_dataset_hold_obj(dsl_pool_t *dp, uint64_t dsobj, void *tag,
                    offsetof(dmu_sendarg_t, dsa_link));
 
                if (doi.doi_type == DMU_OTN_ZAP_METADATA) {
-                       int zaperr = zap_contains(mos, dsobj,
-                           DS_FIELD_LARGE_BLOCKS);
-                       if (zaperr != ENOENT) {
-                               VERIFY0(zaperr);
-                               ds->ds_large_blocks = B_TRUE;
+                       spa_feature_t f;
+
+                       for (f = 0; f < SPA_FEATURES; f++) {
+                               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;
+                               }
                        }
                }
 
-               if (err == 0) {
-                       err = dsl_dir_hold_obj(dp,
-                           dsl_dataset_phys(ds)->ds_dir_obj, NULL, ds,
-                           &ds->ds_dir);
-               }
+               err = dsl_dir_hold_obj(dp,
+                   dsl_dataset_phys(ds)->ds_dir_obj, NULL, ds, &ds->ds_dir);
                if (err != 0) {
                        mutex_destroy(&ds->ds_lock);
                        mutex_destroy(&ds->ds_opening_lock);
@@ -698,6 +706,34 @@ dsl_dataset_tryown(dsl_dataset_t *ds, void *tag)
        return (gotit);
 }
 
+static void
+dsl_dataset_activate_feature(uint64_t dsobj, 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 zero = 0;
+
+       VERIFY(spa_feature_table[f].fi_flags & ZFEATURE_FLAG_PER_DATASET);
+
+       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));
+}
+
+void
+dsl_dataset_deactivate_feature(uint64_t dsobj, 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;
+
+       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);
+}
+
 uint64_t
 dsl_dataset_create_sync_dd(dsl_dir_t *dd, dsl_dataset_t *origin,
     uint64_t flags, dmu_tx_t *tx)
@@ -736,6 +772,7 @@ dsl_dataset_create_sync_dd(dsl_dir_t *dd, dsl_dataset_t *origin,
        if (origin == NULL) {
                dsphys->ds_deadlist_obj = dsl_deadlist_alloc(mos, tx);
        } else {
+               spa_feature_t f;
                dsl_dataset_t *ohds; /* head of the origin snapshot */
 
                dsphys->ds_prev_snap_obj = origin->ds_object;
@@ -756,8 +793,10 @@ dsl_dataset_create_sync_dd(dsl_dir_t *dd, dsl_dataset_t *origin,
                dsphys->ds_flags |= dsl_dataset_phys(origin)->ds_flags &
                    (DS_FLAG_INCONSISTENT | DS_FLAG_CI_DATASET);
 
-               if (origin->ds_large_blocks)
-                       dsl_dataset_activate_large_blocks_sync_impl(dsobj, tx);
+               for (f = 0; f < SPA_FEATURES; f++) {
+                       if (origin->ds_feature_inuse[f])
+                               dsl_dataset_activate_feature(dsobj, f, tx);
+               }
 
                dmu_buf_will_dirty(origin->ds_dbuf, tx);
                dsl_dataset_phys(origin)->ds_num_children++;
@@ -1233,6 +1272,7 @@ dsl_dataset_snapshot_sync_impl(dsl_dataset_t *ds, const char *snapname,
        dsl_dataset_phys_t *dsphys;
        uint64_t dsobj, crtxg;
        objset_t *mos = dp->dp_meta_objset;
+       spa_feature_t f;
        ASSERTV(static zil_header_t zero_zil);
        ASSERTV(objset_t *os);
 
@@ -1282,8 +1322,10 @@ dsl_dataset_snapshot_sync_impl(dsl_dataset_t *ds, const char *snapname,
        dsphys->ds_bp = dsl_dataset_phys(ds)->ds_bp;
        dmu_buf_rele(dbuf, FTAG);
 
-       if (ds->ds_large_blocks)
-               dsl_dataset_activate_large_blocks_sync_impl(dsobj, tx);
+       for (f = 0; f < SPA_FEATURES; f++) {
+               if (ds->ds_feature_inuse[f])
+                       dsl_dataset_activate_feature(dsobj, f, tx);
+       }
 
        ASSERT3U(ds->ds_prev != 0, ==,
            dsl_dataset_phys(ds)->ds_prev_snap_obj != 0);
@@ -1561,6 +1603,8 @@ dsl_dataset_snapshot_tmp(const char *fsname, const char *snapname,
 void
 dsl_dataset_sync(dsl_dataset_t *ds, zio_t *zio, dmu_tx_t *tx)
 {
+       spa_feature_t f;
+
        ASSERT(dmu_tx_is_syncing(tx));
        ASSERT(ds->ds_objset != NULL);
        ASSERT(dsl_dataset_phys(ds)->ds_next_snap_obj == 0);
@@ -1574,9 +1618,13 @@ dsl_dataset_sync(dsl_dataset_t *ds, zio_t *zio, dmu_tx_t *tx)
 
        dmu_objset_sync(ds->ds_objset, zio, tx);
 
-       if (ds->ds_need_large_blocks && !ds->ds_large_blocks) {
-               dsl_dataset_activate_large_blocks_sync_impl(ds->ds_object, tx);
-               ds->ds_large_blocks = B_TRUE;
+       for (f = 0; f < SPA_FEATURES; f++) {
+               if (ds->ds_feature_activation_needed[f]) {
+                       if (ds->ds_feature_inuse[f])
+                               continue;
+                       dsl_dataset_activate_feature(ds->ds_object, f, tx);
+                       ds->ds_feature_inuse[f] = B_TRUE;
+               }
        }
 }
 
@@ -2703,6 +2751,7 @@ void
 dsl_dataset_clone_swap_sync_impl(dsl_dataset_t *clone,
     dsl_dataset_t *origin_head, dmu_tx_t *tx)
 {
+       spa_feature_t f;
        dsl_pool_t *dp = dmu_tx_pool(tx);
        int64_t unused_refres_delta;
 
@@ -2711,6 +2760,43 @@ dsl_dataset_clone_swap_sync_impl(dsl_dataset_t *clone,
            dsl_dataset_phys(clone)->ds_unique_bytes <= origin_head->ds_quota);
        ASSERT3P(clone->ds_prev, ==, origin_head->ds_prev);
 
+       /*
+        * Swap per-dataset feature flags.
+        */
+       for (f = 0; f < SPA_FEATURES; f++) {
+               boolean_t clone_inuse;
+               boolean_t origin_head_inuse;
+
+               if (!(spa_feature_table[f].fi_flags &
+                   ZFEATURE_FLAG_PER_DATASET)) {
+                       ASSERT(!clone->ds_feature_inuse[f]);
+                       ASSERT(!origin_head->ds_feature_inuse[f]);
+                       continue;
+               }
+
+               clone_inuse = clone->ds_feature_inuse[f];
+               origin_head_inuse = origin_head->ds_feature_inuse[f];
+
+               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;
+               }
+               if (origin_head_inuse) {
+                       dsl_dataset_activate_feature(clone->ds_object, f, tx);
+                       clone->ds_feature_inuse[f] = B_TRUE;
+               }
+       }
+
        dmu_buf_will_dirty(clone->ds_dbuf, tx);
        dmu_buf_will_dirty(origin_head->ds_dbuf, tx);
 
@@ -3265,77 +3351,6 @@ dsl_dataset_space_wouldfree(dsl_dataset_t *firstsnap,
        return (err);
 }
 
-static int
-dsl_dataset_activate_large_blocks_check(void *arg, dmu_tx_t *tx)
-{
-       const char *dsname = arg;
-       dsl_dataset_t *ds;
-       dsl_pool_t *dp = dmu_tx_pool(tx);
-       int error = 0;
-
-       if (!spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LARGE_BLOCKS))
-               return (SET_ERROR(ENOTSUP));
-
-       ASSERT(spa_feature_is_enabled(dp->dp_spa,
-           SPA_FEATURE_EXTENSIBLE_DATASET));
-
-       error = dsl_dataset_hold(dp, dsname, FTAG, &ds);
-       if (error != 0)
-               return (error);
-
-       if (ds->ds_large_blocks)
-               error = EALREADY;
-       dsl_dataset_rele(ds, FTAG);
-
-       return (error);
-}
-
-void
-dsl_dataset_activate_large_blocks_sync_impl(uint64_t dsobj, 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 zero = 0;
-
-       spa_feature_incr(spa, SPA_FEATURE_LARGE_BLOCKS, tx);
-       dmu_object_zapify(mos, dsobj, DMU_OT_DSL_DATASET, tx);
-
-       VERIFY0(zap_add(mos, dsobj, DS_FIELD_LARGE_BLOCKS,
-           sizeof (zero), 1, &zero, tx));
-}
-
-static void
-dsl_dataset_activate_large_blocks_sync(void *arg, dmu_tx_t *tx)
-{
-       const char *dsname = arg;
-       dsl_dataset_t *ds;
-
-       VERIFY0(dsl_dataset_hold(dmu_tx_pool(tx), dsname, FTAG, &ds));
-
-       dsl_dataset_activate_large_blocks_sync_impl(ds->ds_object, tx);
-       ASSERT(!ds->ds_large_blocks);
-       ds->ds_large_blocks = B_TRUE;
-       dsl_dataset_rele(ds, FTAG);
-}
-
-int
-dsl_dataset_activate_large_blocks(const char *dsname)
-{
-       int error;
-
-       error = dsl_sync_task(dsname,
-           dsl_dataset_activate_large_blocks_check,
-           dsl_dataset_activate_large_blocks_sync, (void *)dsname,
-           1, ZFS_SPACE_CHECK_RESERVED);
-
-       /*
-        * EALREADY indicates that this dataset already supports large blocks.
-        */
-       if (error == EALREADY)
-               error = 0;
-       return (error);
-}
-
 /*
  * Return TRUE if 'earlier' is an earlier snapshot in 'later's timeline.
  * For example, they could both be snapshots of the same filesystem, and
@@ -3380,7 +3395,6 @@ dsl_dataset_is_before(dsl_dataset_t *later, dsl_dataset_t *earlier,
        return (ret);
 }
 
-
 void
 dsl_dataset_zapify(dsl_dataset_t *ds, dmu_tx_t *tx)
 {
index 0e2238f99e5176862b74e0b5ff5347f7c0cd7c06..e45f46d8da426fb9f0f7b4e6a80b384cc45ffc88 100644 (file)
@@ -20,7 +20,7 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
  * Copyright (c) 2013 Steven Hartland. All rights reserved.
  * Copyright (c) 2013 by Joyent, Inc. All rights reserved.
  */
@@ -246,6 +246,7 @@ dsl_destroy_snapshot_sync_impl(dsl_dataset_t *ds, boolean_t defer, dmu_tx_t *tx)
 #ifdef ZFS_DEBUG
        int err;
 #endif
+       spa_feature_t f;
        int after_branch_point = FALSE;
        dsl_pool_t *dp = ds->ds_dir->dd_pool;
        objset_t *mos = dp->dp_meta_objset;
@@ -277,9 +278,11 @@ dsl_destroy_snapshot_sync_impl(dsl_dataset_t *ds, boolean_t defer, dmu_tx_t *tx)
 
        obj = ds->ds_object;
 
-       if (ds->ds_large_blocks) {
-               ASSERT0(zap_contains(mos, obj, DS_FIELD_LARGE_BLOCKS));
-               spa_feature_decr(dp->dp_spa, SPA_FEATURE_LARGE_BLOCKS, tx);
+       for (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_phys(ds)->ds_prev_snap_obj != 0) {
                ASSERT3P(ds->ds_prev, ==, NULL);
@@ -715,6 +718,7 @@ void
 dsl_destroy_head_sync_impl(dsl_dataset_t *ds, dmu_tx_t *tx)
 {
        dsl_pool_t *dp = dmu_tx_pool(tx);
+       spa_feature_t f;
        objset_t *mos = dp->dp_meta_objset;
        uint64_t obj, ddobj, prevobj = 0;
        boolean_t rmorigin;
@@ -742,12 +746,16 @@ dsl_destroy_head_sync_impl(dsl_dataset_t *ds, dmu_tx_t *tx)
                ASSERT0(ds->ds_reserved);
        }
 
-       if (ds->ds_large_blocks)
-               spa_feature_decr(dp->dp_spa, SPA_FEATURE_LARGE_BLOCKS, tx);
+       obj = ds->ds_object;
 
-       dsl_scan_ds_destroyed(ds, tx);
+       for (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;
+               }
+       }
 
-       obj = ds->ds_object;
+       dsl_scan_ds_destroyed(ds, tx);
 
        if (dsl_dataset_phys(ds)->ds_prev_snap_obj != 0) {
                /* This is a clone */
index 352376f22b9ed8a097efd37bb52d67a86ddb9b0c..bda9548293d0184bce777749a1ab30a06471dff6 100644 (file)
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
  */
 
 #include <sys/zfs_context.h>
@@ -253,7 +253,7 @@ feature_get_refcount_from_disk(spa_t *spa, zfeature_info_t *feature,
 {
        int err;
        uint64_t refcount;
-       uint64_t zapobj = feature->fi_can_readonly ?
+       uint64_t zapobj = (feature->fi_flags & ZFEATURE_FLAG_READONLY_COMPAT) ?
            spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj;
 
        /*
@@ -306,7 +306,7 @@ feature_sync(spa_t *spa, zfeature_info_t *feature, uint64_t refcount,
        uint64_t zapobj;
 
        ASSERT(VALID_FEATURE_OR_NONE(feature->fi_feature));
-       zapobj = feature->fi_can_readonly ?
+       zapobj = (feature->fi_flags & ZFEATURE_FLAG_READONLY_COMPAT) ?
            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));
@@ -327,7 +327,7 @@ feature_sync(spa_t *spa, zfeature_info_t *feature, uint64_t refcount,
 
        if (refcount == 0)
                spa_deactivate_mos_feature(spa, feature->fi_guid);
-       else if (feature->fi_mos)
+       else if (feature->fi_flags & ZFEATURE_FLAG_MOS)
                spa_activate_mos_feature(spa, feature->fi_guid, tx);
 }
 
@@ -338,8 +338,9 @@ 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 ?
+       uint64_t initial_refcount =
+           (feature->fi_flags & ZFEATURE_FLAG_ACTIVATE_ON_ENABLE) ? 1 : 0;
+       uint64_t zapobj = (feature->fi_flags & ZFEATURE_FLAG_READONLY_COMPAT) ?
            spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj;
        int i;
 
@@ -385,7 +386,8 @@ feature_do_action(spa_t *spa, spa_feature_t fid, feature_action_t action,
 {
        uint64_t refcount = 0;
        zfeature_info_t *feature = &spa_feature_table[fid];
-       ASSERTV(uint64_t zapobj = feature->fi_can_readonly ?
+       ASSERTV(uint64_t zapobj =
+           (feature->fi_flags & ZFEATURE_FLAG_READONLY_COMPAT) ?
            spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj);
 
        ASSERT(VALID_FEATURE_FID(fid));
index 609a72ab301a220e55aef68f53285b1dde433e0e..f57e5489cae9dc0bc10c18a8a020f51f866b016d 100644 (file)
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
  * Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
  * Copyright (c) 2014, Nexenta Systems, Inc. All rights reserved.
  */
@@ -135,15 +135,15 @@ zfeature_depends_on(spa_feature_t fid, spa_feature_t check) {
 
 static void
 zfeature_register(spa_feature_t fid, const char *guid, const char *name,
-    const char *desc, boolean_t readonly, boolean_t mos,
-    boolean_t activate_on_enable, const spa_feature_t *deps)
+    const char *desc, zfeature_flags_t flags, const spa_feature_t *deps)
 {
        zfeature_info_t *feature = &spa_feature_table[fid];
        static spa_feature_t nodeps[] = { SPA_FEATURE_NONE };
 
        ASSERT(name != NULL);
        ASSERT(desc != NULL);
-       ASSERT(!readonly || !mos);
+       ASSERT((flags & ZFEATURE_FLAG_READONLY_COMPAT) == 0 ||
+           (flags & ZFEATURE_FLAG_MOS) == 0);
        ASSERT3U(fid, <, SPA_FEATURES);
        ASSERT(zfeature_is_valid_guid(guid));
 
@@ -154,9 +154,7 @@ zfeature_register(spa_feature_t fid, const char *guid, const char *name,
        feature->fi_guid = guid;
        feature->fi_uname = name;
        feature->fi_desc = desc;
-       feature->fi_can_readonly = readonly;
-       feature->fi_mos = mos;
-       feature->fi_activate_on_enable = activate_on_enable;
+       feature->fi_flags = flags;
        feature->fi_depends = deps;
 }
 
@@ -165,28 +163,28 @@ zpool_feature_init(void)
 {
        zfeature_register(SPA_FEATURE_ASYNC_DESTROY,
            "com.delphix:async_destroy", "async_destroy",
-           "Destroy filesystems asynchronously.", B_TRUE, B_FALSE,
-           B_FALSE, NULL);
+           "Destroy filesystems asynchronously.",
+           ZFEATURE_FLAG_READONLY_COMPAT, NULL);
 
        zfeature_register(SPA_FEATURE_EMPTY_BPOBJ,
            "com.delphix:empty_bpobj", "empty_bpobj",
-           "Snapshots use less space.", B_TRUE, B_FALSE,
-           B_FALSE, NULL);
+           "Snapshots use less space.",
+           ZFEATURE_FLAG_READONLY_COMPAT, NULL);
 
        zfeature_register(SPA_FEATURE_LZ4_COMPRESS,
            "org.illumos:lz4_compress", "lz4_compress",
-           "LZ4 compression algorithm support.", B_FALSE, B_FALSE,
-           B_TRUE, NULL);
+           "LZ4 compression algorithm support.",
+           ZFEATURE_FLAG_ACTIVATE_ON_ENABLE, NULL);
 
        zfeature_register(SPA_FEATURE_SPACEMAP_HISTOGRAM,
            "com.delphix:spacemap_histogram", "spacemap_histogram",
-           "Spacemaps maintain space histograms.", B_TRUE, B_FALSE,
-           B_FALSE, NULL);
+           "Spacemaps maintain space histograms.",
+           ZFEATURE_FLAG_READONLY_COMPAT, NULL);
 
        zfeature_register(SPA_FEATURE_ENABLED_TXG,
            "com.delphix:enabled_txg", "enabled_txg",
-           "Record txg at which a feature is enabled", B_TRUE, B_FALSE,
-           B_FALSE, NULL);
+           "Record txg at which a feature is enabled",
+           ZFEATURE_FLAG_READONLY_COMPAT, NULL);
 
        {
        static const spa_feature_t hole_birth_deps[] = {
@@ -196,13 +194,14 @@ zpool_feature_init(void)
        zfeature_register(SPA_FEATURE_HOLE_BIRTH,
            "com.delphix:hole_birth", "hole_birth",
            "Retain hole birth txg for more precise zfs send",
-           B_FALSE, B_TRUE, B_TRUE, hole_birth_deps);
+           ZFEATURE_FLAG_MOS | ZFEATURE_FLAG_ACTIVATE_ON_ENABLE,
+           hole_birth_deps);
        }
 
        zfeature_register(SPA_FEATURE_EXTENSIBLE_DATASET,
            "com.delphix:extensible_dataset", "extensible_dataset",
            "Enhanced dataset functionality, used by other features.",
-           B_FALSE, B_FALSE, B_FALSE, NULL);
+           0, NULL);
 
        {
        static const spa_feature_t bookmarks_deps[] = {
@@ -213,7 +212,7 @@ zpool_feature_init(void)
        zfeature_register(SPA_FEATURE_BOOKMARKS,
            "com.delphix:bookmarks", "bookmarks",
            "\"zfs bookmark\" command",
-           B_TRUE, B_FALSE, B_FALSE, bookmarks_deps);
+           ZFEATURE_FLAG_READONLY_COMPAT, bookmarks_deps);
        }
 
        {
@@ -223,14 +222,15 @@ zpool_feature_init(void)
        };
        zfeature_register(SPA_FEATURE_FS_SS_LIMIT,
            "com.joyent:filesystem_limits", "filesystem_limits",
-           "Filesystem and snapshot limits.", B_TRUE, B_FALSE, B_FALSE,
-           filesystem_limits_deps);
+           "Filesystem and snapshot limits.",
+           ZFEATURE_FLAG_READONLY_COMPAT, filesystem_limits_deps);
        }
 
        zfeature_register(SPA_FEATURE_EMBEDDED_DATA,
            "com.delphix:embedded_data", "embedded_data",
            "Blocks which compress very well use even less space.",
-           B_FALSE, B_TRUE, B_TRUE, NULL);
+           ZFEATURE_FLAG_MOS | ZFEATURE_FLAG_ACTIVATE_ON_ENABLE,
+           NULL);
 
        {
        static const spa_feature_t large_blocks_deps[] = {
@@ -239,7 +239,7 @@ zpool_feature_init(void)
        };
        zfeature_register(SPA_FEATURE_LARGE_BLOCKS,
            "org.open-zfs:large_blocks", "large_blocks",
-           "Support for blocks larger than 128KB.", B_FALSE, B_FALSE, B_FALSE,
-           large_blocks_deps);
+           "Support for blocks larger than 128KB.",
+           ZFEATURE_FLAG_PER_DATASET, large_blocks_deps);
        }
 }