]> granicus.if.org Git - zfs/commitdiff
zhack: Add 'feature disable' command
authorBrian Behlendorf <behlendorf1@llnl.gov>
Thu, 1 Oct 2015 23:32:49 +0000 (16:32 -0700)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Tue, 17 May 2016 18:00:21 +0000 (11:00 -0700)
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Issue #3878

cmd/zhack/zhack.c
include/sys/zfeature.h
lib/libzpool/kernel.c
module/zfs/zfeature.c

index eedd17c30710554c885f348bf101bad08f0d041e..10dd8642ef48ea706b0f646c9be3ad3e5bc3fea6 100644 (file)
@@ -58,12 +58,13 @@ libzfs_handle_t *g_zfs;
 static importargs_t g_importargs;
 static char *g_pool;
 static boolean_t g_readonly;
+static boolean_t g_force = B_FALSE;
 
 static void
 usage(void)
 {
        (void) fprintf(stderr,
-           "Usage: %s [-c cachefile] [-d dir] <subcommand> <args> ...\n"
+           "Usage: %s [-c cachefile] [-d dir] [-f] <subcommand> <args> ...\n"
            "where <subcommand> <args> is one of the following:\n"
            "\n", cmdname);
 
@@ -73,6 +74,9 @@ usage(void)
            "    feature enable [-d desc] <pool> <feature>\n"
            "        add a new enabled feature to the pool\n"
            "        -d <desc> sets the feature's description\n"
+           "    feature disable <pool> <feature>\n"
+           "        remove an enabled, but not active, feature\n"
+           "        from the pool.\n"
            "    feature ref [-md] <pool> <feature>\n"
            "        change the refcount on the given feature\n"
            "        -d decrease instead of increase the refcount\n"
@@ -367,6 +371,94 @@ zhack_do_feature_enable(int argc, char **argv)
        free(desc);
 }
 
