static void init_layout(struct bch_sb_layout *l,
unsigned block_size,
unsigned sb_size,
- u64 start, u64 end)
+ u64 sb_start, u64 sb_end)
{
unsigned i;
/* Create two superblocks in the allowed range: */
for (i = 0; i < l->nr_superblocks; i++) {
- if (start != BCH_SB_SECTOR)
- start = round_up(start, block_size);
+ if (sb_start != BCH_SB_SECTOR)
+ sb_start = round_up(sb_start, block_size);
- l->sb_offset[i] = cpu_to_le64(start);
- start += sb_size;
+ l->sb_offset[i] = cpu_to_le64(sb_start);
+ sb_start += sb_size;
}
- if (start >= end)
+ if (sb_start >= sb_end)
die("insufficient space for superblocks");
}
/* Member info: */
mi = bch2_sb_resize_members(&sb,
(sizeof(*mi) + sizeof(struct bch_member) *
- nr_devs) / sizeof(u64));
+ nr_devs) / sizeof(u64));
for (i = devs; i < devs + nr_devs; i++) {
struct bch_member *m = mi->members + (i - devs);
SET_BCH_MEMBER_DURABILITY(m, i->durability + 1);
}
- /* Disk groups */
+ /* Disk labels*/
for (i = devs; i < devs + nr_devs; i++) {
struct bch_member *m = mi->members + (i - devs);
int idx;
- if (!i->group)
+ if (!i->label)
continue;
- idx = bch2_disk_path_find_or_create(&sb, i->group);
+ idx = bch2_disk_path_find_or_create(&sb, i->label);
if (idx < 0)
die("error creating disk path: %s", idx);
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_disk_group *g = gi->entries + t.group;
if (t.group < disk_groups_nr(gi) && !BCH_GROUP_DELETED(g)) {
- ret = scnprintf(buf, len, "Group %u (%.*s)", t.group,
+ ret = scnprintf(buf, len, "Label %u (%.*s)", t.group,
BCH_SB_LABEL_SIZE, g->label);
} else {
- ret = scnprintf(buf, len, "Bad group %u", t.group);
+ ret = scnprintf(buf, len, "Bad label %u", t.group);
}
break;
}
char member_uuid_str[40];
char data_allowed_str[100];
char data_has_str[100];
- char group[BCH_SB_LABEL_SIZE+10];
+ char label [BCH_SB_LABEL_SIZE+10];
char time_str[64];
if (!bch2_member_exists(m))
unsigned idx = BCH_MEMBER_GROUP(m) - 1;
if (idx < disk_groups_nr(gi)) {
- snprintf(group, sizeof(group), "%.*s (%u)",
+ scnprintf(label, sizeof(label), "%.*s (%u)",
BCH_SB_LABEL_SIZE,
gi->entries[idx].label, idx);
} else {
- strcpy(group, "(bad disk groups section)");
+ strcpy(label, "(bad disk labels section)");
}
} else {
- strcpy(group, "(none)");
+ strcpy(label, "(none)");
}
bch2_flags_to_text(&PBUF(data_allowed_str),
? bch2_member_states[BCH_MEMBER_STATE(m)]
: "unknown",
- group,
+ label,
data_allowed_str,
data_has_str,
}
static void bch2_sb_print_replicas_v0(struct bch_sb *sb, struct bch_sb_field *f,
- enum units units)
+ enum units units)
{
struct bch_sb_field_replicas_v0 *replicas = field_to_type(f, replicas_v0);
struct bch_replicas_entry_v0 *e;
}
static void bch2_sb_print_journal_seq_blacklist(struct bch_sb *sb, struct bch_sb_field *f,
- enum units units)
+ enum units units)
{
struct bch_sb_field_journal_seq_blacklist *bl = field_to_type(f, journal_seq_blacklist);
unsigned i, nr = blacklist_nr_entries(bl);
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),
free(ctl);
} else {
/* It's a path: */
- ret.ioctl_fd = xopen(path, O_RDONLY);
+ ret.ioctl_fd = open(path, O_RDONLY);
+ if (ret.ioctl_fd < 0)
+ die("Error opening filesystem at %s: %m", path);
struct bch_ioctl_query_uuid uuid;
if (ioctl(ret.ioctl_fd, BCH_IOCTL_QUERY_UUID, &uuid) < 0)
* 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);
}
}
}