summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2022-06-17 20:12:02 -0400
committerKent Overstreet <kent.overstreet@linux.dev>2023-10-22 17:09:34 -0400
commit50b13beef09f445e1fb8fbf1e1f852df06baf05a (patch)
treea6b120f5d24aca22fd26b61d1c259635200a335b
parent2ed6248ab3a58dbbe5819cbd0e60e4e3a5b72c47 (diff)
bcachefs: Improve an error message
When inserting a key type that's not valid for a given btree, we should print out which btree we were inserting into. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r--fs/bcachefs/bkey_methods.c4
-rw-r--r--fs/bcachefs/btree_iter.c109
-rw-r--r--fs/bcachefs/btree_iter.h2
-rw-r--r--fs/bcachefs/btree_types.h2
-rw-r--r--fs/bcachefs/debug.c77
-rw-r--r--fs/bcachefs/opts.c1
-rw-r--r--fs/bcachefs/sysfs.c5
7 files changed, 131 insertions, 69 deletions
diff --git a/fs/bcachefs/bkey_methods.c b/fs/bcachefs/bkey_methods.c
index 390ea41414bc..f2351e5ee7c1 100644
--- a/fs/bcachefs/bkey_methods.c
+++ b/fs/bcachefs/bkey_methods.c
@@ -207,8 +207,8 @@ int __bch2_bkey_invalid(struct bch_fs *c, struct bkey_s_c k,
}
if (!(bch2_key_types_allowed[type] & (1U << k.k->type))) {
- prt_printf(err, "invalid key type for this btree (%s)",
- bch2_bkey_types[type]);
+ prt_printf(err, "invalid key type for btree %s (%s)",
+ bch2_btree_ids[type], bch2_bkey_types[k.k->type]);
return -EINVAL;
}
diff --git a/fs/bcachefs/btree_iter.c b/fs/bcachefs/btree_iter.c
index a2219c13aee5..fc989b46b67e 100644
--- a/fs/bcachefs/btree_iter.c
+++ b/fs/bcachefs/btree_iter.c
@@ -3257,6 +3257,7 @@ void __bch2_trans_init(struct btree_trans *trans, struct bch_fs *c,
memset(trans, 0, sizeof(*trans));
trans->c = c;
trans->fn = fn;
+ trans->task = current;
trans->journal_replay_not_finished =
!test_bit(JOURNAL_REPLAY_DONE, &c->journal.flags);
@@ -3277,9 +3278,17 @@ void __bch2_trans_init(struct btree_trans *trans, struct bch_fs *c,
trans->srcu_idx = srcu_read_lock(&c->btree_trans_barrier);
if (IS_ENABLED(CONFIG_BCACHEFS_DEBUG_TRANSACTIONS)) {
- trans->pid = current->pid;
+ struct btree_trans *pos;
+
mutex_lock(&c->btree_trans_lock);
- list_add(&trans->list, &c->btree_trans_list);
+ list_for_each_entry(pos, &c->btree_trans_list, list) {
+ if (trans->task->pid < pos->task->pid) {
+ list_add_tail(&trans->list, &pos->list);
+ goto list_add_done;
+ }
+ }
+ list_add_tail(&trans->list, &c->btree_trans_list);
+list_add_done:
mutex_unlock(&c->btree_trans_lock);
}
}
@@ -3371,77 +3380,57 @@ bch2_btree_path_node_to_text(struct printbuf *out,
}
#ifdef CONFIG_BCACHEFS_DEBUG_TRANSACTIONS
-static bool trans_has_locks(struct btree_trans *trans)
+void bch2_btree_trans_to_text(struct printbuf *out, struct btree_trans *trans)
{
struct btree_path *path;
-
- trans_for_each_path(trans, path)
- if (path->nodes_locked)
- return true;
- return false;
-}
-#endif
-
-void bch2_btree_trans_to_text(struct printbuf *out, struct bch_fs *c)
-{
-#ifdef CONFIG_BCACHEFS_DEBUG_TRANSACTIONS
- struct btree_trans *trans;
- struct btree_path *path;
struct btree *b;
static char lock_types[] = { 'r', 'i', 'w' };
unsigned l;
- mutex_lock(&c->btree_trans_lock);
- list_for_each_entry(trans, &c->btree_trans_list, list) {
- if (!trans_has_locks(trans))
- continue;
-
- prt_printf(out, "%i %s\n", trans->pid, trans->fn);
+ prt_printf(out, "%i %s\n", trans->task->pid, trans->fn);
- trans_for_each_path(trans, path) {
- if (!path->nodes_locked)
- continue;
+ trans_for_each_path(trans, path) {
+ if (!path->nodes_locked)
+ continue;
- prt_printf(out, " path %u %c l=%u %s:",
- path->idx,
- path->cached ? 'c' : 'b',
- path->level,
- bch2_btree_ids[path->btree_id]);
- bch2_bpos_to_text(out, path->pos);
- prt_printf(out, "\n");
-
- for (l = 0; l < BTREE_MAX_DEPTH; l++) {
- if (btree_node_locked(path, l)) {
- prt_printf(out, " %s l=%u ",
- btree_node_intent_locked(path, l) ? "i" : "r", l);
- bch2_btree_path_node_to_text(out,
- (void *) path->l[l].b,
- path->cached);
- prt_printf(out, "\n");
- }
+ prt_printf(out, " path %u %c l=%u %s:",
+ path->idx,
+ path->cached ? 'c' : 'b',
+ path->level,
+ bch2_btree_ids[path->btree_id]);
+ bch2_bpos_to_text(out, path->pos);
+ prt_printf(out, "\n");
+
+ for (l = 0; l < BTREE_MAX_DEPTH; l++) {
+ if (btree_node_locked(path, l)) {
+ prt_printf(out, " %s l=%u ",
+ btree_node_intent_locked(path, l) ? "i" : "r", l);
+ bch2_btree_path_node_to_text(out,
+ (void *) path->l[l].b,
+ path->cached);
+ prt_printf(out, "\n");
}
}
+ }
- b = READ_ONCE(trans->locking);
- if (b) {
- path = &trans->paths[trans->locking_path_idx];
- prt_printf(out, " locking path %u %c l=%u %c %s:",
- trans->locking_path_idx,
- path->cached ? 'c' : 'b',
- trans->locking_level,
- lock_types[trans->locking_lock_type],
- bch2_btree_ids[trans->locking_btree_id]);
- bch2_bpos_to_text(out, trans->locking_pos);
-
- prt_printf(out, " node ");
- bch2_btree_path_node_to_text(out,
- (void *) b, path->cached);
- prt_printf(out, "\n");
- }
+ b = READ_ONCE(trans->locking);
+ if (b) {
+ path = &trans->paths[trans->locking_path_idx];
+ prt_printf(out, " locking path %u %c l=%u %c %s:",
+ trans->locking_path_idx,
+ path->cached ? 'c' : 'b',
+ trans->locking_level,
+ lock_types[trans->locking_lock_type],
+ bch2_btree_ids[trans->locking_btree_id]);
+ bch2_bpos_to_text(out, trans->locking_pos);
+
+ prt_printf(out, " node ");
+ bch2_btree_path_node_to_text(out,
+ (void *) b, path->cached);
+ prt_printf(out, "\n");
}
- mutex_unlock(&c->btree_trans_lock);
-#endif
}
+#endif
void bch2_fs_btree_iter_exit(struct bch_fs *c)
{
diff --git a/fs/bcachefs/btree_iter.h b/fs/bcachefs/btree_iter.h
index 83587383a41f..39f241e25881 100644
--- a/fs/bcachefs/btree_iter.h
+++ b/fs/bcachefs/btree_iter.h
@@ -440,7 +440,7 @@ void bch2_trans_exit(struct btree_trans *);
#define bch2_trans_init(...) __bch2_trans_init(__VA_ARGS__, __func__)
-void bch2_btree_trans_to_text(struct printbuf *, struct bch_fs *);
+void bch2_btree_trans_to_text(struct printbuf *, struct btree_trans *);
void bch2_fs_btree_iter_exit(struct bch_fs *);
int bch2_fs_btree_iter_init(struct bch_fs *);
diff --git a/fs/bcachefs/btree_types.h b/fs/bcachefs/btree_types.h
index ede5661b62a5..4f3e1086a86b 100644
--- a/fs/bcachefs/btree_types.h
+++ b/fs/bcachefs/btree_types.h
@@ -386,7 +386,7 @@ struct btree_trans {
u8 locking_btree_id;
u8 locking_level;
u8 locking_lock_type;
- pid_t pid;
+ struct task_struct *task;
int srcu_idx;
u8 nr_sorted;
diff --git a/fs/bcachefs/debug.c b/fs/bcachefs/debug.c
index 878f4e541f83..0f25b75e3de7 100644
--- a/fs/bcachefs/debug.c
+++ b/fs/bcachefs/debug.c
@@ -529,6 +529,78 @@ static const struct file_operations cached_btree_nodes_ops = {
.read = bch2_cached_btree_nodes_read,
};
+#ifdef CONFIG_BCACHEFS_DEBUG_TRANSACTIONS
+static int prt_backtrace(struct printbuf *out, struct task_struct *task)
+{
+ unsigned long entries[32];
+ unsigned i, nr_entries;
+ int ret;
+
+ ret = down_read_killable(&task->signal->exec_update_lock);
+ if (ret)
+ return ret;
+
+ nr_entries = stack_trace_save_tsk(task, entries, ARRAY_SIZE(entries), 0);
+ for (i = 0; i < nr_entries; i++) {
+ prt_printf(out, "[<0>] %pB", (void *)entries[i]);
+ prt_newline(out);
+ }
+
+ up_read(&task->signal->exec_update_lock);
+ return 0;
+}
+
+static ssize_t bch2_btree_transactions_read(struct file *file, char __user *buf,
+ size_t size, loff_t *ppos)
+{
+ struct dump_iter *i = file->private_data;
+ struct bch_fs *c = i->c;
+ struct btree_trans *trans;
+ int err;
+
+ i->ubuf = buf;
+ i->size = size;
+ i->ret = 0;
+
+ mutex_lock(&c->btree_trans_lock);
+ list_for_each_entry(trans, &c->btree_trans_list, list) {
+ if (trans->task->pid <= i->iter)
+ continue;
+
+ err = flush_buf(i);
+ if (err)
+ return err;
+
+ if (!i->size)
+ break;
+
+ bch2_btree_trans_to_text(&i->buf, trans);
+
+ prt_printf(&i->buf, "backtrace:");
+ prt_newline(&i->buf);
+ printbuf_indent_add(&i->buf, 2);
+ prt_backtrace(&i->buf, trans->task);
+ printbuf_indent_sub(&i->buf, 2);
+ prt_newline(&i->buf);
+
+ i->iter = trans->task->pid;
+ }
+ mutex_unlock(&c->btree_trans_lock);
+
+ if (i->buf.allocation_failure)
+ return -ENOMEM;
+
+ return i->ret;
+}
+
+static const struct file_operations btree_transactions_ops = {
+ .owner = THIS_MODULE,
+ .open = bch2_dump_open,
+ .release = bch2_dump_release,
+ .read = bch2_btree_transactions_read,
+};
+#endif /* CONFIG_BCACHEFS_DEBUG_TRANSACTIONS */
+
static ssize_t bch2_journal_pins_read(struct file *file, char __user *buf,
size_t size, loff_t *ppos)
{
@@ -588,6 +660,11 @@ void bch2_fs_debug_init(struct bch_fs *c)
debugfs_create_file("cached_btree_nodes", 0400, c->fs_debug_dir,
c->btree_debug, &cached_btree_nodes_ops);
+#ifdef CONFIG_BCACHEFS_DEBUG_TRANSACTIONS
+ debugfs_create_file("btree_transactions", 0400, c->fs_debug_dir,
+ c->btree_debug, &btree_transactions_ops);
+#endif
+
debugfs_create_file("journal_pins", 0400, c->fs_debug_dir,
c->btree_debug, &journal_pins_ops);
diff --git a/fs/bcachefs/opts.c b/fs/bcachefs/opts.c
index 5540d5d98d84..98568f21d6d0 100644
--- a/fs/bcachefs/opts.c
+++ b/fs/bcachefs/opts.c
@@ -33,6 +33,7 @@ const char * const bch2_sb_compat[] = {
const char * const bch2_btree_ids[] = {
BCH_BTREE_IDS()
+ "interior btree node",
NULL
};
diff --git a/fs/bcachefs/sysfs.c b/fs/bcachefs/sysfs.c
index b2d6a5c49a4d..173289c34de0 100644
--- a/fs/bcachefs/sysfs.c
+++ b/fs/bcachefs/sysfs.c
@@ -181,7 +181,6 @@ read_attribute(journal_debug);
read_attribute(btree_updates);
read_attribute(btree_cache);
read_attribute(btree_key_cache);
-read_attribute(btree_transactions);
read_attribute(stripes_heap);
read_attribute(open_buckets);
read_attribute(write_points);
@@ -420,9 +419,6 @@ SHOW(bch2_fs)
if (attr == &sysfs_btree_key_cache)
bch2_btree_key_cache_to_text(out, &c->btree_key_cache);
- if (attr == &sysfs_btree_transactions)
- bch2_btree_trans_to_text(out, c);
-
if (attr == &sysfs_stripes_heap)
bch2_stripes_heap_to_text(out, c);
@@ -621,7 +617,6 @@ struct attribute *bch2_fs_internal_files[] = {
&sysfs_btree_updates,
&sysfs_btree_cache,
&sysfs_btree_key_cache,
- &sysfs_btree_transactions,
&sysfs_new_stripes,
&sysfs_stripes_heap,
&sysfs_open_buckets,