+static void
+zhack_feature_disable_sync(void *arg, dmu_tx_t *tx)
+{
+       spa_t *spa = dmu_tx_pool(tx)->dp_spa;
+       zfeature_info_t *feature = arg;
+
+       feature_disable_sync(spa, feature, tx);
+
+       spa_history_log_internal(spa, "zhack disable feature", tx,
+           "name=%s can_readonly=%u",
+           feature->fi_guid, feature->fi_can_readonly);
+}
+
+static void
+zhack_do_feature_disable(int argc, char **argv)
+{
+       char c;
+       char *target;
+       uint64_t count;
+       spa_t *spa;
+       objset_t *mos;
+       zfeature_info_t feature;
+       spa_feature_t nodeps[] = { SPA_FEATURE_NONE };
+
+       /*
+        * fi_desc does not matter here because it was written to disk
+        * when the feature was enabled, but we need to properly set the
+        * feature for read or write based on the information we read off
+        * disk later.
+        */
+       feature.fi_uname = "zhack";
+       feature.fi_mos = B_TRUE;
+       feature.fi_desc = NULL;
+       feature.fi_depends = nodeps;
+       feature.fi_feature = SPA_FEATURE_NONE;
+
+       optind = 1;
+       while ((c = getopt(argc, argv, "")) != -1) {
+               switch (c) {
+               default:
+                       usage();
+                       break;
+               }
+       }
+       argc -= optind;
+       argv += optind;
+
+       if (argc < 2) {
+               (void) fprintf(stderr, "error: missing feature or pool name\n");
+               usage();
+       }
+       target = argv[0];
+       feature.fi_guid = argv[1];
+
+       if (!zfeature_is_valid_guid(feature.fi_guid))
+               fatal(NULL, FTAG, "invalid feature guid: %s", feature.fi_guid);
+
+       zhack_spa_open(target, B_FALSE, FTAG, &spa);
+       mos = spa->spa_meta_objset;
+
+       if (zfeature_is_supported(feature.fi_guid) && (g_force == B_FALSE)) {
+               fatal(spa, FTAG,
+                   "'%s' is a real feature, will not disable\n"
+                   "provide the -f option to force override", feature.fi_guid);
+       }
+
+       if (0 == zap_contains(mos, spa->spa_feat_for_read_obj,
+           feature.fi_guid)) {
+               feature.fi_can_readonly = B_FALSE;
+       } else if (0 == zap_contains(mos, spa->spa_feat_for_write_obj,
+           feature.fi_guid)) {
+               feature.fi_can_readonly = B_TRUE;
+       } else {
+               fatal(spa, FTAG, "feature is not enabled: %s", feature.fi_guid);
+       }
+
+       if (feature_get_refcount_from_disk(spa, &feature, &count) == 0 &&
+           count > 0) {
+               fatal(spa, FTAG, "feature '%s' is active, can not disable",
+                   feature.fi_guid);
+       }
+
+       VERIFY0(dsl_sync_task(spa_name(spa), NULL,
+           zhack_feature_disable_sync, &feature, 5, ZFS_SPACE_CHECK_NORMAL));
+
+       spa_close(spa, FTAG);
+}
+
 static void
 feature_incr_sync(void *arg, dmu_tx_t *tx)
 {
@@ -495,6 +587,8 @@ zhack_do_feature(int argc, char **argv)
                zhack_do_feature_stat(argc, argv);
        } else if (strcmp(subcommand, "enable") == 0) {
                zhack_do_feature_enable(argc, argv);
+       } else if (strcmp(subcommand, "disable") == 0) {
+               zhack_do_feature_disable(argc, argv);
        } else if (strcmp(subcommand, "ref") == 0) {
                zhack_do_feature_ref(argc, argv);
        } else {
@@ -523,7 +617,7 @@ main(int argc, char **argv)
        dprintf_setup(&argc, argv);
        zfs_prop_init();
 
-       while ((c = getopt(argc, argv, "c:d:")) != -1) {
+       while ((c = getopt(argc, argv, "c:d:f")) != -1) {
                switch (c) {
                case 'c':
                        g_importargs.cachefile = optarg;
@@ -532,6 +626,9 @@ main(int argc, char **argv)
                        assert(g_importargs.paths < MAX_NUM_PATHS);
                        g_importargs.path[g_importargs.paths++] = optarg;
                        break;
+               case 'f':
+                       g_force = B_TRUE;
+                       break;
                default:
                        usage();
                        break;
index 5abde149a615f0d9a8ba0154f58eb20f82a4eb72..5ea77f847e1024306967708cd3718cb6ecdac053 100644 (file)
@@ -63,6 +63,8 @@ extern int feature_get_refcount_from_disk(spa_t *spa, zfeature_info_t *feature,
     uint64_t *res);
 extern void feature_enable_sync(struct spa *, zfeature_info_t *,
     struct dmu_tx *);
+extern void feature_disable_sync(struct spa *, zfeature_info_t *,
+    struct dmu_tx *);
 extern void feature_sync(struct spa *, zfeature_info_t *, uint64_t,
     struct dmu_tx *);
 
index 89e474c65d4434f57806f70f1cf319e0785b80c2..f14552374b6ca93c657ad9ad96f22d70b56b569d 100644 (file)
@@ -647,8 +647,6 @@ vn_open(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2, int x3)
 #ifdef __linux__
                flags |= O_DIRECT;
 #endif
-               /* We shouldn't be writing to block devices in userspace */
-               VERIFY(!(flags & FWRITE));
        }
 
        if (flags & FCREAT)
index bda9548293d0184bce777749a1ab30a06471dff6..c83b145687d1021fc9f9e30426e0e33d1aeb453e 100644 (file)
@@ -380,6 +380,43 @@ feature_enable_sync(spa_t *spa, zfeature_info_t *feature, dmu_tx_t *tx)
        }
 }
 
+/*
+ * This function is non-static for zhack; it should otherwise not be used
+ * outside this file.
+ */
+void
+feature_disable_sync(spa_t *spa, zfeature_info_t *feature, dmu_tx_t *tx)
+{
+       uint64_t descobj = spa->spa_feat_desc_obj;
+       uint64_t zapobj = feature->fi_can_readonly ?
+           spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj;
+
+       ASSERT(0 != zapobj);
+       ASSERT(zfeature_is_valid_guid(feature->fi_guid));
+       ASSERT3U(spa_version(spa), >=, SPA_VERSION_FEATURES);
+
+       if (zap_contains(spa->spa_meta_objset, descobj, feature->fi_guid) == 0)
+               VERIFY0(zap_remove(spa->spa_meta_objset, descobj,
+                   feature->fi_guid, tx));
+
+       if (zap_contains(spa->spa_meta_objset, zapobj, feature->fi_guid) == 0)
+               VERIFY0(zap_remove(spa->spa_meta_objset, zapobj,
+                   feature->fi_guid, tx));
+
+       spa_deactivate_mos_feature(spa, feature->fi_guid);
+
+       if (spa_feature_is_enabled(spa, SPA_FEATURE_ENABLED_TXG)) {
+               uint64_t txgobj = spa->spa_feat_enabled_txg_obj;
+
+               if (txgobj && (zap_contains(spa->spa_meta_objset,
+                   txgobj, feature->fi_guid) == 0)) {
+                       spa_feature_decr(spa, SPA_FEATURE_ENABLED_TXG, tx);
+                       VERIFY0(zap_remove(spa->spa_meta_objset, txgobj,
+                           feature->fi_guid, tx));
+               }
+       }
+}
+
 static void
 feature_do_action(spa_t *spa, spa_feature_t fid, feature_action_t action,
     dmu_tx_t *tx)