diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2022-06-17 20:12:02 -0400 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2023-10-22 17:09:34 -0400 |
commit | 50b13beef09f445e1fb8fbf1e1f852df06baf05a (patch) | |
tree | a6b120f5d24aca22fd26b61d1c259635200a335b /fs | |
parent | 2ed6248ab3a58dbbe5819cbd0e60e4e3a5b72c47 (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>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/bcachefs/bkey_methods.c | 4 | ||||
-rw-r--r-- | fs/bcachefs/btree_iter.c | 109 | ||||
-rw-r--r-- | fs/bcachefs/btree_iter.h | 2 | ||||
-rw-r--r-- | fs/bcachefs/btree_types.h | 2 | ||||
-rw-r--r-- | fs/bcachefs/debug.c | 77 | ||||
-rw-r--r-- | fs/bcachefs/opts.c | 1 | ||||
-rw-r--r-- | fs/bcachefs/sysfs.c | 5 |
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, |