]> git.proxmox.com Git - mirror_zfs.git/blobdiff - cmd/zfs/zfs_main.c
Disable 'zfs remap' command
[mirror_zfs.git] / cmd / zfs / zfs_main.c
index cf2d8f2d515e974442ad31dad90bfd101e31668d..b8258a9cf53be4c3ad634683748463831cdc0981 100644 (file)
@@ -66,6 +66,7 @@
 #include <libzfs_core.h>
 #include <zfs_prop.h>
 #include <zfs_deleg.h>
+#include <libzutil.h>
 #include <libuutil.h>
 #ifdef HAVE_IDMAP
 #include <aclutils.h>
@@ -4239,10 +4240,21 @@ zfs_do_receive(int argc, char **argv)
                        }
                        break;
                case 'd':
+                       if (flags.istail) {
+                               (void) fprintf(stderr, gettext("invalid option "
+                                   "combination: -d and -e are mutually "
+                                   "exclusive\n"));
+                               usage(B_FALSE);
+                       }
                        flags.isprefix = B_TRUE;
                        break;
                case 'e':
-                       flags.isprefix = B_TRUE;
+                       if (flags.isprefix) {
+                               (void) fprintf(stderr, gettext("invalid option "
+                                   "combination: -d and -e are mutually "
+                                   "exclusive\n"));
+                               usage(B_FALSE);
+                       }
                        flags.istail = B_TRUE;
                        break;
                case 'n':
@@ -4278,6 +4290,10 @@ zfs_do_receive(int argc, char **argv)
        argc -= optind;
        argv += optind;
 
+       /* zfs recv -e (use "tail" name) implies -d (remove dataset "head") */
+       if (flags.istail)
+               flags.isprefix = B_TRUE;
+
        /* check number of arguments */
        if (argc < 1) {
                (void) fprintf(stderr, gettext("missing snapshot argument\n"));
@@ -5476,7 +5492,6 @@ print_set_creat_perms(uu_avl_t *who_avl)
                gettext("Create time permissions:\n"),
                NULL
        };
-       const char **title_ptr = sc_title;
        who_perm_node_t *who_node = NULL;
        int prev_weight = -1;
 
@@ -5490,7 +5505,7 @@ print_set_creat_perms(uu_avl_t *who_avl)
                deleg_perm_node_t *deleg_node;
 
                if (prev_weight != weight) {
-                       (void) printf("%s", *title_ptr++);
+                       (void) printf("%s", sc_title[weight]);
                        prev_weight = weight;
                }
 
@@ -6059,7 +6074,12 @@ zfs_do_holds(int argc, char **argv)
 
 #define        CHECK_SPINNER 30
 #define        SPINNER_TIME 3          /* seconds */
-#define        MOUNT_TIME 5            /* seconds */
+#define        MOUNT_TIME 1            /* seconds */
+
+typedef struct get_all_state {
+       boolean_t       ga_verbose;
+       get_all_cb_t    *ga_cbp;
+} get_all_state_t;
 
 static int
 get_one_dataset(zfs_handle_t *zhp, void *data)
@@ -6068,10 +6088,10 @@ get_one_dataset(zfs_handle_t *zhp, void *data)
        static int spinval = 0;
        static int spincheck = 0;
        static time_t last_spin_time = (time_t)0;
-       get_all_cb_t *cbp = data;
+       get_all_state_t *state = data;
        zfs_type_t type = zfs_get_type(zhp);
 
