]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
bcachefs: Add .to_text() methods for all superblock sections
authorKent Overstreet <kent.overstreet@gmail.com>
Sun, 20 Feb 2022 10:00:45 +0000 (05:00 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:09:24 +0000 (17:09 -0400)
This patch improves the superblock .to_text() methods and adds methods
for all types that were missing them. It also improves printbufs by
allowing them to specfiy what units we want to be printing in, and adds
new wrapper methods for unifying our kernel and userspace environments.

Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
14 files changed:
fs/bcachefs/disk_groups.c
fs/bcachefs/disk_groups.h
fs/bcachefs/extents.c
fs/bcachefs/journal_io.c
fs/bcachefs/journal_seq_blacklist.c
fs/bcachefs/quota.c
fs/bcachefs/recovery.c
fs/bcachefs/replicas.c
fs/bcachefs/replicas.h
fs/bcachefs/super-io.c
fs/bcachefs/super-io.h
fs/bcachefs/sysfs.c
fs/bcachefs/util.c
fs/bcachefs/util.h

index e411606fd38d37ce3f2c1aa8a54690bc2224c61b..e9ee37f1e07d9abfead6c4b9f823dfe010a2cde3 100644 (file)
@@ -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:
index 3d84f23c34ed42ab2b13e7be4beafddceb3f7fbd..a274aacbdf921e5360aca39227f93488d49e5aa8 100644 (file)
@@ -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);
index 3ed724e1fc98be7e906c77516d90aa4f9ef4b599..c78e10e8ec2c6c8e3488b6de25a8870d010b25f8 100644 (file)
@@ -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:
index 4f0904a515a748777c072b27cfa22b9ab99cc572..491300e3c48f5c970df5c5f663175bed5c62b25f 100644 (file)
@@ -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);
index 3cc63fc202ab4cbc83017cb6cad4412720e03797..3140c8731431ea7d5966b7ab38e4c71dda8a1fe7 100644 (file)
@@ -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 = {
index 6fb8224f565e3a00a2960a5dde41f2182a0dbe5a..b7ef8fa7bbc98356db0a274b3b89e294c8206b9d 100644 (file)
@@ -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)
 {
index 7def5938e24d47cd0fe982c1731beaa205190465..d33b9e2bb1e39653e6f4d71492a2758831053651 100644 (file)
@@ -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);
index c192e31d5d6805a6a1201a893faf0322320839db..7cc2414893fc4c9db104e1e7ecea59f0c6522724 100644 (file)
@@ -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_dev_has_data(struct bch_fs *c, struct bch_dev *ca)
+unsigned bch2_sb_dev_has_data(struct bch_sb *sb, unsigned dev)
 {
-       struct bch_replicas_entry *e;
-       unsigned i, ret = 0;
+       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;
+       }
 
-       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;
+       return data_has;
+}
 
-       percpu_up_read(&c->mark_lock);
+unsigned bch2_dev_has_data(struct bch_fs *c, struct bch_dev *ca)
+{
+       unsigned ret;
+
+       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;
 }
index d237d7c51ccb9b9faa771e72ba123fb505914c16..87820b2e1ad3e1322216aba57da1e083d6d49d37 100644 (file)
@@ -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);
index f89e883ff2e25a9ea0feba2387b8e1f6b2208073..e1ff14eedaea486e4714c0447d8534aa5d1bef5a 100644 (file)
@@ -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);
+               }
 }
index 6170fa0990f1902afa273f2f9057b8479da5296b..ccd6fe7fdf29751283ea0c4397cec25ea301250a 100644 (file)
@@ -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 */
index b727845dd64b73d4ea51fe8842c9f03ca899ad23..1a3068f658a1ffd5eea1bd850a3ffe419fe1fbed 100644 (file)
@@ -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);
                }
index 971f404a01e3b3b8cc577715f259934c000c860e..f170cf9d505292839016682dbb121bf3684169d8 100644 (file)
@@ -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)
index fc8ffa61bbeb970b6a33be89b093dd5bb71d848e..3d5a9e04b3adb23364f9805358e791de481d0f5d 100644 (file)
@@ -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 <time.h>
+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 <uuid/uuid.h>
+#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 <uuid/uuid.h>
-#endif
-
 #endif /* _BCACHEFS_UTIL_H */