diff --git a/fs/bcachefs/disk_groups.c b/fs/bcachefs/disk_groups.c index e411606fd38d..e9ee37f1e07d 100644 --- a/fs/bcachefs/disk_groups.c +++ b/fs/bcachefs/disk_groups.c @@ -343,12 +343,10 @@ int bch2_disk_path_find_or_create(struct bch_sb_handle *sb, const char *name) return v; } -void bch2_disk_path_to_text(struct printbuf *out, - struct bch_sb_handle *sb, - unsigned v) +void bch2_disk_path_to_text(struct printbuf *out, struct bch_sb *sb, unsigned v) { struct bch_sb_field_disk_groups *groups = - bch2_sb_get_disk_groups(sb->sb); + bch2_sb_get_disk_groups(sb); struct bch_disk_group *g; unsigned nr = 0; u16 path[32]; @@ -383,7 +381,7 @@ void bch2_disk_path_to_text(struct printbuf *out, } return; inval: - pr_buf(out, "invalid group %u", v); + pr_buf(out, "invalid label %u", v); } int bch2_dev_group_set(struct bch_fs *c, struct bch_dev *ca, const char *name) @@ -447,6 +445,36 @@ int bch2_opt_target_parse(struct bch_fs *c, const char *buf, u64 *v) return -EINVAL; } +void bch2_sb_target_to_text(struct printbuf *out, struct bch_sb *sb, u64 v) +{ + struct target t = target_decode(v); + + switch (t.type) { + case TARGET_NULL: + pr_buf(out, "none"); + break; + case TARGET_DEV: { + struct bch_sb_field_members *mi = bch2_sb_get_members(sb); + struct bch_member *m = mi->members + t.dev; + + if (bch2_dev_exists(sb, mi, t.dev)) { + pr_buf(out, "Device "); + pr_uuid(out, m->uuid.b); + pr_buf(out, " (%u)", t.dev); + } else { + pr_buf(out, "Bad device %u", t.dev); + } + + break; + } + case TARGET_GROUP: + bch2_disk_path_to_text(out, sb, t.group); + break; + default: + BUG(); + } +} + void bch2_opt_target_to_text(struct printbuf *out, struct bch_fs *c, u64 v) { struct target t = target_decode(v); @@ -477,7 +505,7 @@ void bch2_opt_target_to_text(struct printbuf *out, struct bch_fs *c, u64 v) } case TARGET_GROUP: mutex_lock(&c->sb_lock); - bch2_disk_path_to_text(out, &c->disk_sb, t.group); + bch2_disk_path_to_text(out, c->disk_sb.sb, t.group); mutex_unlock(&c->sb_lock); break; default: diff --git a/fs/bcachefs/disk_groups.h b/fs/bcachefs/disk_groups.h index 3d84f23c34ed..a274aacbdf92 100644 --- a/fs/bcachefs/disk_groups.h +++ b/fs/bcachefs/disk_groups.h @@ -75,8 +75,9 @@ int bch2_disk_path_find(struct bch_sb_handle *, const char *); /* Exported for userspace bcachefs-tools: */ int bch2_disk_path_find_or_create(struct bch_sb_handle *, const char *); -void bch2_disk_path_to_text(struct printbuf *, struct bch_sb_handle *, - unsigned); +void bch2_disk_path_to_text(struct printbuf *, struct bch_sb *, unsigned); + +void bch2_sb_target_to_text(struct printbuf *, struct bch_sb *, u64); int bch2_opt_target_parse(struct bch_fs *, const char *, u64 *); void bch2_opt_target_to_text(struct printbuf *, struct bch_fs *, u64); diff --git a/fs/bcachefs/extents.c b/fs/bcachefs/extents.c index 3ed724e1fc98..c78e10e8ec2c 100644 --- a/fs/bcachefs/extents.c +++ b/fs/bcachefs/extents.c @@ -953,15 +953,19 @@ void bch2_bkey_ptrs_to_text(struct printbuf *out, struct bch_fs *c, switch (__extent_entry_type(entry)) { case BCH_EXTENT_ENTRY_ptr: ptr = entry_to_ptr(entry); - ca = ptr->dev < c->sb.nr_devices && c->devs[ptr->dev] - ? bch_dev_bkey_exists(c, ptr->dev) - : NULL; - pr_buf(out, "ptr: %u:%llu gen %u%s%s", ptr->dev, + pr_buf(out, "ptr: %u:%llu gen %u%s", ptr->dev, (u64) ptr->offset, ptr->gen, - ptr->cached ? " cached" : "", - ca && ptr_stale(ca, ptr) - ? " stale" : ""); + ptr->cached ? " cached" : ""); + + if (c) { + ca = ptr->dev < c->sb.nr_devices && c->devs[ptr->dev] + ? bch_dev_bkey_exists(c, ptr->dev) + : NULL; + + if (ca && ptr_stale(ca, ptr)) + pr_buf(out, " stale"); + } break; case BCH_EXTENT_ENTRY_crc32: case BCH_EXTENT_ENTRY_crc64: diff --git a/fs/bcachefs/journal_io.c b/fs/bcachefs/journal_io.c index 4f0904a515a7..491300e3c48f 100644 --- a/fs/bcachefs/journal_io.c +++ b/fs/bcachefs/journal_io.c @@ -302,7 +302,7 @@ static void journal_entry_btree_keys_to_text(struct printbuf *out, struct bch_fs vstruct_for_each(entry, k) { if (!first) { - printbuf_newline(out); + pr_newline(out); pr_buf(out, "%s: ", bch2_jset_entry_types[entry->type]); } pr_buf(out, "btree=%s l=%u ", bch2_btree_ids[entry->btree_id], entry->level); diff --git a/fs/bcachefs/journal_seq_blacklist.c b/fs/bcachefs/journal_seq_blacklist.c index 3cc63fc202ab..3140c8731431 100644 --- a/fs/bcachefs/journal_seq_blacklist.c +++ b/fs/bcachefs/journal_seq_blacklist.c @@ -235,6 +235,7 @@ static void bch2_sb_journal_seq_blacklist_to_text(struct printbuf *out, le64_to_cpu(i->start), le64_to_cpu(i->end)); } + pr_newline(out); } const struct bch_sb_field_ops bch_sb_field_ops_journal_seq_blacklist = { diff --git a/fs/bcachefs/quota.c b/fs/bcachefs/quota.c index 6fb8224f565e..b7ef8fa7bbc9 100644 --- a/fs/bcachefs/quota.c +++ b/fs/bcachefs/quota.c @@ -6,7 +6,18 @@ #include "subvolume.h" #include "super-io.h" -static int bch2_sb_validate_quota(struct bch_sb *sb, struct bch_sb_field *f, +static const char * const bch2_quota_types[] = { + "user", + "group", + "project", +}; + +static const char * const bch2_quota_counters[] = { + "space", + "inodes", +}; + +static int bch2_sb_quota_validate(struct bch_sb *sb, struct bch_sb_field *f, struct printbuf *err) { struct bch_sb_field_quota *q = field_to_type(f, quota); @@ -14,13 +25,36 @@ static int bch2_sb_validate_quota(struct bch_sb *sb, struct bch_sb_field *f, if (vstruct_bytes(&q->field) < sizeof(*q)) { pr_buf(err, "wrong size (got %llu should be %zu)", vstruct_bytes(&q->field), sizeof(*q)); + return -EINVAL; } return 0; } +static void bch2_sb_quota_to_text(struct printbuf *out, struct bch_sb *sb, + struct bch_sb_field *f) +{ + struct bch_sb_field_quota *q = field_to_type(f, quota); + unsigned qtyp, counter; + + for (qtyp = 0; qtyp < ARRAY_SIZE(q->q); qtyp++) { + pr_buf(out, "%s: flags %llx", + bch2_quota_types[qtyp], + le64_to_cpu(q->q[qtyp].flags)); + + for (counter = 0; counter < Q_COUNTERS; counter++) + pr_buf(out, " %s timelimit %u warnlimit %u", + bch2_quota_counters[counter], + le32_to_cpu(q->q[qtyp].c[counter].timelimit), + le32_to_cpu(q->q[qtyp].c[counter].warnlimit)); + + pr_newline(out); + } +} + const struct bch_sb_field_ops bch_sb_field_ops_quota = { - .validate = bch2_sb_validate_quota, + .validate = bch2_sb_quota_validate, + .to_text = bch2_sb_quota_to_text, }; const char *bch2_quota_invalid(const struct bch_fs *c, struct bkey_s_c k) @@ -34,11 +68,6 @@ const char *bch2_quota_invalid(const struct bch_fs *c, struct bkey_s_c k) return NULL; } -static const char * const bch2_quota_counters[] = { - "space", - "inodes", -}; - void bch2_quota_to_text(struct printbuf *out, struct bch_fs *c, struct bkey_s_c k) { diff --git a/fs/bcachefs/recovery.c b/fs/bcachefs/recovery.c index 7def5938e24d..d33b9e2bb1e3 100644 --- a/fs/bcachefs/recovery.c +++ b/fs/bcachefs/recovery.c @@ -821,7 +821,7 @@ static struct bch_sb_field_clean *read_superblock_clean(struct bch_fs *c) return ERR_PTR(-ENOMEM); } - ret = bch2_sb_clean_validate(c, clean, READ); + ret = bch2_sb_clean_validate_late(c, clean, READ); if (ret) { mutex_unlock(&c->sb_lock); return ERR_PTR(ret); diff --git a/fs/bcachefs/replicas.c b/fs/bcachefs/replicas.c index c192e31d5d68..7cc2414893fc 100644 --- a/fs/bcachefs/replicas.c +++ b/fs/bcachefs/replicas.c @@ -36,6 +36,22 @@ static void bch2_cpu_replicas_sort(struct bch_replicas_cpu *r) eytzinger0_sort(r->entries, r->nr, r->entry_size, memcmp, NULL); } +void bch2_replicas_entry_v0_to_text(struct printbuf *out, + struct bch_replicas_entry_v0 *e) +{ + unsigned i; + + if (e->data_type < BCH_DATA_NR) + pr_buf(out, "%s", bch2_data_types[e->data_type]); + else + pr_buf(out, "(invalid data type %u)", e->data_type); + + pr_buf(out, ": %u [", e->nr_devs); + for (i = 0; i < e->nr_devs; i++) + pr_buf(out, i ? " %u" : "%u", e->devs[i]); + pr_buf(out, "]"); +} + void bch2_replicas_entry_to_text(struct printbuf *out, struct bch_replicas_entry *e) { @@ -867,7 +883,7 @@ static int bch2_cpu_replicas_validate(struct bch_replicas_cpu *cpu_r, return 0; } -static int bch2_sb_validate_replicas(struct bch_sb *sb, struct bch_sb_field *f, +static int bch2_sb_replicas_validate(struct bch_sb *sb, struct bch_sb_field *f, struct printbuf *err) { struct bch_sb_field_replicas *sb_r = field_to_type(f, replicas); @@ -897,14 +913,15 @@ static void bch2_sb_replicas_to_text(struct printbuf *out, bch2_replicas_entry_to_text(out, e); } + pr_newline(out); } const struct bch_sb_field_ops bch_sb_field_ops_replicas = { - .validate = bch2_sb_validate_replicas, + .validate = bch2_sb_replicas_validate, .to_text = bch2_sb_replicas_to_text, }; -static int bch2_sb_validate_replicas_v0(struct bch_sb *sb, struct bch_sb_field *f, +static int bch2_sb_replicas_v0_validate(struct bch_sb *sb, struct bch_sb_field *f, struct printbuf *err) { struct bch_sb_field_replicas_v0 *sb_r = field_to_type(f, replicas_v0); @@ -919,8 +936,27 @@ static int bch2_sb_validate_replicas_v0(struct bch_sb *sb, struct bch_sb_field * return ret; } +static void bch2_sb_replicas_v0_to_text(struct printbuf *out, + struct bch_sb *sb, + struct bch_sb_field *f) +{ + struct bch_sb_field_replicas_v0 *sb_r = field_to_type(f, replicas_v0); + struct bch_replicas_entry_v0 *e; + bool first = true; + + for_each_replicas_entry(sb_r, e) { + if (!first) + pr_buf(out, " "); + first = false; + + bch2_replicas_entry_v0_to_text(out, e); + } + pr_newline(out); +} + const struct bch_sb_field_ops bch_sb_field_ops_replicas_v0 = { - .validate = bch2_sb_validate_replicas_v0, + .validate = bch2_sb_replicas_v0_validate, + .to_text = bch2_sb_replicas_v0_to_text, }; /* Query replicas: */ @@ -977,19 +1013,42 @@ bool bch2_have_enough_devs(struct bch_fs *c, struct bch_devs_mask devs, return ret; } +unsigned bch2_sb_dev_has_data(struct bch_sb *sb, unsigned dev) +{ + struct bch_sb_field_replicas *replicas; + struct bch_sb_field_replicas_v0 *replicas_v0; + unsigned i, data_has = 0; + + replicas = bch2_sb_get_replicas(sb); + replicas_v0 = bch2_sb_get_replicas_v0(sb); + + if (replicas) { + struct bch_replicas_entry *r; + + for_each_replicas_entry(replicas, r) + for (i = 0; i < r->nr_devs; i++) + if (r->devs[i] == dev) + data_has |= 1 << r->data_type; + } else if (replicas_v0) { + struct bch_replicas_entry_v0 *r; + + for_each_replicas_entry_v0(replicas_v0, r) + for (i = 0; i < r->nr_devs; i++) + if (r->devs[i] == dev) + data_has |= 1 << r->data_type; + } + + + return data_has; +} + unsigned bch2_dev_has_data(struct bch_fs *c, struct bch_dev *ca) { - struct bch_replicas_entry *e; - unsigned i, ret = 0; + unsigned ret; - percpu_down_read(&c->mark_lock); - - for_each_cpu_replicas_entry(&c->replicas, e) - for (i = 0; i < e->nr_devs; i++) - if (e->devs[i] == ca->dev_idx) - ret |= 1 << e->data_type; - - percpu_up_read(&c->mark_lock); + mutex_lock(&c->sb_lock); + ret = bch2_sb_dev_has_data(c->disk_sb.sb, ca->dev_idx); + mutex_unlock(&c->sb_lock); return ret; } diff --git a/fs/bcachefs/replicas.h b/fs/bcachefs/replicas.h index d237d7c51ccb..87820b2e1ad3 100644 --- a/fs/bcachefs/replicas.h +++ b/fs/bcachefs/replicas.h @@ -64,6 +64,7 @@ static inline void bch2_replicas_entry_cached(struct bch_replicas_entry *e, bool bch2_have_enough_devs(struct bch_fs *, struct bch_devs_mask, unsigned, bool); +unsigned bch2_sb_dev_has_data(struct bch_sb *, unsigned); unsigned bch2_dev_has_data(struct bch_fs *, struct bch_dev *); int bch2_replicas_gc_end(struct bch_fs *, int); diff --git a/fs/bcachefs/super-io.c b/fs/bcachefs/super-io.c index f89e883ff2e2..e1ff14eedaea 100644 --- a/fs/bcachefs/super-io.c +++ b/fs/bcachefs/super-io.c @@ -920,7 +920,7 @@ static int u64_cmp(const void *_l, const void *_r) return l < r ? -1 : l > r ? 1 : 0; } -static int bch2_sb_validate_journal(struct bch_sb *sb, +static int bch2_sb_journal_validate(struct bch_sb *sb, struct bch_sb_field *f, struct printbuf *err) { @@ -973,13 +973,26 @@ err: return ret; } +static void bch2_sb_journal_to_text(struct printbuf *out, struct bch_sb *sb, + struct bch_sb_field *f) +{ + struct bch_sb_field_journal *journal = field_to_type(f, journal); + unsigned i, nr = bch2_nr_journal_buckets(journal); + + pr_buf(out, "Buckets: "); + for (i = 0; i < nr; i++) + pr_buf(out, " %llu", le64_to_cpu(journal->buckets[i])); + pr_newline(out); +} + static const struct bch_sb_field_ops bch_sb_field_ops_journal = { - .validate = bch2_sb_validate_journal, + .validate = bch2_sb_journal_validate, + .to_text = bch2_sb_journal_to_text, }; /* BCH_SB_FIELD_members: */ -static int bch2_sb_validate_members(struct bch_sb *sb, +static int bch2_sb_members_validate(struct bch_sb *sb, struct bch_sb_field *f, struct printbuf *err) { @@ -1029,13 +1042,105 @@ static int bch2_sb_validate_members(struct bch_sb *sb, return 0; } +static void bch2_sb_members_to_text(struct printbuf *out, struct bch_sb *sb, + struct bch_sb_field *f) +{ + struct bch_sb_field_members *mi = field_to_type(f, members); + struct bch_sb_field_disk_groups *gi = bch2_sb_get_disk_groups(sb); + unsigned i; + + for (i = 0; i < sb->nr_devices; i++) { + struct bch_member *m = mi->members + i; + unsigned data_have = bch2_sb_dev_has_data(sb, i); + u64 bucket_size = le16_to_cpu(m->bucket_size); + u64 device_size = le64_to_cpu(m->nbuckets) * bucket_size; + + if (!bch2_member_exists(m)) + continue; + + pr_buf(out, "Device: %u", i); + pr_newline(out); + + printbuf_indent_push(out, 2); + + pr_buf(out, "UUID: "); + pr_uuid(out, m->uuid.b); + pr_newline(out); + + pr_buf(out, "Size: "); + pr_units(out, device_size, device_size << 9); + pr_newline(out); + + pr_buf(out, "Bucket size: "); + pr_units(out, bucket_size, bucket_size << 9); + pr_newline(out); + + pr_buf(out, "First bucket: %u", + le16_to_cpu(m->first_bucket)); + pr_newline(out); + + pr_buf(out, "Buckets: %llu", + le64_to_cpu(m->nbuckets)); + pr_newline(out); + + pr_buf(out, "Last mount: "); + if (m->last_mount) + pr_time(out, le64_to_cpu(m->last_mount)); + else + pr_buf(out, "(never)"); + pr_newline(out); + + pr_buf(out, "State: %s", + BCH_MEMBER_STATE(m) < BCH_MEMBER_STATE_NR + ? bch2_member_states[BCH_MEMBER_STATE(m)] + : "unknown"); + pr_newline(out); + + pr_buf(out, "Group: "); + if (BCH_MEMBER_GROUP(m)) { + unsigned idx = BCH_MEMBER_GROUP(m) - 1; + + if (idx < disk_groups_nr(gi)) + pr_buf(out, "%s (%u)", + gi->entries[idx].label, idx); + else + pr_buf(out, "(bad disk labels section)"); + } else { + pr_buf(out, "(none)"); + } + pr_newline(out); + + pr_buf(out, "Data allowed: "); + if (BCH_MEMBER_DATA_ALLOWED(m)) + bch2_flags_to_text(out, bch2_data_types, + BCH_MEMBER_DATA_ALLOWED(m)); + else + pr_buf(out, "(none)"); + pr_newline(out); + + pr_buf(out, "Has data: "); + if (data_have) + bch2_flags_to_text(out, bch2_data_types, data_have); + else + pr_buf(out, "(none)"); + pr_newline(out); + + pr_buf(out, "Discard: %llu", + BCH_MEMBER_DISCARD(m)); + pr_newline(out); + + printbuf_indent_pop(out, 2); + } +} + static const struct bch_sb_field_ops bch_sb_field_ops_members = { - .validate = bch2_sb_validate_members, + .validate = bch2_sb_members_validate, + .to_text = bch2_sb_members_to_text, }; /* BCH_SB_FIELD_crypt: */ -static int bch2_sb_validate_crypt(struct bch_sb *sb, +static int bch2_sb_crypt_validate(struct bch_sb *sb, struct bch_sb_field *f, struct printbuf *err) { @@ -1055,13 +1160,29 @@ static int bch2_sb_validate_crypt(struct bch_sb *sb, return 0; } +static void bch2_sb_crypt_to_text(struct printbuf *out, struct bch_sb *sb, + struct bch_sb_field *f) +{ + struct bch_sb_field_crypt *crypt = field_to_type(f, crypt); + + pr_buf(out, "KFD: %llu", BCH_CRYPT_KDF_TYPE(crypt)); + pr_newline(out); + pr_buf(out, "scrypt n: %llu", BCH_KDF_SCRYPT_N(crypt)); + pr_newline(out); + pr_buf(out, "scrypt r: %llu", BCH_KDF_SCRYPT_R(crypt)); + pr_newline(out); + pr_buf(out, "scrypt p: %llu", BCH_KDF_SCRYPT_P(crypt)); + pr_newline(out); +} + static const struct bch_sb_field_ops bch_sb_field_ops_crypt = { - .validate = bch2_sb_validate_crypt, + .validate = bch2_sb_crypt_validate, + .to_text = bch2_sb_crypt_to_text, }; /* BCH_SB_FIELD_clean: */ -int bch2_sb_clean_validate(struct bch_fs *c, struct bch_sb_field_clean *clean, int write) +int bch2_sb_clean_validate_late(struct bch_fs *c, struct bch_sb_field_clean *clean, int write) { struct jset_entry *entry; int ret; @@ -1251,7 +1372,7 @@ void bch2_fs_mark_clean(struct bch_fs *c) * this should be in the write path, and we should be validating every * superblock section: */ - ret = bch2_sb_clean_validate(c, sb_clean, WRITE); + ret = bch2_sb_clean_validate_late(c, sb_clean, WRITE); if (ret) { bch_err(c, "error writing marking filesystem clean: validate error"); goto out; @@ -1262,7 +1383,7 @@ out: mutex_unlock(&c->sb_lock); } -static int bch2_sb_validate_clean(struct bch_sb *sb, +static int bch2_sb_clean_validate(struct bch_sb *sb, struct bch_sb_field *f, struct printbuf *err) { @@ -1277,8 +1398,32 @@ static int bch2_sb_validate_clean(struct bch_sb *sb, return 0; } +static void bch2_sb_clean_to_text(struct printbuf *out, struct bch_sb *sb, + struct bch_sb_field *f) +{ + struct bch_sb_field_clean *clean = field_to_type(f, clean); + struct jset_entry *entry; + + pr_buf(out, "flags: %x", le32_to_cpu(clean->flags)); + pr_newline(out); + pr_buf(out, "journal_seq: %llu", le64_to_cpu(clean->journal_seq)); + pr_newline(out); + + for (entry = clean->start; + entry != vstruct_end(&clean->field); + entry = vstruct_next(entry)) { + if (entry->type == BCH_JSET_ENTRY_btree_keys && + !entry->u64s) + continue; + + bch2_journal_entry_to_text(out, NULL, entry); + pr_newline(out); + } +} + static const struct bch_sb_field_ops bch_sb_field_ops_clean = { - .validate = bch2_sb_validate_clean, + .validate = bch2_sb_clean_validate, + .to_text = bch2_sb_clean_to_text, }; static const struct bch_sb_field_ops *bch2_sb_field_ops[] = { @@ -1302,7 +1447,7 @@ static int bch2_sb_field_validate(struct bch_sb *sb, struct bch_sb_field *f, ret = bch2_sb_field_ops[type]->validate(sb, f, &err); if (ret) { - pr_buf(&err, "\n"); + pr_newline(&err); bch2_sb_field_to_text(&err, sb, f); *orig_err = err; } @@ -1323,7 +1468,202 @@ void bch2_sb_field_to_text(struct printbuf *out, struct bch_sb *sb, pr_buf(out, "(unknown field %u)", type); pr_buf(out, " (size %llu):", vstruct_bytes(f)); + pr_newline(out); - if (ops && ops->to_text) + if (ops && ops->to_text) { + printbuf_indent_push(out, 2); bch2_sb_field_ops[type]->to_text(out, sb, f); + printbuf_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; + + 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_uuid(out, sb->user_uuid.b); + pr_newline(out); + + pr_buf(out, "Internal UUID: "); + pr_uuid(out, sb->uuid.b); + pr_newline(out); + + pr_buf(out, "Device index: %u", sb->dev_idx); + pr_newline(out); + + pr_buf(out, "Label: "); + pr_buf(out, "%.*s", (int) sizeof(sb->label), sb->label); + pr_newline(out); + + pr_buf(out, "Version: %u", le16_to_cpu(sb->version)); + pr_newline(out); + + pr_buf(out, "Oldest version on disk: %u", le16_to_cpu(sb->version_min)); + pr_newline(out); + + pr_buf(out, "Created: "); + if (sb->time_base_lo) + pr_time(out, le64_to_cpu(sb->time_base_lo) / NSEC_PER_SEC); + else + pr_buf(out, "(not set)"); + pr_newline(out); + + pr_buf(out, "Squence number: %llu", le64_to_cpu(sb->seq)); + pr_newline(out); + + pr_buf(out, "Block_size: "); + pr_units(out, le16_to_cpu(sb->block_size), + (u32) le16_to_cpu(sb->block_size) << 9); + pr_newline(out); + + pr_buf(out, "Btree node size: "); + pr_units(out, BCH_SB_BTREE_NODE_SIZE(sb), + BCH_SB_BTREE_NODE_SIZE(sb) << 9); + pr_newline(out); + + pr_buf(out, "Error action: %s", + BCH_SB_ERROR_ACTION(sb) < BCH_ON_ERROR_NR + ? bch2_error_actions[BCH_SB_ERROR_ACTION(sb)] + : "unknown"); + pr_newline(out); + + pr_buf(out, "Clean: %llu", BCH_SB_CLEAN(sb)); + pr_newline(out); + + pr_buf(out, "Features: "); + bch2_flags_to_text(out, bch2_sb_features, + le64_to_cpu(sb->features[0])); + pr_newline(out); + + pr_buf(out, "Compat features: "); + bch2_flags_to_text(out, bch2_sb_compat, + le64_to_cpu(sb->compat[0])); + pr_newline(out); + + pr_buf(out, "Metadata replicas: %llu", BCH_SB_META_REPLICAS_WANT(sb)); + pr_newline(out); + + pr_buf(out, "Data replicas: %llu", BCH_SB_DATA_REPLICAS_WANT(sb)); + pr_newline(out); + + pr_buf(out, "Metadata checksum type: %s (%llu)", + BCH_SB_META_CSUM_TYPE(sb) < BCH_CSUM_OPT_NR + ? bch2_csum_opts[BCH_SB_META_CSUM_TYPE(sb)] + : "unknown", + BCH_SB_META_CSUM_TYPE(sb)); + pr_newline(out); + + pr_buf(out, "Data checksum type: %s (%llu)", + BCH_SB_DATA_CSUM_TYPE(sb) < BCH_CSUM_OPT_NR + ? bch2_csum_opts[BCH_SB_DATA_CSUM_TYPE(sb)] + : "unknown", + BCH_SB_DATA_CSUM_TYPE(sb)); + pr_newline(out); + + pr_buf(out, "Compression type: %s (%llu)", + BCH_SB_COMPRESSION_TYPE(sb) < BCH_COMPRESSION_OPT_NR + ? bch2_compression_opts[BCH_SB_COMPRESSION_TYPE(sb)] + : "unknown", + BCH_SB_COMPRESSION_TYPE(sb)); + pr_newline(out); + + pr_buf(out, "Foreground write target: "); + bch2_sb_target_to_text(out, sb, BCH_SB_FOREGROUND_TARGET(sb)); + pr_newline(out); + + pr_buf(out, "Background write target: "); + bch2_sb_target_to_text(out, sb, BCH_SB_BACKGROUND_TARGET(sb)); + pr_newline(out); + + pr_buf(out, "Promote target: "); + bch2_sb_target_to_text(out, sb, BCH_SB_PROMOTE_TARGET(sb)); + pr_newline(out); + + pr_buf(out, "Metadata target: "); + bch2_sb_target_to_text(out, sb, BCH_SB_METADATA_TARGET(sb)); + pr_newline(out); + + pr_buf(out, "String hash type: %s (%llu)", + BCH_SB_STR_HASH_TYPE(sb) < BCH_STR_HASH_NR + ? bch2_str_hash_types[BCH_SB_STR_HASH_TYPE(sb)] + : "unknown", + BCH_SB_STR_HASH_TYPE(sb)); + pr_newline(out); + + pr_buf(out, "32 bit inodes: %llu", BCH_SB_INODE_32BIT(sb)); + pr_newline(out); + + pr_buf(out, "GC reserve percentage: %llu%%", BCH_SB_GC_RESERVE(sb)); + pr_newline(out); + + pr_buf(out, "Root reserve percentage: %llu%%", BCH_SB_ROOT_RESERVE(sb)); + pr_newline(out); + + pr_buf(out, "Devices: %u live, %u total", + nr_devices, sb->nr_devices); + pr_newline(out); + + pr_buf(out, "Sections: "); + vstruct_for_each(sb, f) + fields_have |= 1 << le32_to_cpu(f->type); + bch2_flags_to_text(out, bch2_sb_fields, fields_have); + pr_newline(out); + + pr_buf(out, "Superblock size: %llu", vstruct_bytes(sb)); + pr_newline(out); + + if (print_layout) { + pr_newline(out); + pr_buf(out, "layout:"); + pr_newline(out); + printbuf_indent_push(out, 2); + bch2_sb_layout_to_text(out, &sb->layout); + printbuf_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); + } } diff --git a/fs/bcachefs/super-io.h b/fs/bcachefs/super-io.h index 6170fa0990f1..ccd6fe7fdf29 100644 --- a/fs/bcachefs/super-io.h +++ b/fs/bcachefs/super-io.h @@ -121,12 +121,14 @@ static inline struct bch_member_cpu bch2_mi_to_cpu(struct bch_member *mi) void bch2_journal_super_entries_add_common(struct bch_fs *, struct jset_entry **, u64); -int bch2_sb_clean_validate(struct bch_fs *, struct bch_sb_field_clean *, int); +int bch2_sb_clean_validate_late(struct bch_fs *, struct bch_sb_field_clean *, int); int bch2_fs_mark_dirty(struct bch_fs *); void bch2_fs_mark_clean(struct bch_fs *); void bch2_sb_field_to_text(struct printbuf *, struct bch_sb *, struct bch_sb_field *); +void bch2_sb_layout_to_text(struct printbuf *, struct bch_sb_layout *); +void bch2_sb_to_text(struct printbuf *, struct bch_sb *, bool, unsigned); #endif /* _BCACHEFS_SUPER_IO_H */ diff --git a/fs/bcachefs/sysfs.c b/fs/bcachefs/sysfs.c index b727845dd64b..1a3068f658a1 100644 --- a/fs/bcachefs/sysfs.c +++ b/fs/bcachefs/sysfs.c @@ -825,7 +825,7 @@ SHOW(bch2_dev) if (attr == &sysfs_label) { if (ca->mi.group) { mutex_lock(&c->sb_lock); - bch2_disk_path_to_text(&out, &c->disk_sb, + bch2_disk_path_to_text(&out, c->disk_sb.sb, ca->mi.group - 1); mutex_unlock(&c->sb_lock); } diff --git a/fs/bcachefs/util.c b/fs/bcachefs/util.c index 971f404a01e3..f170cf9d5052 100644 --- a/fs/bcachefs/util.c +++ b/fs/bcachefs/util.c @@ -120,6 +120,27 @@ void bch2_hprint(struct printbuf *buf, s64 v) pr_buf(buf, "%c", si_units[u]); } +void bch2_pr_units(struct printbuf *out, s64 raw, s64 bytes) +{ + if (raw < 0) { + pr_buf(out, "-"); + raw = -raw; + bytes = -bytes; + } + + switch (out->units) { + case PRINTBUF_UNITS_RAW: + pr_buf(out, "%llu", raw); + break; + case PRINTBUF_UNITS_BYTES: + pr_buf(out, "%llu", bytes); + break; + case PRINTBUF_UNITS_HUMAN_READABLE: + bch2_hprint(out, bytes); + break; + } +} + void bch2_string_opt_to_text(struct printbuf *out, const char * const list[], size_t selected) diff --git a/fs/bcachefs/util.h b/fs/bcachefs/util.h index fc8ffa61bbeb..3d5a9e04b3ad 100644 --- a/fs/bcachefs/util.h +++ b/fs/bcachefs/util.h @@ -235,10 +235,17 @@ do { \ #define ANYSINT_MAX(t) \ ((((t) 1 << (sizeof(t) * 8 - 2)) - (t) 1) * (t) 2 + (t) 1) +enum printbuf_units { + PRINTBUF_UNITS_RAW, + PRINTBUF_UNITS_BYTES, + PRINTBUF_UNITS_HUMAN_READABLE, +}; + struct printbuf { - char *pos; - char *end; - unsigned indent; + char *pos; + char *end; + unsigned indent; + enum printbuf_units units; }; static inline size_t printbuf_remaining(struct printbuf *buf) @@ -272,7 +279,7 @@ static inline void printbuf_indent_pop(struct printbuf *buf, unsigned spaces) buf->indent -= spaces; } -static inline void printbuf_newline(struct printbuf *buf) +static inline void pr_newline(struct printbuf *buf) { unsigned i; @@ -281,6 +288,46 @@ static inline void printbuf_newline(struct printbuf *buf) pr_buf(buf, " "); } +void bch2_pr_units(struct printbuf *, s64, s64); +#define pr_units(...) bch2_pr_units(__VA_ARGS__) + +#ifdef __KERNEL__ +static inline void pr_time(struct printbuf *out, u64 time) +{ + pr_buf(out, "%llu", time); +} +#else +#include +static inline void pr_time(struct printbuf *out, u64 _time) +{ + char time_str[64]; + time_t time = _time; + struct tm *tm = localtime(&time); + size_t err = strftime(time_str, sizeof(time_str), "%c", tm); + if (!err) + pr_buf(out, "(formatting error)"); + else + pr_buf(out, "%s", time_str); +} +#endif + +#ifdef __KERNEL__ +static inline void uuid_unparse_lower(u8 *uuid, char *out) +{ + sprintf(out, "%plU", uuid); +} +#else +#include +#endif + +static inline void pr_uuid(struct printbuf *out, u8 *uuid) +{ + char uuid_str[40]; + + uuid_unparse_lower(uuid, uuid_str); + pr_buf(out, uuid_str); +} + int bch2_strtoint_h(const char *, int *); int bch2_strtouint_h(const char *, unsigned int *); int bch2_strtoll_h(const char *, long long *); @@ -784,13 +831,4 @@ static inline int u8_cmp(u8 l, u8 r) return cmp_int(l, r); } -#ifdef __KERNEL__ -static inline void uuid_unparse_lower(u8 *uuid, char *out) -{ - sprintf(out, "%plU", uuid); -} -#else -#include -#endif - #endif /* _BCACHEFS_UTIL_H */