summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.bcachefs_revision2
-rw-r--r--libbcachefs/alloc_background.c3
-rw-r--r--libbcachefs/dirent.c6
-rw-r--r--libbcachefs/disk_groups.c49
-rw-r--r--libbcachefs/disk_groups.h5
-rw-r--r--libbcachefs/extents.c18
-rw-r--r--libbcachefs/journal_io.c4
-rw-r--r--libbcachefs/journal_reclaim.c3
-rw-r--r--libbcachefs/journal_seq_blacklist.c1
-rw-r--r--libbcachefs/quota.c43
-rw-r--r--libbcachefs/recovery.c2
-rw-r--r--libbcachefs/replicas.c85
-rw-r--r--libbcachefs/replicas.h1
-rw-r--r--libbcachefs/super-io.c364
-rw-r--r--libbcachefs/super-io.h4
-rw-r--r--libbcachefs/sysfs.c2
-rw-r--r--libbcachefs/util.c34
-rw-r--r--libbcachefs/util.h64
-rw-r--r--libbcachefs/xattr.c10
19 files changed, 605 insertions, 95 deletions
diff --git a/.bcachefs_revision b/.bcachefs_revision
index 5165b9d..b537d89 100644
--- a/.bcachefs_revision
+++ b/.bcachefs_revision
@@ -1 +1 @@
-7d0925084b6927ad8c631bde92fb1c41cc6270c2
+9d554fa16def4f6310d2df74092c5568419e69e3
diff --git a/libbcachefs/alloc_background.c b/libbcachefs/alloc_background.c
index 023db62..4afb2d4 100644
--- a/libbcachefs/alloc_background.c
+++ b/libbcachefs/alloc_background.c
@@ -794,7 +794,8 @@ static int push_invalidated_bucket(struct bch_fs *c, struct bch_dev *ca, u64 b)
static void discard_one_bucket(struct bch_fs *c, struct bch_dev *ca, u64 b)
{
- if (ca->mi.discard &&
+ if (!c->opts.nochanges &&
+ ca->mi.discard &&
blk_queue_discard(bdev_get_queue(ca->disk_sb.bdev)))
blkdev_issue_discard(ca->disk_sb.bdev, bucket_to_sector(ca, b),
ca->mi.bucket_size, GFP_NOFS, 0);
diff --git a/libbcachefs/dirent.c b/libbcachefs/dirent.c
index 6f699b7..a43a244 100644
--- a/libbcachefs/dirent.c
+++ b/libbcachefs/dirent.c
@@ -122,9 +122,9 @@ void bch2_dirent_to_text(struct printbuf *out, struct bch_fs *c,
{
struct bkey_s_c_dirent d = bkey_s_c_to_dirent(k);
- bch_scnmemcpy(out, d.v->d_name,
- bch2_dirent_name_bytes(d));
- pr_buf(out, " -> %llu type %s",
+ pr_buf(out, "%.*s -> %llu type %s",
+ bch2_dirent_name_bytes(d),
+ d.v->d_name,
d.v->d_type != DT_SUBVOL
? le64_to_cpu(d.v->d_inum)
: le32_to_cpu(d.v->d_child_subvol),
diff --git a/libbcachefs/disk_groups.c b/libbcachefs/disk_groups.c
index 6c84297..19698e5 100644
--- a/libbcachefs/disk_groups.c
+++ b/libbcachefs/disk_groups.c
@@ -76,8 +76,9 @@ static int bch2_sb_disk_groups_validate(struct bch_sb *sb,
for (g = sorted; g + 1 < sorted + nr_groups; g++)
if (!BCH_GROUP_DELETED(g) &&
!group_cmp(&g[0], &g[1])) {
- pr_buf(err, "duplicate label %llu.", BCH_GROUP_PARENT(g));
- bch_scnmemcpy(err, g->label, strnlen(g->label, sizeof(g->label)));
+ pr_buf(err, "duplicate label %llu.%.*s",
+ BCH_GROUP_PARENT(g),
+ (int) sizeof(g->label), g->label);
goto err;
}
@@ -342,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];
@@ -376,15 +375,13 @@ void bch2_disk_path_to_text(struct printbuf *out,
v = path[--nr];
g = groups->entries + v;
- bch_scnmemcpy(out, g->label,
- strnlen(g->label, sizeof(g->label)));
-
+ pr_buf(out, "%.*s", (int) sizeof(g->label), g->label);
if (nr)
pr_buf(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)
@@ -448,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);
@@ -481,7 +508,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/libbcachefs/disk_groups.h b/libbcachefs/disk_groups.h
index 3d84f23..a274aac 100644
--- a/libbcachefs/disk_groups.h
+++ b/libbcachefs/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/libbcachefs/extents.c b/libbcachefs/extents.c
index 44c584e..cc50e4b 100644
--- a/libbcachefs/extents.c
+++ b/libbcachefs/extents.c
@@ -954,15 +954,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/libbcachefs/journal_io.c b/libbcachefs/journal_io.c
index 901e346..05c1092 100644
--- a/libbcachefs/journal_io.c
+++ b/libbcachefs/journal_io.c
@@ -303,7 +303,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);
@@ -596,7 +596,7 @@ static void journal_entry_log_to_text(struct printbuf *out, struct bch_fs *c,
struct jset_entry_log *l = container_of(entry, struct jset_entry_log, entry);
unsigned bytes = vstruct_bytes(entry) - offsetof(struct jset_entry_log, d);
- bch_scnmemcpy(out, l->d, strnlen(l->d, bytes));
+ pr_buf(out, "%.*s", bytes, l->d);
}
struct jset_entry_ops {
diff --git a/libbcachefs/journal_reclaim.c b/libbcachefs/journal_reclaim.c
index 52a3935..9467191 100644
--- a/libbcachefs/journal_reclaim.c
+++ b/libbcachefs/journal_reclaim.c
@@ -286,7 +286,8 @@ void bch2_journal_do_discards(struct journal *j)
struct journal_device *ja = &ca->journal;
while (should_discard_bucket(j, ja)) {
- if (ca->mi.discard &&
+ if (!c->opts.nochanges &&
+ ca->mi.discard &&
blk_queue_discard(bdev_get_queue(ca->disk_sb.bdev)))
blkdev_issue_discard(ca->disk_sb.bdev,
bucket_to_sector(ca,
diff --git a/libbcachefs/journal_seq_blacklist.c b/libbcachefs/journal_seq_blacklist.c
index 3cc63fc..3140c87 100644
--- a/libbcachefs/journal_seq_blacklist.c
+++ b/libbcachefs/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/libbcachefs/quota.c b/libbcachefs/quota.c
index 6fb8224..b7ef8fa 100644
--- a/libbcachefs/quota.c
+++ b/libbcachefs/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/libbcachefs/recovery.c b/libbcachefs/recovery.c
index 96f13f2..ed25595 100644
--- a/libbcachefs/recovery.c
+++ b/libbcachefs/recovery.c
@@ -803,7 +803,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/libbcachefs/replicas.c b/libbcachefs/replicas.c
index 96994b7..6c1d42f 100644
--- a/libbcachefs/replicas.c
+++ b/libbcachefs/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)
{
@@ -860,7 +876,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);
@@ -890,14 +906,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);
@@ -912,8 +929,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: */
@@ -970,19 +1006,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;
}
diff --git a/libbcachefs/replicas.h b/libbcachefs/replicas.h
index d237d7c..87820b2 100644
--- a/libbcachefs/replicas.h
+++ b/libbcachefs/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/libbcachefs/super-io.c b/libbcachefs/super-io.c
index eae6318..08613a7 100644
--- a/libbcachefs/super-io.c
+++ b/libbcachefs/super-io.c
@@ -918,7 +918,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)
{
@@ -971,13 +971,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)
{
@@ -1027,13 +1040,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)
{
@@ -1053,13 +1158,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;
@@ -1248,7 +1369,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;
@@ -1259,7 +1380,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)
{
@@ -1274,8 +1395,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[] = {
@@ -1299,7 +1444,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;
}
@@ -1320,7 +1465,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/libbcachefs/super-io.h b/libbcachefs/super-io.h
index 3b425be..50f31a3 100644
--- a/libbcachefs/super-io.h
+++ b/libbcachefs/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/libbcachefs/sysfs.c b/libbcachefs/sysfs.c
index b727845..1a3068f 100644
--- a/libbcachefs/sysfs.c
+++ b/libbcachefs/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/libbcachefs/util.c b/libbcachefs/util.c
index 0bbea33..ab808fe 100644
--- a/libbcachefs/util.c
+++ b/libbcachefs/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)
@@ -579,19 +600,6 @@ void memcpy_from_bio(void *dst, struct bio *src, struct bvec_iter src_iter)
}
}
-void bch_scnmemcpy(struct printbuf *out,
- const char *src, size_t len)
-{
- size_t n = printbuf_remaining(out);
-
- if (n) {
- n = min(n - 1, len);
- memcpy(out->pos, src, n);
- out->pos += n;
- *out->pos = '\0';
- }
-}
-
#include "eytzinger.h"
static int alignment_ok(const void *base, size_t align)
diff --git a/libbcachefs/util.h b/libbcachefs/util.h
index e55407d..b43c195 100644
--- a/libbcachefs/util.h
+++ b/libbcachefs/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,7 +288,45 @@ static inline void printbuf_newline(struct printbuf *buf)
pr_buf(buf, " ");
}
-void bch_scnmemcpy(struct printbuf *, const char *, size_t);
+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 *);
@@ -768,13 +813,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 */
diff --git a/libbcachefs/xattr.c b/libbcachefs/xattr.c
index 4d7db64..1673654 100644
--- a/libbcachefs/xattr.c
+++ b/libbcachefs/xattr.c
@@ -111,11 +111,11 @@ void bch2_xattr_to_text(struct printbuf *out, struct bch_fs *c,
else
pr_buf(out, "(unknown type %u)", xattr.v->x_type);
- bch_scnmemcpy(out, xattr.v->x_name,
- xattr.v->x_name_len);
- pr_buf(out, ":");
- bch_scnmemcpy(out, xattr_val(xattr.v),
- le16_to_cpu(xattr.v->x_val_len));
+ pr_buf(out, "%.*s:%.*s",
+ xattr.v->x_name_len,
+ xattr.v->x_name,
+ le16_to_cpu(xattr.v->x_val_len),
+ (char *) xattr_val(xattr.v));
}
static int bch2_xattr_get_trans(struct btree_trans *trans, struct bch_inode_info *inode,