]> git.sesse.net Git - bcachefs-tools-debian/commitdiff
Use opts.h for format options
authorKent Overstreet <kent.overstreet@gmail.com>
Wed, 19 Dec 2018 20:23:59 +0000 (15:23 -0500)
committerKent Overstreet <kent.overstreet@gmail.com>
Wed, 19 Dec 2018 23:27:57 +0000 (18:27 -0500)
cmd_device.c
cmd_format.c
cmd_migrate.c
libbcachefs.c
libbcachefs.h
tools-util.c
tools-util.h

index fa63e48d1b10adde910c2fc3e5ebc8b0f4ea7db4..797b958c0bb32a8fe8f45cde0ed9694f9c77d5d6 100644 (file)
@@ -95,12 +95,20 @@ int cmd_device_add(int argc, char *argv[])
        dev_opts.path = dev_path;
        dev_opts.fd = open_for_format(dev_opts.path, force);
 
-       format_opts.block_size  =
-               read_file_u64(fs.sysfs_fd, "block_size") >> 9;
-       format_opts.btree_node_size =
-               read_file_u64(fs.sysfs_fd, "btree_node_size") >> 9;
+       struct bch_opt_strs fs_opt_strs;
+       memset(&fs_opt_strs, 0, sizeof(fs_opt_strs));
 
-       struct bch_sb *sb = bch2_format(format_opts, &dev_opts, 1);
+       struct bch_opts fs_opts = bch2_parse_opts(fs_opt_strs);
+
+       opt_set(fs_opts, block_size,
+               read_file_u64(fs.sysfs_fd, "block_size") >> 9);
+       opt_set(fs_opts, btree_node_size,
+               read_file_u64(fs.sysfs_fd, "btree_node_size") >> 9);
+
+       struct bch_sb *sb = bch2_format(fs_opt_strs,
+                                       fs_opts,
+                                       format_opts,
+                                       &dev_opts, 1);
        free(sb);
        fsync(dev_opts.fd);
        close(dev_opts.fd);
index a4824947a3c8ff46275cc5496ff7b92ba5c725bc..83246a0f717c42c4f4a89e503fb10d36b15d1199 100644 (file)
@@ -5,6 +5,7 @@
  *
  * GPLv2
  */
+#include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <getopt.h>
 #include "libbcachefs/super-io.h"
 #include "libbcachefs/util.h"
 
