X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=cmd_format.c;h=673c63a70b452f1a3e00f6fac97e9ae55a4db8a0;hb=4a81dc2fa3513a6ac6b2145985415dfb833a48eb;hp=f222a8b795974a84c140c552ddd8b72f684e4205;hpb=a17f7bcec7ed810a247c24e56229af8f43a9a6ae;p=bcachefs-tools-debian diff --git a/cmd_format.c b/cmd_format.c index f222a8b..673c63a 100644 --- a/cmd_format.c +++ b/cmd_format.c @@ -5,6 +5,7 @@ * * GPLv2 */ +#include #include #include #include @@ -17,164 +18,90 @@ #include #include -#include #include #include "ccan/darray/darray.h" #include "cmds.h" -#include "libbcache.h" +#include "libbcachefs.h" #include "crypto.h" -#include "opts.h" -#include "util.h" - -/* Open a block device, do magic blkid stuff: */ -static int open_for_format(const char *dev, bool force) -{ - blkid_probe pr; - const char *fs_type = NULL, *fs_label = NULL; - size_t fs_type_len, fs_label_len; - - int fd = xopen(dev, O_RDWR|O_EXCL); - - if (force) - return fd; - - if (!(pr = blkid_new_probe())) - die("blkid error 1"); - if (blkid_probe_set_device(pr, fd, 0, 0)) - die("blkid error 2"); - if (blkid_probe_enable_partitions(pr, true)) - die("blkid error 3"); - if (blkid_do_fullprobe(pr) < 0) - die("blkid error 4"); - - blkid_probe_lookup_value(pr, "TYPE", &fs_type, &fs_type_len); - blkid_probe_lookup_value(pr, "LABEL", &fs_label, &fs_label_len); - - if (fs_type) { - if (fs_label) - printf("%s contains a %s filesystem labelled '%s'\n", - dev, fs_type, fs_label); - else - printf("%s contains a %s filesystem\n", - dev, fs_type); - fputs("Proceed anyway?", stdout); - if (!ask_yn()) - exit(EXIT_FAILURE); - } - - blkid_free_probe(pr); - return fd; -} - -#define OPTS \ -t("bcache format - create a new bcache filesystem on one or more devices") \ -t("Usage: bcache format [OPTION]... ") \ -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, encrypted, NULL, "Enable whole filesystem encryption (chacha20/poly1305)")\ -x(0, no_passphrase, NULL, "Don't encrypt master encryption key")\ -x('e', error_action, "(continue|readonly|panic)", NULL) \ -x(0, max_journal_entry_size, "size", 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('t', tier, "#", "Higher tier indicates slower devices")\ -x(0, discard, NULL, NULL) \ -t("Device specific options must come before corresponding devices, e.g.") \ -t(" bcache format --tier 0 /dev/sdb --tier 1 /dev/sdc") \ -t("") \ -x('h', help, NULL, "display this help and exit") +#include "libbcachefs/opts.h" +#include "libbcachefs/super-io.h" +#include "libbcachefs/util.h" + +#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("bcache format - create a new bcache filesystem on one or more devices\n" - "Usage: bcache format [OPTION]... \n" + puts("bcachefs format - create a new bcachefs filesystem on one or more devices\n" + "Usage: bcachefs format [OPTION]... \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)\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" - " --error_action=(continue|readonly|panic)\n" - " Action to take on filesystem error\n" - " --max_journal_entry_size=size\n" - " -l, --label=label\n" - " --uuid=uuid\n" - " -f, --force\n" + " -L, --label=label\n" + " -U, --uuid=uuid\n" "\n" - "Device specific options:\n" - " --fs_size=size Size of filesystem on device\n" - " --bucket=size bucket size\n" - " --discard Enable discards\n" - " -t, --tier=# tier of subsequent devices\n" + "Device specific options:"); + + bch2_opts_usage(OPT_DEVICE); + + puts(" -g, --group=label Disk group\n" "\n" - " -h, --help display this help and exit\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" - " bcache format --tier 0 /dev/sdb --tier 1 /dev/sdc\n" + " bcachefs format --group cache /dev/sdb /dev/sdc\n" "\n" "Report bugs to "); } enum { - Opt_no_opt = 1, -#define t(text) -#define x(shortopt, longopt, arg, help) Opt_##longopt, + O_no_opt = 1, +#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 = Opt_##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 -static unsigned hatoi_validate(const char *s, const char *msg) +u64 read_flag_list_or_die(char *opt, const char * const list[], + const char *msg) { - u64 v; - - if (bch_strtoull_h(s, &v)) - die("bad %s %s", msg, s); - - if (v & (v - 1)) - die("%s must be a power of two", msg); - - v /= 512; - - if (v > USHRT_MAX) - die("%s too large\n", msg); - - if (!v) - die("%s too small\n", msg); + u64 v = bch2_read_flag_list(opt, list); + if (v == (u64) -1) + die("Bad %s %s", msg, opt); return v; } @@ -182,131 +109,117 @@ static unsigned hatoi_validate(const char *s, const char *msg) int cmd_format(int argc, char *argv[]) { darray(struct dev_opts) devices; - struct format_opts opts = format_opts_default(); - struct dev_opts dev_opts = { 0 }, *dev; - bool force = false, no_passphrase = false; + darray(char *) device_paths; + 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); + darray_init(device_paths); + + 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:L:U:ft:h", + "-L:U:g:fqh", format_opts, NULL)) != -1) switch (opt) { - case Opt_block_size: - case 'b': - opts.block_size = - hatoi_validate(optarg, "block size"); + case O_replicas: + if (kstrtouint(optarg, 10, &v) || + !v || + v > BCH_REPLICAS_MAX) + die("invalid replicas"); + + opt_set(fs_opts, metadata_replicas, v); + opt_set(fs_opts, data_replicas, v); break; - case Opt_btree_node_size: - opts.btree_node_size = - hatoi_validate(optarg, "btree node size"); - break; - case Opt_metadata_checksum_type: - opts.meta_csum_type = - read_string_list_or_die(optarg, - bch_csum_types, "checksum type"); - break; - case Opt_data_checksum_type: - opts.data_csum_type = - read_string_list_or_die(optarg, - bch_csum_types, "checksum type"); - break; - case Opt_compression_type: - opts.compression_type = - read_string_list_or_die(optarg, - bch_compression_types, - "compression type"); - break; - case Opt_encrypted: + case O_encrypted: opts.encrypted = true; break; - case Opt_no_passphrase: + case O_no_passphrase: no_passphrase = true; break; - case Opt_error_action: - case 'e': - opts.on_error_action = - read_string_list_or_die(optarg, - bch_error_actions, "error action"); - break; - case Opt_max_journal_entry_size: - opts.max_journal_entry_size = - hatoi_validate(optarg, "journal entry size"); - break; - case Opt_label: + case O_label: case 'L': - opts.label = strdup(optarg); + opts.label = optarg; break; - case Opt_uuid: + case O_uuid: case 'U': if (uuid_parse(optarg, opts.uuid.b)) die("Bad uuid"); break; - case Opt_force: + case O_force: case 'f': force = true; break; - case Opt_fs_size: - if (bch_strtoull_h(optarg, &dev_opts.size)) + case O_fs_size: + if (bch2_strtoull_h(optarg, &dev_opts.size)) die("invalid filesystem size"); dev_opts.size >>= 9; break; - case Opt_bucket_size: + case O_bucket_size: dev_opts.bucket_size = hatoi_validate(optarg, "bucket size"); break; - case Opt_tier: - case 't': - if (kstrtouint(optarg, 10, &dev_opts.tier) || - dev_opts.tier >= BCH_TIER_MAX) - die("invalid tier"); + case O_group: + case 'g': + dev_opts.group = optarg; break; - case Opt_discard: + case O_discard: dev_opts.discard = true; break; - case Opt_no_opt: - dev_opts.path = strdup(optarg); + case O_data_allowed: + dev_opts.data_allowed = + read_flag_list_or_die(optarg, + bch2_data_types, "data type"); + break; + case O_durability: + if (kstrtouint(optarg, 10, &dev_opts.durability) || + dev_opts.durability > BCH_REPLICAS_MAX) + die("invalid durability"); + break; + case O_no_opt: + darray_append(device_paths, optarg); + dev_opts.path = optarg; darray_append(devices, dev_opts); dev_opts.size = 0; break; - case Opt_help: + case O_quiet: + case 'q': + quiet = true; + break; + case O_help: case 'h': usage(); exit(EXIT_SUCCESS); break; + case '?': + exit(EXIT_FAILURE); + break; } - if (!darray_size(devices)) + if (darray_empty(devices)) die("Please supply a device"); - if (opts.encrypted && !no_passphrase) { - opts.passphrase = read_passphrase("Enter passphrase: "); - - if (isatty(STDIN_FILENO)) { - char *pass2 = - read_passphrase("Enter same passphrase again: "); - - if (strcmp(opts.passphrase, pass2)) { - memzero_explicit(opts.passphrase, - strlen(opts.passphrase)); - memzero_explicit(pass2, strlen(pass2)); - die("Passphrases do not match"); - } - - memzero_explicit(pass2, strlen(pass2)); - free(pass2); - } - } + if (opts.encrypted && !no_passphrase) + opts.passphrase = read_passphrase_twice("Enter passphrase: "); darray_foreach(dev, devices) dev->fd = open_for_format(dev->path, force); struct bch_sb *sb = - bcache_format(opts, devices.item, darray_size(devices)); - bcache_super_print(sb, HUMAN_READABLE); + 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); free(sb); if (opts.passphrase) { @@ -314,5 +227,87 @@ int cmd_format(int argc, char *argv[]) free(opts.passphrase); } + darray_free(devices); + + if (!opts.passphrase) { + /* + * Start the filesystem once, to allocate the journal and create + * the root directory: + */ + struct bch_fs *c = bch2_fs_open(device_paths.item, + darray_size(device_paths), + bch2_opts_empty()); + if (IS_ERR(c)) + die("error opening %s: %s", device_paths.item, + strerror(-PTR_ERR(c))); + + bch2_fs_stop(c); + } + + darray_free(device_paths); + + return 0; +} + +static void show_super_usage(void) +{ + puts("bcachefs show-super \n" + "Usage: bcachefs show-super [OPTION].. device\n" + "\n" + "Options:\n" + " -f, --fields=(fields) list of sections to print\n" + " -l, --layout print superblock layout\n" + " -h, --help display this help and exit\n" + "Report bugs to "); + exit(EXIT_SUCCESS); +} + +int cmd_show_super(int argc, char *argv[]) +{ + static const struct option longopts[] = { + { "fields", 1, NULL, 'f' }, + { "layout", 0, NULL, 'l' }, + { "help", 0, NULL, 'h' }, + { NULL } + }; + unsigned fields = 1 << BCH_SB_FIELD_members; + bool print_layout = false; + int opt; + + while ((opt = getopt_long(argc, argv, "f:lh", longopts, NULL)) != -1) + switch (opt) { + case 'f': + fields = !strcmp(optarg, "all") + ? ~0 + : read_flag_list_or_die(optarg, + bch2_sb_fields, "superblock field"); + break; + case 'l': + print_layout = true; + break; + case 'h': + show_super_usage(); + break; + } + args_shift(optind); + + char *dev = arg_pop(); + if (!dev) + die("please supply a device"); + if (argc) + die("too many arguments"); + + struct bch_opts opts = bch2_opts_empty(); + + opt_set(opts, noexcl, true); + opt_set(opts, nochanges, true); + + struct bch_sb_handle sb; + int ret = bch2_read_super(dev, &opts, &sb); + if (ret) + die("Error opening %s: %s", dev, strerror(-ret)); + + bch2_sb_print(sb.sb, print_layout, fields, HUMAN_READABLE); + bch2_free_super(&sb); return 0; }