]> git.proxmox.com Git - mirror_zfs-debian.git/blobdiff - cmd/zhack/zhack.c
New upstream version 0.7.6
[mirror_zfs-debian.git] / cmd / zhack / zhack.c
index 64ab8edbbc02a8bacdacc27598543dcfcfcd01c1..e15af8f4ea02eb207c5f3cd89b9bbd79d1f39c44 100644 (file)
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
  * Copyright (c) 2013 Steven Hartland. All rights reserved.
  */
 
@@ -48,7 +48,6 @@
 #include <sys/zio_compress.h>
 #include <sys/zfeature.h>
 #include <sys/dmu_tx.h>
-#undef ZFS_MAXNAMELEN
 #include <libzfs.h>
 
 extern boolean_t zfeature_checks_disable;
@@ -70,9 +69,10 @@ usage(void)
        (void) fprintf(stderr,
            "    feature stat <pool>\n"
            "        print information about enabled features\n"
-           "    feature enable [-d desc] <pool> <feature>\n"
+           "    feature enable [-r] [-d desc] <pool> <feature>\n"
            "        add a new enabled feature to the pool\n"
            "        -d <desc> sets the feature's description\n"
+           "        -r set read-only compatible flag for feature\n"
            "    feature ref [-md] <pool> <feature>\n"
            "        change the refcount on the given feature\n"
            "        -d decrease instead of increase the refcount\n"
@@ -84,10 +84,15 @@ usage(void)
 
 
 static void
-fatal(const char *fmt, ...)
+fatal(spa_t *spa, void *tag, const char *fmt, ...)
 {
        va_list ap;
 
+       if (spa != NULL) {
+               spa_close(spa, tag);
+               (void) spa_export(g_pool, NULL, B_TRUE, B_FALSE);
+       }
+
        va_start(ap, fmt);
        (void) fprintf(stderr, "%s: ", cmdname);
        (void) vfprintf(stderr, fmt, ap);
@@ -116,16 +121,11 @@ space_delta_cb(dmu_object_type_t bonustype, void *data,
  * Target is the dataset whose pool we want to open.
  */
 static void
-import_pool(const char *target, boolean_t readonly)
+zhack_import(char *target, boolean_t readonly)
 {
        nvlist_t *config;
-       nvlist_t *pools;
-       int error;
-       char *sepp;
-       spa_t *spa;
-       nvpair_t *elem;
        nvlist_t *props;
-       char *name;
+       int error;
 
        kernel_init(readonly ? FREAD : (FREAD | FWRITE));
        g_zfs = libzfs_init();
@@ -134,42 +134,14 @@ import_pool(const char *target, boolean_t readonly)
        dmu_objset_register_type(DMU_OST_ZFS, space_delta_cb);
 
        g_readonly = readonly;
-
-       /*
-        * If we only want readonly access, it's OK if we find
-        * a potentially-active (ie, imported into the kernel) pool from the
-        * default cachefile.
-        */
-       if (readonly && spa_open(target, &spa, FTAG) == 0) {
-               spa_close(spa, FTAG);
-               return;
-       }
-
        g_importargs.unique = B_TRUE;
        g_importargs.can_be_active = readonly;
        g_pool = strdup(target);
-       if ((sepp = strpbrk(g_pool, "/@")) != NULL)
-               *sepp = '\0';
-       g_importargs.poolname = g_pool;
-       pools = zpool_search_import(g_zfs, &g_importargs);
-
-       if (nvlist_empty(pools)) {
-               if (!g_importargs.can_be_active) {
-                       g_importargs.can_be_active = B_TRUE;
-                       if (zpool_search_import(g_zfs, &g_importargs) != NULL ||
-                           spa_open(target, &spa, FTAG) == 0) {
-                               fatal("cannot import '%s': pool is active; run "
-                                   "\"zpool export %s\" first\n",
-                                   g_pool, g_pool);
-                       }
-               }
-
-               fatal("cannot import '%s': no such pool available\n", g_pool);
-       }
 
-       elem = nvlist_next_nvpair(pools, NULL);
-       name = nvpair_name(elem);
-       VERIFY(nvpair_value_nvlist(elem, &config) == 0);
+       error = zpool_tryimport(g_zfs, target, &config, &g_importargs);
+       if (error)
+               fatal(NULL, FTAG, "cannot import '%s': %s", target,
+                   libzfs_error_description(g_zfs));
 
        props = NULL;
        if (readonly) {
@@ -179,31 +151,34 @@ import_pool(const char *target, boolean_t readonly)
        }
 
        zfeature_checks_disable = B_TRUE;
-       error = spa_import(name, config, props, ZFS_IMPORT_NORMAL);
+       error = spa_import(target, config, props,
+           (readonly ?  ZFS_IMPORT_SKIP_MMP : ZFS_IMPORT_NORMAL));
        zfeature_checks_disable = B_FALSE;
        if (error == EEXIST)
                error = 0;
 
        if (error)
-               fatal("can't import '%s': %s", name, strerror(error));
+               fatal(NULL, FTAG, "can't import '%s': %s", target,
+                   strerror(error));
 }
 
 static void
-zhack_spa_open(const char *target, boolean_t readonly, void *tag, spa_t **spa)
+zhack_spa_open(char *target, boolean_t readonly, void *tag, spa_t **spa)
 {
        int err;
 
-       import_pool(target, readonly);
+       zhack_import(target, readonly);
 
        zfeature_checks_disable = B_TRUE;
        err = spa_open(target, spa, tag);
        zfeature_checks_disable = B_FALSE;
 
        if (err != 0)
-               fatal("cannot open '%s': %s", target, strerror(err));
+               fatal(*spa, FTAG, "cannot open '%s': %s", target,
+                   strerror(err));
        if (spa_version(*spa) < SPA_VERSION_FEATURES) {
-               fatal("'%s' has version %d, features not enabled", target,
-                   (int)spa_version(*spa));
+               fatal(*spa, FTAG, "'%s' has version %d, features not enabled",
+                   target, (int)spa_version(*spa));
        }
 }
 
@@ -269,32 +244,36 @@ zhack_do_feature_stat(int argc, char **argv)
        dump_obj(os, spa->spa_feat_for_read_obj, "for_read");
        dump_obj(os, spa->spa_feat_for_write_obj, "for_write");
        dump_obj(os, spa->spa_feat_desc_obj, "descriptions");
+       if (spa_feature_is_active(spa, SPA_FEATURE_ENABLED_TXG)) {
+               dump_obj(os, spa->spa_feat_enabled_txg_obj, "enabled_txg");
+       }
        dump_mos(spa);
 
        spa_close(spa, FTAG);
 }
 
 static void
-feature_enable_sync(void *arg, dmu_tx_t *tx)
+zhack_feature_enable_sync(void *arg, dmu_tx_t *tx)
 {
        spa_t *spa = dmu_tx_pool(tx)->dp_spa;
        zfeature_info_t *feature = arg;
 
-       spa_feature_enable(spa, feature, 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
 zhack_do_feature_enable(int argc, char **argv)
 {
-       char c;
+       int c;
        char *desc, *target;
        spa_t *spa;
        objset_t *mos;
        zfeature_info_t feature;
-       zfeature_info_t *nodeps[] = { NULL };
+       spa_feature_t nodeps[] = { SPA_FEATURE_NONE };
 
        /*
         * Features are not added to the pool's label until their refcounts
@@ -302,15 +281,15 @@ 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_flags = 0;
        feature.fi_depends = nodeps;
+       feature.fi_feature = SPA_FEATURE_NONE;
 
        optind = 1;
-       while ((c = getopt(argc, argv, "rmd:")) != -1) {
+       while ((c = getopt(argc, argv, "+rd:")) != -1) {
                switch (c) {
                case 'r':
-                       feature.fi_can_readonly = B_TRUE;
+                       feature.fi_flags |= ZFEATURE_FLAG_READONLY_COMPAT;
                        break;
                case 'd':
                        desc = strdup(optarg);
@@ -336,18 +315,19 @@ zhack_do_feature_enable(int argc, char **argv)
        feature.fi_guid = argv[1];
 
        if (!zfeature_is_valid_guid(feature.fi_guid))
-               fatal("invalid feature guid: %s", 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 (0 == zfeature_lookup_guid(feature.fi_guid, NULL))
-               fatal("'%s' is a real feature, will not enable");
+       if (zfeature_is_supported(feature.fi_guid))
+               fatal(spa, FTAG, "'%s' is a real feature, will not enable");
        if (0 == zap_contains(mos, spa->spa_feat_desc_obj, feature.fi_guid))
-               fatal("feature already enabled: %s", feature.fi_guid);
+               fatal(spa, FTAG, "feature already enabled: %s",
+                   feature.fi_guid);
 
        VERIFY0(dsl_sync_task(spa_name(spa), NULL,
-           feature_enable_sync, &feature, 5));
+           zhack_feature_enable_sync, &feature, 5, ZFS_SPACE_CHECK_NORMAL));
 
        spa_close(spa, FTAG);
 
@@ -359,8 +339,10 @@ feature_incr_sync(void *arg, dmu_tx_t *tx)
 {
        spa_t *spa = dmu_tx_pool(tx)->dp_spa;
        zfeature_info_t *feature = arg;
+       uint64_t refcount;
 
-       spa_feature_incr(spa, feature, tx);
+       VERIFY0(feature_get_refcount_from_disk(spa, feature, &refcount));
+       feature_sync(spa, feature, refcount + 1, tx);
        spa_history_log_internal(spa, "zhack feature incr", tx,
            "name=%s", feature->fi_guid);
 }
@@ -370,8 +352,10 @@ feature_decr_sync(void *arg, dmu_tx_t *tx)
 {
        spa_t *spa = dmu_tx_pool(tx)->dp_spa;
        zfeature_info_t *feature = arg;
+       uint64_t refcount;
 
-       spa_feature_decr(spa, feature, tx);
+       VERIFY0(feature_get_refcount_from_disk(spa, feature, &refcount));
+       feature_sync(spa, feature, refcount - 1, tx);
        spa_history_log_internal(spa, "zhack feature decr", tx,
            "name=%s", feature->fi_guid);
 }
@@ -379,13 +363,13 @@ feature_decr_sync(void *arg, dmu_tx_t *tx)
 static void
 zhack_do_feature_ref(int argc, char **argv)
 {
-       char c;
+       int c;
        char *target;
        boolean_t decr = B_FALSE;
        spa_t *spa;
        objset_t *mos;
        zfeature_info_t feature;
-       zfeature_info_t *nodeps[] = { NULL };
+       spa_feature_t nodeps[] = { SPA_FEATURE_NONE };
 
        /*
         * fi_desc does not matter here because it was written to disk
@@ -394,15 +378,16 @@ 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;
 
        optind = 1;
-       while ((c = getopt(argc, argv, "md")) != -1) {
+       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;
@@ -423,29 +408,38 @@ zhack_do_feature_ref(int argc, char **argv)
        feature.fi_guid = argv[1];
 
        if (!zfeature_is_valid_guid(feature.fi_guid))
-               fatal("invalid feature guid: %s", 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 (0 == zfeature_lookup_guid(feature.fi_guid, NULL))
-               fatal("'%s' is a real feature, will not change refcount");
+       if (zfeature_is_supported(feature.fi_guid)) {
+               fatal(spa, FTAG,
+                   "'%s' is a real feature, will not change refcount");
+       }
 
        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("feature is not enabled: %s", feature.fi_guid);
+               fatal(spa, FTAG, "feature is not enabled: %s", feature.fi_guid);
        }
 
-       if (decr && !spa_feature_is_active(spa, &feature))
-               fatal("feature refcount already 0: %s", feature.fi_guid);
+       if (decr) {
+               uint64_t count;
+               if (feature_get_refcount_from_disk(spa, &feature,
+                   &count) == 0 && count == 0) {
+                       fatal(spa, FTAG, "feature refcount already 0: %s",
+                           feature.fi_guid);
+               }
+       }
 
        VERIFY0(dsl_sync_task(spa_name(spa), NULL,
-           decr ? feature_decr_sync : feature_incr_sync, &feature, 5));
+           decr ? feature_decr_sync : feature_incr_sync, &feature,
+           5, ZFS_SPACE_CHECK_NORMAL));
 
        spa_close(spa, FTAG);
 }
@@ -489,14 +483,14 @@ main(int argc, char **argv)
        char *path[MAX_NUM_PATHS];
        const char *subcommand;
        int rv = 0;
-       char c;
+       int c;
 
        g_importargs.path = path;
 
        dprintf_setup(&argc, argv);
        zfs_prop_init();
 
-       while ((c = getopt(argc, argv, "c:d:")) != -1) {
+       while ((c = getopt(argc, argv, "+c:d:")) != -1) {
                switch (c) {
                case 'c':
                        g_importargs.cachefile = optarg;
@@ -530,8 +524,8 @@ main(int argc, char **argv)
                usage();
        }
 
-       if (!g_readonly && spa_export(g_pool, NULL, B_TRUE, B_TRUE) != 0) {
-               fatal("pool export failed; "
+       if (!g_readonly && spa_export(g_pool, NULL, B_TRUE, B_FALSE) != 0) {
+               fatal(NULL, FTAG, "pool export failed; "
                    "changes may not be committed to disk\n");
        }