-#define OPTS                                                                   \
-t("bcachefs format - create a new bcachefs filesystem on one or more devices") \
-t("Usage: bcachefs format [OPTION]... <devices>")                              \
-t("")                                                                          \
-x('b', block_size,             "size",                 NULL)                   \
-x(0,   btree_node_size,        "size",                 "Default 256k")         \
-x(0,   metadata_checksum_type, "(none|crc32c|crc64)",  NULL)                   \
-x(0,   data_checksum_type,     "(none|crc32c|crc64)",  NULL)                   \
-x(0,   compression_type,       "(none|lz4|gzip)",      NULL)                   \
-x(0,   background_compression_type,    "(none|lz4|gzip)",      NULL)           \
-x(0,   replicas,               "#",                    NULL)                   \
-x(0,   data_replicas,          "#",                    NULL)                   \
-x(0,   metadata_replicas,      "#",                    NULL)                   \
-x(0,   foreground_target,      "target",               NULL)                   \
-x(0,   background_target,      "target",               NULL)                   \
-x(0,   promote_target,         "target",               NULL)                   \
-x(0,   encrypted,              NULL,                   "Enable whole filesystem encryption (chacha20/poly1305)")\
-x(0,   no_passphrase,          NULL,                   "Don't encrypt master encryption key")\
-x('e', error_action,           "(continue|remount-ro|panic)", NULL)            \
-x('L', label,                  "label",                NULL)                   \
-x('U', uuid,                   "uuid",                 NULL)                   \
-x('f', force,                  NULL,                   NULL)                   \
-t("")                                                                          \
-t("Device specific options:")                                                  \
-x(0,   fs_size,                "size",                 "Size of filesystem on device")\
-x(0,   bucket_size,            "size",                 "Bucket size")          \
-x('g', group,                  "label",                "Disk group")\
-x(0,   discard,                NULL,                   NULL)                   \
-x(0,   data_allowed,           "journal,btree,data",   "Allowed types of data on this device")\
-x(0,   durability,             "#",                    "Number of times data written to this device will have been considered replicated")\
-t("Device specific options must come before corresponding devices, e.g.")      \
-t("  bcachefs format --group cache /dev/sdb --tier 1 /dev/sdc")                        \
-t("")                                                                          \
-x('q', quiet,                  NULL,                   "Only print errors")    \
-x('h', help,                   NULL,                   "Display this help and exit")
+#define OPTS                                           \
+x(0,   replicas,               required_argument)      \
+x(0,   encrypted,              no_argument)            \
+x(0,   no_passphrase,          no_argument)            \
+x('L', label,                  required_argument)      \
+x('U', uuid,                   required_argument)      \
+x(0,   fs_size,                required_argument)      \
+x(0,   bucket_size,            required_argument)      \
+x('g', group,                  required_argument)      \
+x(0,   discard,                no_argument)            \
+x(0,   data_allowed,           required_argument)      \
+x(0,   durability,             required_argument)      \
+x('f', force,                  no_argument)            \
+x('q', quiet,                  no_argument)            \
+x('h', help,                   no_argument)
 
 static void usage(void)
 {
-#define t(text)                                puts(text "\n")
-#define x(shortopt, longopt, arg, help) do {                           \
-       OPTS
-#undef x
-#undef t
-
        puts("bcachefs format - create a new bcachefs filesystem on one or more devices\n"
             "Usage: bcachefs format [OPTION]... <devices>\n"
             "\n"
-            "Options:\n"
-            "  -b, --block=size\n"
-            "      --btree_node=size       Btree node size, default 256k\n"
-            "      --metadata_checksum_type=(none|crc32c|crc64)\n"
-            "      --data_checksum_type=(none|crc32c|crc64)\n"
-            "      --compression_type=(none|lz4|gzip|zstd)\n"
-            "      --background_compression_type=(none|lz4|gzip|zstd)\n"
-            "      --data_replicas=#       Number of data replicas\n"
-            "      --metadata_replicas=#   Number of metadata replicas\n"
+            "Options:");
+
+       bch2_opts_usage(OPT_FORMAT);
+
+       puts(
             "      --replicas=#            Sets both data and metadata replicas\n"
             "      --encrypted             Enable whole filesystem encryption (chacha20/poly1305)\n"
             "      --no_passphrase         Don't encrypt master encryption key\n"
-            "  -e, --error_action=(continue|remount-ro|panic)\n"
-            "                              Action to take on filesystem error\n"
             "  -L, --label=label\n"
             "  -U, --uuid=uuid\n"
-            "  -f, --force\n"
             "\n"
-            "Device specific options:\n"
-            "      --fs_size=size          Size of filesystem on device\n"
-            "      --bucket=size           Bucket size\n"
-            "      --discard               Enable discards\n"
-            "      --durability=#          Device durability (0-4)\n"
-            "  -g, --group=label           Disk group\n"
+            "Device specific options:");
+
+       bch2_opts_usage(OPT_DEVICE);
+
+       puts("  -g, --group=label           Disk group\n"
             "\n"
+            "  -f, --force\n"
             "  -q, --quiet                 Only print errors\n"
             "  -h, --help                  Display this help and exit\n"
             "\n"
             "Device specific options must come before corresponding devices, e.g.\n"
-            "  bcachefs format --group cache /dev/sdb --tier 1 /dev/sdc\n"
+            "  bcachefs format --group cache /dev/sdb /dev/sdc\n"
             "\n"
             "Report bugs to <linux-bcache@vger.kernel.org>");
 }
 
 enum {
        O_no_opt = 1,
-#define t(text)
-#define x(shortopt, longopt, arg, help)        O_##longopt,
+#define x(shortopt, longopt, arg)      O_##longopt,
        OPTS
 #undef x
-#undef t
 };
 
-static const struct option format_opts[] = {
-#define t(text)
-#define x(shortopt, longopt, arg, help)        {                               \
-       .name           = #longopt,                                     \
-       .has_arg        = arg ? required_argument : no_argument,        \
-       .flag           = NULL,                                         \
-       .val            = O_##longopt,                                  \
+#define x(shortopt, longopt, arg) {                    \
+       .name           = #longopt,                     \
+       .has_arg        = arg,                          \
+       .flag           = NULL,                         \
+       .val            = O_##longopt,                  \
 },
