return BCH_MIN_NR_NBUCKETS * bucket_size;
}
-static void init_layout(struct bch_sb_layout *l, unsigned block_size,
- u64 start, u64 end)
+static void init_layout(struct bch_sb_layout *l,
+ unsigned block_size,
+ unsigned sb_size,
+ u64 sb_start, u64 sb_end)
{
- unsigned sb_size;
- u64 backup; /* offset of 2nd sb */
+ unsigned i;
memset(l, 0, sizeof(*l));
- if (start != BCH_SB_SECTOR)
- start = round_up(start, block_size);
- end = round_down(end, block_size);
-
- if (start >= end)
- die("insufficient space for superblocks");
-
- /*
- * Create two superblocks in the allowed range: reserve a maximum of 64k
- */
- sb_size = min_t(u64, 128, end - start / 2);
-
- backup = start + sb_size;
- backup = round_up(backup, block_size);
-
- backup = min(backup, end);
-
- sb_size = min(end - backup, backup- start);
- sb_size = rounddown_pow_of_two(sb_size);
-
- if (sb_size < 8)
- die("insufficient space for superblocks");
-
l->magic = BCACHE_MAGIC;
l->layout_type = 0;
l->nr_superblocks = 2;
l->sb_max_size_bits = ilog2(sb_size);
- l->sb_offset[0] = cpu_to_le64(start);
- l->sb_offset[1] = cpu_to_le64(backup);
+
+ /* Create two superblocks in the allowed range: */
+ for (i = 0; i < l->nr_superblocks; i++) {
+ if (sb_start != BCH_SB_SECTOR)
+ sb_start = round_up(sb_start, block_size);
+
+ l->sb_offset[i] = cpu_to_le64(sb_start);
+ sb_start += sb_size;
+ }
+
+ if (sb_start >= sb_end)
+ die("insufficient space for superblocks");
}
void bch2_pick_bucket_size(struct bch_opts opts, struct dev_opts *dev)
{
- if (!dev->sb_offset) {
- dev->sb_offset = BCH_SB_SECTOR;
- dev->sb_end = BCH_SB_SECTOR + 256;
- }
-
if (!dev->size)
dev->size = get_size(dev->path, dev->fd) >> 9;
for (i = devs; i < devs + nr_devs; i++) {
sb.sb->dev_idx = i - devs;
+ if (!i->sb_offset) {
+ i->sb_offset = BCH_SB_SECTOR;
+ i->sb_end = i->size;
+ }
+
init_layout(&sb.sb->layout, fs_opts.block_size,
+ opts.superblock_size,
i->sb_offset, i->sb_end);
+ /*
+ * Also create a backup superblock at the end of the disk:
+ *
+ * If we're not creating a superblock at the default offset, it
+ * means we're being run from the migrate tool and we could be
+ * overwriting existing data if we write to the end of the disk:
+ */
+ if (i->sb_offset == BCH_SB_SECTOR) {
+ struct bch_sb_layout *l = &sb.sb->layout;
+ u64 backup_sb = i->size - (1 << l->sb_max_size_bits);
+
+ backup_sb = rounddown(backup_sb, i->bucket_size);
+ l->sb_offset[l->nr_superblocks++] = cpu_to_le64(backup_sb);
+ }
+
if (i->sb_offset == BCH_SB_SECTOR) {
/* Zero start of disk */
static const char zeroes[BCH_SB_SECTOR << 9];
struct bch_sb_field_members *mi;
char user_uuid_str[40], internal_uuid_str[40];
char features_str[500];
+ char compat_features_str[500];
char fields_have_str[200];
char label[BCH_SB_LABEL_SIZE + 1];
char time_str[64];
bch2_sb_features,
le64_to_cpu(sb->features[0]));
+ bch2_flags_to_text(&PBUF(compat_features_str),
+ bch2_sb_compat,
+ le64_to_cpu(sb->compat[0]));
+
vstruct_for_each(sb, f)
fields_have |= 1 << le32_to_cpu(f->type);
bch2_flags_to_text(&PBUF(fields_have_str),
"Error action: %s\n"
"Clean: %llu\n"
"Features: %s\n"
+ "Compat features: %s\n"
"Metadata replicas: %llu\n"
"Data replicas: %llu\n"
BCH_SB_CLEAN(sb),
features_str,
+ compat_features_str,
BCH_SB_META_REPLICAS_WANT(sb),
BCH_SB_DATA_REPLICAS_WANT(sb),
* Given a path to a block device, open the filesystem it belongs to; also
* return the device's idx:
*/
-struct bchfs_handle bchu_fs_open_by_dev(const char *path, unsigned *idx)
+struct bchfs_handle bchu_fs_open_by_dev(const char *path, int *idx)
{
char buf[1024], *uuid_str;
return bcache_fs_open(uuid_str);
}
+int bchu_dev_path_to_idx(struct bchfs_handle fs, const char *dev_path)
+{
+ int idx;
+ struct bchfs_handle fs2 = bchu_fs_open_by_dev(dev_path, &idx);
+
+ if (memcmp(&fs.uuid, &fs2.uuid, sizeof(fs.uuid)))
+ idx = -1;
+ bcache_fs_close(fs2);
+ return idx;
+}
+
int bchu_data(struct bchfs_handle fs, struct bch_ioctl_data cmd)
{
int progress_fd = xioctl(fs.ioctl_fd, BCH_IOCTL_DATA, &cmd);
/* option parsing */
+void bch2_opt_strs_free(struct bch_opt_strs *opts)
+{
+ unsigned i;
+
+ for (i = 0; i < bch2_opts_nr; i++) {
+ free(opts->by_id[i]);
+ opts->by_id[i] = NULL;
+ }
+}
+
struct bch_opt_strs bch2_cmdline_opts_get(int *argc, char *argv[],
unsigned opt_types)
{
optid = bch2_opt_lookup(optstr);
if (optid < 0 ||
!(bch2_opt_table[optid].mode & opt_types)) {
- free(optstr);
i++;
- continue;
+ goto next;
}
if (!valstr &&
if (!valstr)
valstr = "1";
- opts.by_id[optid] = valstr;
+ opts.by_id[optid] = strdup(valstr);
*argc -= nr_args;
memmove(&argv[i],
&argv[i + nr_args],
sizeof(char *) * (*argc - i));
argv[*argc] = NULL;
+next:
+ free(optstr);
}
return opts;
return opts;
}
+#define newline(c) \
+ do { \
+ printf("\n"); \
+ c = 0; \
+ } while(0)
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;
const char *l = opt->help;
if (c >= helpcol)
- newline();
+ newline(c);
while (1) {
const char *n = strchrnul(l, '\n');
- tabalign();
+ while (c < helpcol) {
+ putchar(' ');
+ c++;
+ }
printf("%.*s", (int) (n - l), l);
- newline();
+ newline(c);
if (!*n)
break;
l = n + 1;
}
} else {
- newline();
+ newline(c);
}
}
}