+ pr_indent_pop(out, 2);
+ }
+}
+
+void bch2_sb_layout_to_text(struct printbuf *out, struct bch_sb_layout *l)
+{
+ unsigned i;
+
+ pr_buf(out, "Type: %u", l->layout_type);
+ pr_newline(out);
+
+ pr_buf(out, "Superblock max size: ");
+ pr_units(out,
+ 1 << l->sb_max_size_bits,
+ 512 << l->sb_max_size_bits);
+ pr_newline(out);
+
+ pr_buf(out, "Nr superblocks: %u", l->nr_superblocks);
+ pr_newline(out);
+
+ pr_buf(out, "Offsets: ");
+ for (i = 0; i < l->nr_superblocks; i++) {
+ if (i)
+ pr_buf(out, ", ");
+ pr_buf(out, "%llu", le64_to_cpu(l->sb_offset[i]));
+ }
+ pr_newline(out);
+}
+
+void bch2_sb_to_text(struct printbuf *out, struct bch_sb *sb,
+ bool print_layout, unsigned fields)
+{
+ struct bch_sb_field_members *mi;
+ struct bch_sb_field *f;
+ u64 fields_have = 0;
+ unsigned nr_devices = 0;
+
+ if (!out->tabstops[0])
+ out->tabstops[0] = 32;
+
+ mi = bch2_sb_get_members(sb);
+ if (mi) {
+ struct bch_member *m;
+
+ for (m = mi->members;
+ m < mi->members + sb->nr_devices;
+ m++)
+ nr_devices += bch2_member_exists(m);
+ }
+
+ pr_buf(out, "External UUID:");
+ pr_tab(out);
+ pr_uuid(out, sb->user_uuid.b);
+ pr_newline(out);
+
+ pr_buf(out, "Internal UUID:");
+ pr_tab(out);
+ pr_uuid(out, sb->uuid.b);
+ pr_newline(out);
+
+ pr_buf(out, "Device index:");
+ pr_tab(out);
+ pr_buf(out, "%u", sb->dev_idx);
+ pr_newline(out);
+
+ pr_buf(out, "Label:");
+ pr_tab(out);
+ pr_buf(out, "%.*s", (int) sizeof(sb->label), sb->label);
+ pr_newline(out);
+
+ pr_buf(out, "Version:");
+ pr_tab(out);
+ pr_buf(out, "%s", bch2_metadata_versions[le16_to_cpu(sb->version)]);
+ pr_newline(out);
+
+ pr_buf(out, "Oldest version on disk:");
+ pr_tab(out);
+ pr_buf(out, "%s", bch2_metadata_versions[le16_to_cpu(sb->version_min)]);
+ pr_newline(out);
+
+ pr_buf(out, "Created:");
+ pr_tab(out);
+ if (sb->time_base_lo)
+ pr_time(out, div_u64(le64_to_cpu(sb->time_base_lo), NSEC_PER_SEC));
+ else
+ pr_buf(out, "(not set)");
+ pr_newline(out);
+
+ pr_buf(out, "Sequence number:");
+ pr_tab(out);
+ pr_buf(out, "%llu", le64_to_cpu(sb->seq));
+ pr_newline(out);
+
+ pr_buf(out, "Superblock size:");
+ pr_tab(out);
+ pr_buf(out, "%zu", vstruct_bytes(sb));
+ pr_newline(out);
+
+ pr_buf(out, "Clean:");
+ pr_tab(out);
+ pr_buf(out, "%llu", BCH_SB_CLEAN(sb));
+ pr_newline(out);
+
+ pr_buf(out, "Devices:");
+ pr_tab(out);
+ pr_buf(out, "%u", nr_devices);
+ pr_newline(out);
+
+ pr_buf(out, "Sections:");
+ vstruct_for_each(sb, f)
+ fields_have |= 1 << le32_to_cpu(f->type);
+ pr_tab(out);
+ bch2_flags_to_text(out, bch2_sb_fields, fields_have);
+ pr_newline(out);
+
+ pr_buf(out, "Features:");
+ pr_tab(out);
+ bch2_flags_to_text(out, bch2_sb_features,
+ le64_to_cpu(sb->features[0]));
+ pr_newline(out);
+
+ pr_buf(out, "Compat features:");
+ pr_tab(out);
+ bch2_flags_to_text(out, bch2_sb_compat,
+ le64_to_cpu(sb->compat[0]));
+ pr_newline(out);
+
+ pr_newline(out);
+ pr_buf(out, "Options:");
+ pr_newline(out);
+ pr_indent_push(out, 2);
+ {
+ enum bch_opt_id id;
+
+ for (id = 0; id < bch2_opts_nr; id++) {
+ const struct bch_option *opt = bch2_opt_table + id;
+
+ if (opt->get_sb != BCH2_NO_SB_OPT) {
+ u64 v = bch2_opt_from_sb(sb, id);
+
+ pr_buf(out, "%s:", opt->attr.name);
+ pr_tab(out);
+ bch2_opt_to_text(out, NULL, sb, opt, v,
+ OPT_HUMAN_READABLE|OPT_SHOW_FULL_LIST);
+ pr_newline(out);
+ }
+ }
+ }
+
+ pr_indent_pop(out, 2);
+
+ if (print_layout) {
+ pr_newline(out);
+ pr_buf(out, "layout:");
+ pr_newline(out);
+ pr_indent_push(out, 2);
+ bch2_sb_layout_to_text(out, &sb->layout);
+ pr_indent_pop(out, 2);
+ }
+
+ vstruct_for_each(sb, f)
+ if (fields & (1 << le32_to_cpu(f->type))) {
+ pr_newline(out);
+ bch2_sb_field_to_text(out, sb, f);
+ }