+static const struct option format_opts[] = {
        OPTS
-#undef x
-#undef t
        { NULL }
 };
+#undef x
 
 u64 read_flag_list_or_die(char *opt, const char * const list[],
                          const char *msg)
@@ -148,73 +112,28 @@ int cmd_format(int argc, char *argv[])
        struct format_opts opts = format_opts_default();
        struct dev_opts dev_opts = dev_opts_default(), *dev;
        bool force = false, no_passphrase = false, quiet = false;
+       unsigned v;
        int opt;
 
        darray_init(devices);
 
+       struct bch_opt_strs fs_opt_strs =
+               bch2_cmdline_opts_get(&argc, argv, OPT_FORMAT);
+       struct bch_opts fs_opts = bch2_parse_opts(fs_opt_strs);
+
        while ((opt = getopt_long(argc, argv,
-                                 "-b:e:g:L:U:fqh",
+                                 "-L:U:fh",
                                  format_opts,
                                  NULL)) != -1)
                switch (opt) {
-               case O_block_size:
-               case 'b':
-                       opts.block_size =
-                               hatoi_validate(optarg, "block size");
-                       break;
-               case O_btree_node_size:
-                       opts.btree_node_size =
-                               hatoi_validate(optarg, "btree node size");
-                       break;
-               case O_metadata_checksum_type:
-                       opts.meta_csum_type =
-                               read_string_list_or_die(optarg,
-                                               bch2_csum_types, "checksum type");
-                       break;
-               case O_data_checksum_type:
-                       opts.data_csum_type =
-                               read_string_list_or_die(optarg,
-                                               bch2_csum_types, "checksum type");
-                       break;
-               case O_compression_type:
-                       opts.compression_type =
-                               read_string_list_or_die(optarg,
-                                               bch2_compression_types,
-                                               "compression type");
-                       break;
-               case O_background_compression_type:
-                       opts.background_compression_type =
-                               read_string_list_or_die(optarg,
-                                               bch2_compression_types,
-                                               "compression type");
-                       break;
-               case O_data_replicas:
-                       if (kstrtouint(optarg, 10, &opts.data_replicas) ||
-                           !opts.data_replicas ||
-                           opts.data_replicas > BCH_REPLICAS_MAX)
-                               die("invalid replicas");
-                       break;
-               case O_metadata_replicas:
-                       if (kstrtouint(optarg, 10, &opts.meta_replicas) ||
-                           !opts.meta_replicas ||
-                           opts.meta_replicas > BCH_REPLICAS_MAX)
-                               die("invalid replicas");
-                       break;
                case O_replicas:
-                       if (kstrtouint(optarg, 10, &opts.data_replicas) ||
-                           !opts.data_replicas ||
-                           opts.data_replicas > BCH_REPLICAS_MAX)
+                       if (kstrtouint(optarg, 10, &v) ||
+                           !v ||
+                           v > BCH_REPLICAS_MAX)
                                die("invalid replicas");
-                       opts.meta_replicas = opts.data_replicas;
-                       break;
-               case O_foreground_target:
-                       opts.foreground_target = optarg;
-                       break;
-               case O_background_target:
-                       opts.background_target = optarg;
-                       break;
-               case O_promote_target:
-                       opts.promote_target = optarg;
+
+                       opt_set(fs_opts, metadata_replicas, v);
+                       opt_set(fs_opts, data_replicas, v);
                        break;
                case O_encrypted:
                        opts.encrypted = true;
@@ -222,12 +141,6 @@ int cmd_format(int argc, char *argv[])
                case O_no_passphrase:
                        no_passphrase = true;
                        break;
-               case O_error_action:
-               case 'e':
-                       opts.on_error_action =
-                               read_string_list_or_die(optarg,
-                                               bch2_error_actions, "error action");
-                       break;
                case O_label:
                case 'L':
                        opts.label = optarg;
@@ -282,6 +195,9 @@ int cmd_format(int argc, char *argv[])
                        usage();
                        exit(EXIT_SUCCESS);
                        break;
+               case '?':
+                       die("unrecognized option %s", optarg);
+                       break;
                }
 
        if (darray_empty(devices))
@@ -294,7 +210,10 @@ int cmd_format(int argc, char *argv[])
                dev->fd = open_for_format(dev->path, force);
 
        struct bch_sb *sb =