-       if (cbp->cb_verbose) {
+       if (state->ga_verbose) {
                if (--spincheck < 0) {
                        time_t now = time(NULL);
                        if (last_spin_time + SPINNER_TIME < now) {
@@ -6097,25 +6117,23 @@ get_one_dataset(zfs_handle_t *zhp, void *data)
                zfs_close(zhp);
                return (0);
        }
-       libzfs_add_handle(cbp, zhp);
-       assert(cbp->cb_used <= cbp->cb_alloc);
+       libzfs_add_handle(state->ga_cbp, zhp);
+       assert(state->ga_cbp->cb_used <= state->ga_cbp->cb_alloc);
 
        return (0);
 }
 
 static void
-get_all_datasets(zfs_handle_t ***dslist, size_t *count, boolean_t verbose)
+get_all_datasets(get_all_cb_t *cbp, boolean_t verbose)
 {
-       get_all_cb_t cb = { 0 };
-       cb.cb_verbose = verbose;
-       cb.cb_getone = get_one_dataset;
+       get_all_state_t state = {
+           .ga_verbose = verbose,
+           .ga_cbp = cbp
+       };
 
        if (verbose)
                set_progress_header(gettext("Reading ZFS config"));
-       (void) zfs_iter_root(g_zfs, get_one_dataset, &cb);
-
-       *dslist = cb.cb_handles;
-       *count = cb.cb_used;
+       (void) zfs_iter_root(g_zfs, get_one_dataset, &state);
 
        if (verbose)
                finish_progress(gettext("done."));
@@ -6126,8 +6144,19 @@ get_all_datasets(zfs_handle_t ***dslist, size_t *count, boolean_t verbose)
  * similar, we have a common function with an extra parameter to determine which
  * mode we are using.
  */
-#define        OP_SHARE        0x1
-#define        OP_MOUNT        0x2
+typedef enum { OP_SHARE, OP_MOUNT } share_mount_op_t;
+
+typedef struct share_mount_state {
+       share_mount_op_t        sm_op;
+       boolean_t       sm_verbose;
+       int     sm_flags;
+       char    *sm_options;
+       char    *sm_proto; /* only valid for OP_SHARE */
+       pthread_mutex_t sm_lock; /* protects the remaining fields */
+       uint_t  sm_total; /* number of filesystems to process */
+       uint_t  sm_done; /* number of filesystems processed */
+       int     sm_status; /* -1 if any of the share/mount operations failed */
+} share_mount_state_t;
 
 /*
  * Share or mount a dataset.
@@ -6385,6 +6414,29 @@ report_mount_progress(int current, int total)
                update_progress(info);
 }
 
+/*
+ * zfs_foreach_mountpoint() callback that mounts or shares one filesystem and
+ * updates the progress meter.
+ */
+static int
+share_mount_one_cb(zfs_handle_t *zhp, void *arg)
+{
+       share_mount_state_t *sms = arg;
+       int ret;
+
+       ret = share_mount_one(zhp, sms->sm_op, sms->sm_flags, sms->sm_proto,
+           B_FALSE, sms->sm_options);
+
+       pthread_mutex_lock(&sms->sm_lock);
+       if (ret != 0)
+               sms->sm_status = ret;
+       sms->sm_done++;
+       if (sms->sm_verbose)
+               report_mount_progress(sms->sm_done, sms->sm_total);
+       pthread_mutex_unlock(&sms->sm_lock);
+       return (ret);
+}
+
 static void
 append_options(char *mntopts, char *newopts)
 {
@@ -6459,8 +6511,6 @@ share_mount(int op, int argc, char **argv)
 
        /* check number of arguments */
        if (do_all) {
-               zfs_handle_t **dslist = NULL;
-               size_t i, count = 0;
                char *protocol = NULL;
 
                if (op == OP_SHARE && argc > 0) {
@@ -6481,27 +6531,35 @@ share_mount(int op, int argc, char **argv)
                }
 
                start_progress_timer();
-               get_all_datasets(&dslist, &count, verbose);
+               get_all_cb_t cb = { 0 };
+               get_all_datasets(&cb, verbose);
 
-               if (count == 0) {
+               if (cb.cb_used == 0) {
                        if (options != NULL)
                                free(options);
                        return (0);
                }
 
-               qsort(dslist, count, sizeof (void *), libzfs_dataset_cmp);
-
-               for (i = 0; i < count; i++) {
-                       if (verbose)
-                               report_mount_progress(i, count);
+               share_mount_state_t share_mount_state = { 0 };
+               share_mount_state.sm_op = op;
+               share_mount_state.sm_verbose = verbose;
+               share_mount_state.sm_flags = flags;
+               share_mount_state.sm_options = options;
+               share_mount_state.sm_proto = protocol;
+               share_mount_state.sm_total = cb.cb_used;
+               pthread_mutex_init(&share_mount_state.sm_lock, NULL);
 
-                       if (share_mount_one(dslist[i], op, flags, protocol,
-                           B_FALSE, options) != 0)
-                               ret = 1;
-                       zfs_close(dslist[i]);
-               }
+               /*
+                * libshare isn't mt-safe, so only do the operation in parallel
+                * if we're mounting.
+                */
+               zfs_foreach_mountpoint(g_zfs, cb.cb_handles, cb.cb_used,
+                   share_mount_one_cb, &share_mount_state, op == OP_MOUNT);
+               ret = share_mount_state.sm_status;
 
-               free(dslist);
+               for (int i = 0; i < cb.cb_used; i++)
+                       zfs_close(cb.cb_handles[i]);
+               free(cb.cb_handles);
        } else if (argc == 0) {
                struct mnttab entry;
 
@@ -7025,6 +7083,21 @@ zfs_do_unshare(int argc, char **argv)
        return (unshare_unmount(OP_SHARE, argc, argv));
 }
 
+static int
+disable_command_idx(char *command)
+{
+       for (int i = 0; i < NCOMMAND; i++) {
+               if (command_table[i].name == NULL)
+                       continue;
+
+               if (strcmp(command, command_table[i].name) == 0) {
+                       command_table[i].name = NULL;
+                       return (0);
+               }
+       }
+       return (1);
+}
+
 static int
 find_command_idx(char *command, int *idx)
 {
@@ -7122,7 +7195,22 @@ zfs_do_diff(int argc, char **argv)
 /*
  * zfs remap <filesystem | volume>
  *
- * Remap the indirect blocks in the given fileystem or volume.
+ * N.B. The remap command has been disabled and may be removed in the future.
+ *
+ * Remap the indirect blocks in the given filesystem or volume so that they no
+ * longer reference blocks on previously removed vdevs and we can eventually
+ * shrink the size of the indirect mapping objects for the previously removed
+ * vdevs. Note that remapping all blocks might not be possible and that
+ * references from snapshots will still exist and cannot be remapped.
+ *
+ * This functionality is no longer particularly useful now that the removal
+ * code can map large chunks.  Furthermore, explaining what this command
+ * does and why it may be useful requires a detailed understanding of the
+ * internals of device removal.  These are details users should not be
+ * bothered with.  If required, the remap command can be re-enabled by
+ * setting the ZFS_REMAP_ENABLED environment variable.
+ *
+ * > ZFS_REMAP_ENABLED=yes zfs remap <filesystem | volume>
  */
 static int
 zfs_do_remap(int argc, char **argv)
@@ -7238,7 +7326,7 @@ zfs_do_bookmark(int argc, char **argv)
        fnvlist_free(nvl);
 
        if (ret != 0) {
-               const char *err_msg;
+               const char *err_msg = NULL;
                char errbuf[1024];
 
                (void) snprintf(errbuf, sizeof (errbuf),
@@ -7265,11 +7353,13 @@ zfs_do_bookmark(int argc, char **argv)
                        err_msg = "dataset does not exist";
                        break;
                default:
-                       err_msg = "unknown error";
+                       (void) zfs_standard_error(g_zfs, ret, errbuf);
                        break;
                }
-               (void) fprintf(stderr, "%s: %s\n", errbuf,
-                   dgettext(TEXT_DOMAIN, err_msg));
+               if (err_msg != NULL) {
+                       (void) fprintf(stderr, "%s: %s\n", errbuf,
+                           dgettext(TEXT_DOMAIN, err_msg));
+               }
        }
 
        return (ret != 0);
@@ -7285,7 +7375,7 @@ zfs_do_channel_program(int argc, char **argv)
        int ret, fd, c;
        char *progbuf, *filename, *poolname;
        size_t progsize, progread;
-       nvlist_t *outnvl;
+       nvlist_t *outnvl = NULL;
        uint64_t instrlimit = ZCP_DEFAULT_INSTRLIMIT;
        uint64_t memlimit = ZCP_DEFAULT_MEMLIMIT;
        boolean_t sync_flag = B_TRUE, json_output = B_FALSE;
@@ -7412,8 +7502,9 @@ zfs_do_channel_program(int argc, char **argv)
                 * falling back on strerror() for an unexpected return code.
                 */
                char *errstring = NULL;
+               const char *msg = gettext("Channel program execution failed");
                uint64_t instructions = 0;
-               if (nvlist_exists(outnvl, ZCP_RET_ERROR)) {
+               if (outnvl != NULL && nvlist_exists(outnvl, ZCP_RET_ERROR)) {
                        (void) nvlist_lookup_string(outnvl,
                            ZCP_RET_ERROR, &errstring);
                        if (errstring == NULL)
@@ -7442,12 +7533,12 @@ zfs_do_channel_program(int argc, char **argv)
                                    "programs must be run as root.";
                                break;
                        default:
-                               errstring = strerror(ret);
+                               (void) zfs_standard_error(g_zfs, ret, msg);
                        }
                }
-               (void) fprintf(stderr,
-                   gettext("Channel program execution failed:\n%s\n"),
-                   errstring);
+               if (errstring != NULL)
+                       (void) fprintf(stderr, "%s:\n%s\n", msg, errstring);
+
                if (ret == ETIME && instructions != 0)
                        (void) fprintf(stderr,
                            gettext("%llu Lua instructions\n"),
@@ -7945,6 +8036,13 @@ main(int argc, char **argv)
        if (strcmp(cmdname, "snap") == 0)
                cmdname = "snapshot";
 
+       /*
+        * The 'remap' command has been disabled and may be removed in the
+        * future.  See the comment above zfs_do_remap() for details.
+        */
+       if (!libzfs_envvar_is_set("ZFS_REMAP_ENABLED"))
+               disable_command_idx("remap");
+
        /*
         * Special case '-?'
         */