summaryrefslogtreecommitdiff
path: root/c_src/libbcachefs.c
diff options
context:
space:
mode:
Diffstat (limited to 'c_src/libbcachefs.c')
-rw-r--r--c_src/libbcachefs.c165
1 files changed, 106 insertions, 59 deletions
diff --git a/c_src/libbcachefs.c b/c_src/libbcachefs.c
index c3af991b..d212b6ef 100644
--- a/c_src/libbcachefs.c
+++ b/c_src/libbcachefs.c
@@ -68,26 +68,23 @@ static u64 min_size(unsigned bucket_size)
u64 bch2_pick_bucket_size(struct bch_opts opts, struct dev_opts *dev)
{
- u64 bucket_size;
-
- if (dev->size < min_size(opts.block_size))
+ if (dev->opts.fs_size < min_size(opts.block_size))
die("cannot format %s, too small (%llu bytes, min %llu)",
- dev->path, dev->size, min_size(opts.block_size));
+ dev->path, dev->opts.fs_size, min_size(opts.block_size));
/* Bucket size must be >= block size: */
- bucket_size = opts.block_size;
+ u64 bucket_size = opts.block_size;
/* Bucket size must be >= btree node size: */
if (opt_defined(opts, btree_node_size))
- bucket_size = max_t(unsigned, bucket_size,
- opts.btree_node_size);
+ bucket_size = max_t(unsigned, bucket_size, opts.btree_node_size);
/* Want a bucket size of at least 128k, if possible: */
bucket_size = max(bucket_size, 128ULL << 10);
- if (dev->size >= min_size(bucket_size)) {
+ if (dev->opts.fs_size >= min_size(bucket_size)) {
unsigned scale = max(1,
- ilog2(dev->size / min_size(bucket_size)) / 4);
+ ilog2(dev->opts.fs_size / min_size(bucket_size)) / 4);
scale = rounddown_pow_of_two(scale);
@@ -96,7 +93,7 @@ u64 bch2_pick_bucket_size(struct bch_opts opts, struct dev_opts *dev)
} else {
do {
bucket_size /= 2;
- } while (dev->size < min_size(bucket_size));
+ } while (dev->opts.fs_size < min_size(bucket_size));
}
return bucket_size;
@@ -104,22 +101,18 @@ u64 bch2_pick_bucket_size(struct bch_opts opts, struct dev_opts *dev)
void bch2_check_bucket_size(struct bch_opts opts, struct dev_opts *dev)
{
- if (dev->bucket_size < opts.block_size)
- die("Bucket size (%llu) cannot be smaller than block size (%u)",
- dev->bucket_size, opts.block_size);
+ if (dev->opts.bucket_size < opts.block_size)
+ die("Bucket size (%u) cannot be smaller than block size (%u)",
+ dev->opts.bucket_size, opts.block_size);
if (opt_defined(opts, btree_node_size) &&
- dev->bucket_size < opts.btree_node_size)
- die("Bucket size (%llu) cannot be smaller than btree node size (%u)",
- dev->bucket_size, opts.btree_node_size);
+ dev->opts.bucket_size < opts.btree_node_size)
+ die("Bucket size (%u) cannot be smaller than btree node size (%u)",
+ dev->opts.bucket_size, opts.btree_node_size);
if (dev->nbuckets < BCH_MIN_NR_NBUCKETS)
- die("Not enough buckets: %llu, need %u (bucket size %llu)",
- dev->nbuckets, BCH_MIN_NR_NBUCKETS, dev->bucket_size);
-
- if (dev->bucket_size > (u32) U16_MAX << 9)
- die("Bucket size (%llu) too big (max %u)",
- dev->bucket_size, (u32) U16_MAX << 9);
+ die("Not enough buckets: %llu, need %u (bucket size %u)",
+ dev->nbuckets, BCH_MIN_NR_NBUCKETS, dev->opts.bucket_size);
}
static unsigned parse_target(struct bch_sb_handle *sb,
@@ -144,6 +137,17 @@ static unsigned parse_target(struct bch_sb_handle *sb,
return 0;
}
+static void bch2_opt_set_sb_all(struct bch_sb *sb, int dev_idx, struct bch_opts *opts)
+{
+ for (unsigned id = 0; id < bch2_opts_nr; id++) {
+ u64 v = bch2_opt_defined_by_id(opts, id)
+ ? bch2_opt_get_by_id(opts, id)
+ : bch2_opt_get_by_id(&bch2_opts_default, id);
+
+ __bch2_opt_set_sb(sb, dev_idx, &bch2_opt_table[id], v);
+ }
+}
+
struct bch_sb *bch2_format(struct bch_opt_strs fs_opt_strs,
struct bch_opts fs_opts,
struct format_opts opts,
@@ -153,47 +157,45 @@ struct bch_sb *bch2_format(struct bch_opt_strs fs_opt_strs,
struct bch_sb_handle sb = { NULL };
struct dev_opts *i;
unsigned max_dev_block_size = 0;
- unsigned opt_id;
u64 min_bucket_size = U64_MAX;
for (i = devs; i < devs + nr_devs; i++)
max_dev_block_size = max(max_dev_block_size, get_blocksize(i->bdev->bd_fd));
/* calculate block size: */
- if (!opt_defined(fs_opts, block_size)) {
+ 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)
+
+ 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);
/* get device size, if it wasn't specified: */
for (i = devs; i < devs + nr_devs; i++)
- if (!i->size)
- i->size = get_size(i->bdev->bd_fd);
+ if (!opt_defined(i->opts, fs_size))
+ opt_set(i->opts, fs_size, get_size(i->bdev->bd_fd));
/* calculate bucket sizes: */
for (i = devs; i < devs + nr_devs; i++)
min_bucket_size = min(min_bucket_size,
- i->bucket_size ?: bch2_pick_bucket_size(fs_opts, i));
+ i->opts.bucket_size ?: bch2_pick_bucket_size(fs_opts, i));
for (i = devs; i < devs + nr_devs; i++)
- if (!i->bucket_size)
- i->bucket_size = min_bucket_size;
+ if (!opt_defined(i->opts, bucket_size))
+ opt_set(i->opts, bucket_size, min_bucket_size);
for (i = devs; i < devs + nr_devs; i++) {
- i->nbuckets = i->size / i->bucket_size;
+ i->nbuckets = i->opts.fs_size / i->opts.bucket_size;
bch2_check_bucket_size(fs_opts, i);
}
/* calculate btree node size: */
if (!opt_defined(fs_opts, btree_node_size)) {
- /* 256k default btree node size */
- opt_set(fs_opts, btree_node_size, 256 << 10);
+ unsigned s = bch2_opts_default.btree_node_size;
for (i = devs; i < devs + nr_devs; i++)
- fs_opts.btree_node_size =
- min_t(unsigned, fs_opts.btree_node_size,
- i->bucket_size);
+ s = min(s, i->opts.bucket_size);
+ opt_set(fs_opts, btree_node_size, s);
}
if (uuid_is_null(opts.uuid.b))
@@ -219,17 +221,7 @@ struct bch_sb *bch2_format(struct bch_opt_strs fs_opt_strs,
opts.label,
min(strlen(opts.label), sizeof(sb.sb->label)));
- for (opt_id = 0;
- opt_id < bch2_opts_nr;
- opt_id++) {
- u64 v;
-
- 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);
-
- __bch2_opt_set_sb(sb.sb, -1, &bch2_opt_table[opt_id], v);
- }
+ bch2_opt_set_sb_all(sb.sb, -1, &fs_opts);
struct timespec now;
if (clock_gettime(CLOCK_REALTIME, &now))
@@ -245,16 +237,13 @@ struct bch_sb *bch2_format(struct bch_opt_strs fs_opt_strs,
nr_devs) / sizeof(u64));
mi->member_bytes = cpu_to_le16(sizeof(struct bch_member));
for (i = devs; i < devs + nr_devs; i++) {
- struct bch_member *m = bch2_members_v2_get_mut(sb.sb, (i - devs));
+ unsigned idx = i - devs;
+ struct bch_member *m = bch2_members_v2_get_mut(sb.sb, idx);
uuid_generate(m->uuid.b);
m->nbuckets = cpu_to_le64(i->nbuckets);
m->first_bucket = 0;
- m->bucket_size = cpu_to_le16(i->bucket_size >> 9);
-
- SET_BCH_MEMBER_DISCARD(m, i->discard);
- SET_BCH_MEMBER_DATA_ALLOWED(m, i->data_allowed);
- SET_BCH_MEMBER_DURABILITY(m, i->durability + 1);
+ bch2_opt_set_sb_all(sb.sb, idx, &i->opts);
}
/* Disk labels*/
@@ -298,7 +287,7 @@ struct bch_sb *bch2_format(struct bch_opt_strs fs_opt_strs,
bch2_sb_members_cpy_v2_v1(&sb);
for (i = devs; i < devs + nr_devs; i++) {
- u64 size_sectors = i->size >> 9;
+ u64 size_sectors = i->opts.fs_size >> 9;
sb.sb->dev_idx = i - devs;
@@ -322,7 +311,7 @@ struct bch_sb *bch2_format(struct bch_opt_strs fs_opt_strs,
struct bch_sb_layout *l = &sb.sb->layout;
u64 backup_sb = size_sectors - (1 << l->sb_max_size_bits);
- backup_sb = rounddown(backup_sb, i->bucket_size >> 9);
+ backup_sb = rounddown(backup_sb, i->opts.bucket_size >> 9);
l->sb_offset[l->nr_superblocks++] = cpu_to_le64(backup_sb);
}
@@ -619,6 +608,8 @@ int bchu_data(struct bchfs_handle fs, struct bch_ioctl_data cmd)
/* option parsing */
+#include <getopt.h>
+
void bch2_opt_strs_free(struct bch_opt_strs *opts)
{
unsigned i;
@@ -629,6 +620,64 @@ void bch2_opt_strs_free(struct bch_opt_strs *opts)
}
}
+static bool opt_type_filter(const struct bch_option *opt, unsigned opt_types)
+{
+ if (!(opt->flags & opt_types))
+ return false;
+
+ if ((opt_types & OPT_FORMAT) &&
+ !opt->set_sb && !opt->set_member)
+ return false;
+
+ return true;
+}
+
+const struct bch_option *bch2_cmdline_opt_parse(int argc, char *argv[],
+ unsigned opt_types)
+{
+ if (optind >= argc)
+ return NULL;
+
+ if (argv[optind][0] != '-' ||
+ argv[optind][1] != '-')
+ return NULL;
+
+ char *optstr = strdup(argv[optind] + 2);
+ optarg = argv[optind + 1];
+
+ char *eq = strchr(optstr, '=');
+ if (eq) {
+ *eq = '\0';
+ optarg = eq + 1;
+ }
+
+ if (!optarg)
+ optarg = "1";
+
+
+ int optid = bch2_opt_lookup(optstr);
+ if (optid < 0)
+ goto noopt;
+
+ const struct bch_option *opt = bch2_opt_table + optid;
+ if (!opt_type_filter(opt, opt_types))
+ goto noopt;
+
+ optind++;
+
+ if (opt->type != BCH_OPT_BOOL) {
+ if (optarg == argv[optind])
+ optind++;
+ } else {
+ optarg = NULL;
+ }
+
+ return opt;
+noopt:
+ free(optstr);
+ return NULL;
+}
+
struct bch_opt_strs bch2_cmdline_opts_get(int *argc, char *argv[],
unsigned opt_types)
{
@@ -716,19 +765,17 @@ struct bch_opts bch2_parse_opts(struct bch_opt_strs strs)
#define newline(c) \
do { \
printf("\n"); \
- c = 0; \
+ c = 0; \
} while(0)
void bch2_opts_usage(unsigned opt_types)
{
const struct bch_option *opt;
unsigned i, c = 0, helpcol = 30;
-
-
for (opt = bch2_opt_table;
opt < bch2_opt_table + bch2_opts_nr;
opt++) {
- if (!(opt->flags & opt_types))
+ if (!opt_type_filter(opt, opt_types))
continue;
c += printf(" --%s", opt->attr.name);