-               bch2_format(opts, devices.item, darray_size(devices));
+               bch2_format(fs_opt_strs,
+                           fs_opts,
+                           opts,
+                           devices.item, darray_size(devices));
 
        if (!quiet)
                bch2_sb_print(sb, false, 1 << BCH_SB_FIELD_members, HUMAN_READABLE);
index 8f464858781ee8e85cf025257b0557e4f73fa064..2d82d157e7f8add7f61dfbf4536a6dac748dcd53 100644 (file)
@@ -185,13 +185,13 @@ static struct bch_inode_unpacked create_file(struct bch_fs *c,
                        (handler) != NULL;                      \
                        (handler) = *(handlers)++)
 
-static const struct xattr_handler *xattr_resolve_name(const char **name)
+static const struct xattr_handler *xattr_resolve_name(char **name)
 {
        const struct xattr_handler **handlers = bch2_xattr_handlers;
        const struct xattr_handler *handler;
 
        for_each_xattr_handler(handlers, handler) {
-               const char *n;
+               char *n;
 
                n = strcmp_prefix(*name, xattr_prefix(handler));
                if (n) {
@@ -225,7 +225,7 @@ static void copy_xattrs(struct bch_fs *c, struct bch_inode_unpacked *dst,
        if (attrs_size < 0)
                die("listxattr error: %m");
 
-       const char *next, *attr;
+       char *next, *attr;
        for (attr = attrs;
             attr < attrs + attrs_size;
             attr = next) {
@@ -657,8 +657,10 @@ static const struct option migrate_opts[] = {
        { NULL }
 };
 
-static int migrate_fs(const char *fs_path,
-                     struct format_opts format_opts,
+static int migrate_fs(const char               *fs_path,
+                     struct bch_opt_strs       fs_opt_strs,
+                     struct bch_opts           fs_opts,
+                     struct format_opts        format_opts,
                      bool force)
 {
        if (!path_is_fs_root(fs_path))
@@ -675,25 +677,24 @@ static int migrate_fs(const char *fs_path,
        dev.path = dev_t_to_path(stat.st_dev);
        dev.fd = xopen(dev.path, O_RDWR);
 
-       unsigned block_size = get_blocksize(dev.path, dev.fd) << 9;
-       BUG_ON(!is_power_of_2(block_size) || block_size < 512);
-       format_opts.block_size = block_size >> 9;
+       opt_set(fs_opts, block_size, get_blocksize(dev.path, dev.fd));
 
        char *file_path = mprintf("%s/bcachefs", fs_path);
        printf("Creating new filesystem on %s in space reserved at %s\n",
               dev.path, file_path);
 
-       bch2_pick_bucket_size(format_opts, &dev);
+       bch2_pick_bucket_size(fs_opts, &dev);
 
        u64 bcachefs_inum;
        ranges extents = reserve_new_fs_space(file_path,
-                               format_opts.block_size << 9,
+                               fs_opts.block_size << 9,
                                get_size(dev.path, dev.fd) / 5,
                                &bcachefs_inum, stat.st_dev, force);
 
        find_superblock_space(extents, &dev);
 
-       struct bch_sb *sb = bch2_format(format_opts, &dev, 1);
+       struct bch_sb *sb = bch2_format(fs_opt_strs,
+                                       fs_opts,format_opts, &dev, 1);
        u64 sb_offset = le64_to_cpu(sb->layout.sb_offset[0]);
 
        if (format_opts.passphrase)
@@ -757,6 +758,10 @@ int cmd_migrate(int argc, char *argv[])
        bool no_passphrase = false, force = false;
        int opt;
 
+       struct bch_opt_strs fs_opt_strs =
+               bch2_cmdline_opts_get(&argc, argv, OPT_FORMAT);
+       struct bch_opts fs_opts = bch2_parse_opts(fs_opt_strs);
+
        while ((opt = getopt_long(argc, argv, "f:Fh",
                                  migrate_opts, NULL)) != -1)
                switch (opt) {
@@ -783,7 +788,10 @@ int cmd_migrate(int argc, char *argv[])
        if (format_opts.encrypted && !no_passphrase)
                format_opts.passphrase = read_passphrase_twice("Enter passphrase: ");
 
-       return migrate_fs(fs_path, format_opts, force);
+       return migrate_fs(fs_path,
+                         fs_opt_strs,
+                         fs_opts,
+                         format_opts, force);
 }
 
 static void migrate_superblock_usage(void)
index b24e7f37c33fe04ddffac3647150a626855b5e0d..ea52ce4887e277f31051a97b9ddecee31dff8a58 100644 (file)
@@ -23,6 +23,7 @@
 #include "libbcachefs/opts.h"
 #include "libbcachefs/replicas.h"
 #include "libbcachefs/super-io.h"
+#include "tools-util.h"
 
 #define NSEC_PER_SEC   1000000000L
 
@@ -71,7 +72,7 @@ static void init_layout(struct bch_sb_layout *l, unsigned block_size,
        l->sb_offset[1]         = cpu_to_le64(backup);
 }
 
-void bch2_pick_bucket_size(struct format_opts opts, struct dev_opts *dev)
+void bch2_pick_bucket_size(struct bch_opts opts, struct dev_opts *dev)
 {
        if (!dev->sb_offset) {
                dev->sb_offset  = BCH_SB_SECTOR;
@@ -90,7 +91,9 @@ void bch2_pick_bucket_size(struct format_opts opts, struct dev_opts *dev)
                dev->bucket_size = opts.block_size;
 
                /* Bucket size must be >= btree node size: */
-               dev->bucket_size = max(dev->bucket_size, opts.btree_node_size);
+               if (opt_defined(opts, btree_node_size))
+                       dev->bucket_size = max_t(unsigned, dev->bucket_size,
+                                                opts.btree_node_size);
 
                /* Want a bucket size of at least 128k, if possible: */
                dev->bucket_size = max(dev->bucket_size, 256U);
@@ -115,7 +118,8 @@ void bch2_pick_bucket_size(struct format_opts opts, struct dev_opts *dev)
        if (dev->bucket_size < opts.block_size)
                die("Bucket size cannot be smaller than block size");
 
-       if (dev->bucket_size < opts.btree_node_size)
+       if (opt_defined(opts, btree_node_size) &&
+           dev->bucket_size < opts.btree_node_size)
                die("Bucket size cannot be smaller than btree node size");
 
        if (dev->nbuckets < BCH_MIN_NR_NBUCKETS)
@@ -146,37 +150,48 @@ static unsigned parse_target(struct bch_sb_handle *sb,
        return 0;
 }
 
-struct bch_sb *bch2_format(struct format_opts opts,
-                          struct dev_opts *devs, size_t nr_devs)
+struct bch_sb *bch2_format(struct bch_opt_strs fs_opt_strs,
+                          struct bch_opts      fs_opts,
+                          struct format_opts   opts,
+                          struct dev_opts      *devs,
+                          size_t               nr_devs)
 {
        struct bch_sb_handle sb = { NULL };
        struct dev_opts *i;
        struct bch_sb_field_members *mi;
+       unsigned max_dev_block_size = 0;
+       unsigned opt_id;
+
+       for (i = devs; i < devs + nr_devs; i++)
+               max_dev_block_size = max(max_dev_block_size,
+                                        get_blocksize(i->path, i->fd));
 
        /* calculate block size: */
-       if (!opts.block_size)
-               for (i = devs; i < devs + nr_devs; i++)
-                       opts.block_size = max(opts.block_size,
-                                             get_blocksize(i->path, i->fd));
+       if (!opt_defined(fs_opts, block_size)) {
+               opt_set(fs_opts, block_size, max_dev_block_size);
+       } else if (fs_opts.block_size < max_dev_block_size)
+               die("blocksize too small: %u, must be greater than device blocksize %u",
+                   fs_opts.block_size, max_dev_block_size);
 
        /* calculate bucket sizes: */
        for (i = devs; i < devs + nr_devs; i++)
-               bch2_pick_bucket_size(opts, i);
+               bch2_pick_bucket_size(fs_opts, i);
 
        /* calculate btree node size: */
-       if (!opts.btree_node_size) {
+       if (!opt_defined(fs_opts, btree_node_size)) {
                /* 256k default btree node size */
-               opts.btree_node_size = 512;
+               opt_set(fs_opts, btree_node_size, 512);
 
                for (i = devs; i < devs + nr_devs; i++)
-                       opts.btree_node_size =
-                               min(opts.btree_node_size, i->bucket_size);
+                       fs_opts.btree_node_size =
+                               min_t(unsigned, fs_opts.btree_node_size,
+                                     i->bucket_size);
        }
 
-       if (!is_power_of_2(opts.block_size))
+       if (!is_power_of_2(fs_opts.block_size))
                die("block size must be power of 2");
 
-       if (!is_power_of_2(opts.btree_node_size))
+       if (!is_power_of_2(fs_opts.btree_node_size))
                die("btree node size must be power of 2");
 
        if (uuid_is_null(opts.uuid.b))
@@ -188,7 +203,7 @@ struct bch_sb *bch2_format(struct format_opts opts,
        sb.sb->version          = le16_to_cpu(bcachefs_metadata_version_current);
        sb.sb->version_min      = le16_to_cpu(bcachefs_metadata_version_current);
        sb.sb->magic            = BCACHE_MAGIC;
-       sb.sb->block_size       = cpu_to_le16(opts.block_size);
+       sb.sb->block_size       = cpu_to_le16(fs_opts.block_size);
        sb.sb->user_uuid        = opts.uuid;
        sb.sb->nr_devices       = nr_devs;
 
@@ -199,24 +214,24 @@ struct bch_sb *bch2_format(struct format_opts opts,
                       opts.label,
                       min(strlen(opts.label), sizeof(sb.sb->label)));
 
-       SET_BCH_SB_CSUM_TYPE(sb.sb,             opts.meta_csum_type);
-       SET_BCH_SB_META_CSUM_TYPE(sb.sb,        opts.meta_csum_type);
-       SET_BCH_SB_DATA_CSUM_TYPE(sb.sb,        opts.data_csum_type);
-       SET_BCH_SB_COMPRESSION_TYPE(sb.sb,      opts.compression_type);
-       SET_BCH_SB_BACKGROUND_COMPRESSION_TYPE(sb.sb,
-                                               opts.background_compression_type);
-
-       SET_BCH_SB_BTREE_NODE_SIZE(sb.sb,       opts.btree_node_size);
-       SET_BCH_SB_GC_RESERVE(sb.sb,            8);
-       SET_BCH_SB_META_REPLICAS_WANT(sb.sb,    opts.meta_replicas);
-       SET_BCH_SB_META_REPLICAS_REQ(sb.sb,     opts.meta_replicas_required);
-       SET_BCH_SB_DATA_REPLICAS_WANT(sb.sb,    opts.data_replicas);
-       SET_BCH_SB_DATA_REPLICAS_REQ(sb.sb,     opts.data_replicas_required);
-       SET_BCH_SB_ERROR_ACTION(sb.sb,          opts.on_error_action);
-       SET_BCH_SB_STR_HASH_TYPE(sb.sb,         BCH_STR_HASH_SIPHASH);
-       SET_BCH_SB_ENCODED_EXTENT_MAX_BITS(sb.sb,ilog2(opts.encoded_extent_max));
-
-       SET_BCH_SB_POSIX_ACL(sb.sb,             1);
+       for (opt_id = 0;
+            opt_id < bch2_opts_nr;
+            opt_id++) {
+               const struct bch_option *opt = &bch2_opt_table[opt_id];
+               u64 v;
+
+               if (opt->set_sb == SET_NO_SB_OPT)
+                       continue;
+
+               v = bch2_opt_defined_by_id(&fs_opts, opt_id)
+                       ? bch2_opt_get_by_id(&fs_opts, opt_id)
+                       : bch2_opt_get_by_id(&bch2_opts_default, opt_id);
+
+               opt->set_sb(sb.sb, v);
+       }
+
+       SET_BCH_SB_ENCODED_EXTENT_MAX_BITS(sb.sb,
+                               ilog2(opts.encoded_extent_max));
 
        struct timespec now;
        if (clock_gettime(CLOCK_REALTIME, &now))
@@ -260,11 +275,11 @@ struct bch_sb *bch2_format(struct format_opts opts,
        }
 
        SET_BCH_SB_FOREGROUND_TARGET(sb.sb,
-               parse_target(&sb, devs, nr_devs, opts.foreground_target));
+               parse_target(&sb, devs, nr_devs, fs_opt_strs.foreground_target));
        SET_BCH_SB_BACKGROUND_TARGET(sb.sb,
-               parse_target(&sb, devs, nr_devs, opts.background_target));
+               parse_target(&sb, devs, nr_devs, fs_opt_strs.background_target));
        SET_BCH_SB_PROMOTE_TARGET(sb.sb,
-               parse_target(&sb, devs, nr_devs, opts.promote_target));
+               parse_target(&sb, devs, nr_devs, fs_opt_strs.promote_target));
 
        /* Crypt: */
        if (opts.encrypted) {
@@ -278,7 +293,7 @@ struct bch_sb *bch2_format(struct format_opts opts,
        for (i = devs; i < devs + nr_devs; i++) {
                sb.sb->dev_idx = i - devs;
 
-               init_layout(&sb.sb->layout, opts.block_size,
+               init_layout(&sb.sb->layout, fs_opts.block_size,
                            i->sb_offset, i->sb_end);
 
                if (i->sb_offset == BCH_SB_SECTOR) {
@@ -931,3 +946,151 @@ int bchu_data(struct bchfs_handle fs, struct bch_ioctl_data cmd)
        close(progress_fd);
        return 0;
 }
+
+/* option parsing */
+
+struct bch_opt_strs bch2_cmdline_opts_get(int *argc, char *argv[],
+                                         unsigned opt_types)
+{
+       struct bch_opt_strs opts;
+       unsigned i = 1;
+
+       memset(&opts, 0, sizeof(opts));
+
+       while (i < *argc) {
+               char *optstr = strcmp_prefix(argv[i], "--");
+               char *valstr = NULL, *p;
+               int optid, nr_args = 1;
+
+               if (!optstr) {
+                       i++;
+                       continue;
+               }
+
+               optstr = strdup(optstr);
+
+               p = optstr;
+               while (isalpha(*p) || *p == '_')
+                       p++;
+
+               if (*p == '=') {
+                       *p = '\0';
+                       valstr = p + 1;
+               }
+
+               optid = bch2_opt_lookup(optstr);
+               if (optid < 0 ||
+                   !(bch2_opt_table[optid].mode & opt_types)) {
+                       free(optstr);
+                       i++;
+                       continue;
+               }
+
+               if (!valstr &&
+                   bch2_opt_table[optid].type != BCH_OPT_BOOL) {
+                       nr_args = 2;
+                       valstr = argv[i + 1];
+               }
+
+               if (!valstr)
+                       valstr = "1";
+
+               opts.by_id[optid] = valstr;
+
+               *argc -= nr_args;
+               memmove(&argv[i],
+                       &argv[i + nr_args],
+                       sizeof(char *) * (*argc - i));
+               argv[*argc] = NULL;
+       }
+
+       return opts;
+}
+
+struct bch_opts bch2_parse_opts(struct bch_opt_strs strs)
+{
+       struct bch_opts opts = bch2_opts_empty();
+       unsigned i;
+       int ret;
+       u64 v;
+
+       for (i = 0; i < bch2_opts_nr; i++) {
+               if (!strs.by_id[i] ||
+                   bch2_opt_table[i].type == BCH_OPT_FN)
+                       continue;
+
+               ret = bch2_opt_parse(NULL, &bch2_opt_table[i],
+                                    strs.by_id[i], &v);
+               if (ret < 0)
+                       die("Invalid %s: %s", strs.by_id[i], strerror(-ret));
+
+               bch2_opt_set_by_id(&opts, i, v);
+       }
+
+       return opts;
+}
+
+void bch2_opts_usage(unsigned opt_types)
+{
+       const struct bch_option *opt;
+       unsigned i, c = 0, helpcol = 30;
+
+       void tabalign() {
+               while (c < helpcol) {
+                       putchar(' ');
+                       c++;
+               }
+       }
+
+       void newline() {
+               printf("\n");
+               c = 0;
+       }
+
+       for (opt = bch2_opt_table;
+            opt < bch2_opt_table + bch2_opts_nr;
+            opt++) {
+               if (!(opt->mode & opt_types))
+                       continue;
+
+               c += printf("      --%s", opt->attr.name);
+
+               switch (opt->type) {
+               case BCH_OPT_BOOL:
+                       break;
+               case BCH_OPT_STR:
+                       c += printf("=(");
+                       for (i = 0; opt->choices[i]; i++) {
+                               if (i)
+                                       c += printf("|");
+                               c += printf("%s", opt->choices[i]);
+                       }
+                       c += printf(")");
+                       break;
+               default:
+                       c += printf("=%s", opt->hint);
+                       break;
+               }
+
+               if (opt->help) {
+                       const char *l = opt->help;
+
+                       if (c >= helpcol)
+                               newline();
+
+                       while (1) {
+                               const char *n = strchrnul(l, '\n');
+
+                               tabalign();
+                               printf("%.*s", (int) (n - l), l);
+                               newline();
+
+                               if (!*n)
+                                       break;
+                               l = n + 1;
+                       }
+               } else {
+                       newline();
+               }
+       }
+}
index 7f914d226a04e6222a5d05b30466e2206f6cb2eb..b8da35d16c1125ce96d2626845a031cede396f44 100644 (file)
@@ -6,34 +6,33 @@
 
 #include "libbcachefs/bcachefs_format.h"
 #include "libbcachefs/bcachefs_ioctl.h"
-#include "tools-util.h"
+#include "libbcachefs/opts.h"
 #include "libbcachefs/vstructs.h"
+#include "tools-util.h"
+
+/* option parsing */
+
+struct bch_opt_strs {
+union {
+       char                    *by_id[bch2_opts_nr];
+};
+struct {
+#define x(_name, ...)  char    *_name;
+       BCH_OPTS()
+#undef x
+};
+};
+
+struct bch_opt_strs bch2_cmdline_opts_get(int *, char *[], unsigned);
+struct bch_opts bch2_parse_opts(struct bch_opt_strs);
+void bch2_opts_usage(unsigned);
 
 struct format_opts {
        char            *label;
        uuid_le         uuid;
 
-       unsigned        on_error_action;
-
-       unsigned        block_size;
-       unsigned        btree_node_size;
        unsigned        encoded_extent_max;
 
-       unsigned        meta_replicas;
-       unsigned        data_replicas;
-
-       unsigned        meta_replicas_required;
-       unsigned        data_replicas_required;
-
-       const char      *foreground_target;
-       const char      *background_target;
-       const char      *promote_target;
-
-       unsigned        meta_csum_type;
-       unsigned        data_csum_type;
-       unsigned        compression_type;
-       unsigned        background_compression_type;
-
        bool            encrypted;
        char            *passphrase;
 };
@@ -41,14 +40,7 @@ struct format_opts {
 static inline struct format_opts format_opts_default()
 {
        return (struct format_opts) {
-               .on_error_action        = BCH_ON_ERROR_RO,
                .encoded_extent_max     = 128,
-               .meta_csum_type         = BCH_CSUM_OPT_CRC32C,
-               .data_csum_type         = BCH_CSUM_OPT_CRC32C,
-               .meta_replicas          = 1,
-               .data_replicas          = 1,
-               .meta_replicas_required = 1,
-               .data_replicas_required = 1,
        };
 }
 
@@ -76,8 +68,10 @@ static inline struct dev_opts dev_opts_default()
        };
 }
 
-void bch2_pick_bucket_size(struct format_opts, struct dev_opts *);
-struct bch_sb *bch2_format(struct format_opts, struct dev_opts *, size_t);
+void bch2_pick_bucket_size(struct bch_opts, struct dev_opts *);
+struct bch_sb *bch2_format(struct bch_opt_strs,
+                          struct bch_opts,
+                          struct format_opts, struct dev_opts *, size_t);
 
 void bch2_super_write(int, struct bch_sb *);
 struct bch_sb *__bch2_super_read(int, u64);
index b107cc43e17dfcbee2877a37c555a0c32cb9154a..486bbacf2a92cf0292d5eb6a84f5f43a069122bb 100644 (file)
@@ -386,7 +386,7 @@ struct fiemap_extent fiemap_iter_next(struct fiemap_iter *iter)
        return e;
 }
 
-const char *strcmp_prefix(const char *a, const char *a_prefix)
+char *strcmp_prefix(char *a, const char *a_prefix)
 {
        while (*a_prefix && *a == *a_prefix) {
                a++;
index 57f61e50cd2ecbdb9e6b400e810a3af93c6661d1..ae63f723621d899e57e2963471cd4bc90cd46a41 100644 (file)
@@ -145,7 +145,7 @@ struct fiemap_extent fiemap_iter_next(struct fiemap_iter *);
        for (fiemap_iter_init(&iter, fd);                               \
             (extent = fiemap_iter_next(&iter)).fe_length;)
 
-const char *strcmp_prefix(const char *, const char *);
+char *strcmp_prefix(char *, const char *);
 
 unsigned hatoi_validate(const char *, const char *);