Commit d880a438 authored by Kent Overstreet's avatar Kent Overstreet

bcachefs: Further improve btree_update_to_text()

Print start and end level of the btree update; also a bit of cleanup.
Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent 9fb3036f
...@@ -26,9 +26,9 @@ ...@@ -26,9 +26,9 @@
#include <linux/random.h> #include <linux/random.h>
const char * const bch2_btree_update_modes[] = { static const char * const bch2_btree_update_modes[] = {
#define x(t) #t, #define x(t) #t,
BCH_WATERMARKS() BTREE_UPDATE_MODES()
#undef x #undef x
NULL NULL
}; };
...@@ -850,15 +850,17 @@ static void btree_update_updated_node(struct btree_update *as, struct btree *b) ...@@ -850,15 +850,17 @@ static void btree_update_updated_node(struct btree_update *as, struct btree *b)
{ {
struct bch_fs *c = as->c; struct bch_fs *c = as->c;
mutex_lock(&c->btree_interior_update_lock);
list_add_tail(&as->unwritten_list, &c->btree_interior_updates_unwritten);
BUG_ON(as->mode != BTREE_UPDATE_none); BUG_ON(as->mode != BTREE_UPDATE_none);
BUG_ON(as->update_level_end < b->c.level);
BUG_ON(!btree_node_dirty(b)); BUG_ON(!btree_node_dirty(b));
BUG_ON(!b->c.level); BUG_ON(!b->c.level);
mutex_lock(&c->btree_interior_update_lock);
list_add_tail(&as->unwritten_list, &c->btree_interior_updates_unwritten);
as->mode = BTREE_UPDATE_node; as->mode = BTREE_UPDATE_node;
as->b = b; as->b = b;
as->update_level_end = b->c.level;
set_btree_node_write_blocked(b); set_btree_node_write_blocked(b);
list_add(&as->write_blocked_list, &b->write_blocked); list_add(&as->write_blocked_list, &b->write_blocked);
...@@ -1100,7 +1102,7 @@ static void bch2_btree_update_done(struct btree_update *as, struct btree_trans * ...@@ -1100,7 +1102,7 @@ static void bch2_btree_update_done(struct btree_update *as, struct btree_trans *
static struct btree_update * static struct btree_update *
bch2_btree_update_start(struct btree_trans *trans, struct btree_path *path, bch2_btree_update_start(struct btree_trans *trans, struct btree_path *path,
unsigned level, bool split, unsigned flags) unsigned level_start, bool split, unsigned flags)
{ {
struct bch_fs *c = trans->c; struct bch_fs *c = trans->c;
struct btree_update *as; struct btree_update *as;
...@@ -1108,7 +1110,7 @@ bch2_btree_update_start(struct btree_trans *trans, struct btree_path *path, ...@@ -1108,7 +1110,7 @@ bch2_btree_update_start(struct btree_trans *trans, struct btree_path *path,
int disk_res_flags = (flags & BCH_TRANS_COMMIT_no_enospc) int disk_res_flags = (flags & BCH_TRANS_COMMIT_no_enospc)
? BCH_DISK_RESERVATION_NOFAIL : 0; ? BCH_DISK_RESERVATION_NOFAIL : 0;
unsigned nr_nodes[2] = { 0, 0 }; unsigned nr_nodes[2] = { 0, 0 };
unsigned update_level = level; unsigned level_end = level_start;
enum bch_watermark watermark = flags & BCH_WATERMARK_MASK; enum bch_watermark watermark = flags & BCH_WATERMARK_MASK;
int ret = 0; int ret = 0;
u32 restart_count = trans->restart_count; u32 restart_count = trans->restart_count;
...@@ -1140,17 +1142,17 @@ bch2_btree_update_start(struct btree_trans *trans, struct btree_path *path, ...@@ -1140,17 +1142,17 @@ bch2_btree_update_start(struct btree_trans *trans, struct btree_path *path,
} }
while (1) { while (1) {
nr_nodes[!!update_level] += 1 + split; nr_nodes[!!level_end] += 1 + split;
update_level++; level_end++;
ret = bch2_btree_path_upgrade(trans, path, update_level + 1); ret = bch2_btree_path_upgrade(trans, path, level_end + 1);
if (ret) if (ret)
return ERR_PTR(ret); return ERR_PTR(ret);
if (!btree_path_node(path, update_level)) { if (!btree_path_node(path, level_end)) {
/* Allocating new root? */ /* Allocating new root? */
nr_nodes[1] += split; nr_nodes[1] += split;
update_level = BTREE_MAX_DEPTH; level_end = BTREE_MAX_DEPTH;
break; break;
} }
...@@ -1158,11 +1160,11 @@ bch2_btree_update_start(struct btree_trans *trans, struct btree_path *path, ...@@ -1158,11 +1160,11 @@ bch2_btree_update_start(struct btree_trans *trans, struct btree_path *path,
* Always check for space for two keys, even if we won't have to * Always check for space for two keys, even if we won't have to
* split at prior level - it might have been a merge instead: * split at prior level - it might have been a merge instead:
*/ */
if (bch2_btree_node_insert_fits(path->l[update_level].b, if (bch2_btree_node_insert_fits(path->l[level_end].b,
BKEY_BTREE_PTR_U64s_MAX * 2)) BKEY_BTREE_PTR_U64s_MAX * 2))
break; break;
split = path->l[update_level].b->nr.live_u64s > BTREE_SPLIT_THRESHOLD(c); split = path->l[level_end].b->nr.live_u64s > BTREE_SPLIT_THRESHOLD(c);
} }
if (!down_read_trylock(&c->gc_lock)) { if (!down_read_trylock(&c->gc_lock)) {
...@@ -1176,14 +1178,15 @@ bch2_btree_update_start(struct btree_trans *trans, struct btree_path *path, ...@@ -1176,14 +1178,15 @@ bch2_btree_update_start(struct btree_trans *trans, struct btree_path *path,
as = mempool_alloc(&c->btree_interior_update_pool, GFP_NOFS); as = mempool_alloc(&c->btree_interior_update_pool, GFP_NOFS);
memset(as, 0, sizeof(*as)); memset(as, 0, sizeof(*as));
closure_init(&as->cl, NULL); closure_init(&as->cl, NULL);
as->c = c; as->c = c;
as->start_time = start_time; as->start_time = start_time;
as->ip_started = _RET_IP_; as->ip_started = _RET_IP_;
as->mode = BTREE_UPDATE_none; as->mode = BTREE_UPDATE_none;
as->watermark = watermark; as->watermark = watermark;
as->took_gc_lock = true; as->took_gc_lock = true;
as->btree_id = path->btree_id; as->btree_id = path->btree_id;
as->update_level = update_level; as->update_level_start = level_start;
as->update_level_end = level_end;
INIT_LIST_HEAD(&as->list); INIT_LIST_HEAD(&as->list);
INIT_LIST_HEAD(&as->unwritten_list); INIT_LIST_HEAD(&as->unwritten_list);
INIT_LIST_HEAD(&as->write_blocked_list); INIT_LIST_HEAD(&as->write_blocked_list);
...@@ -1373,12 +1376,12 @@ static void bch2_insert_fixup_btree_ptr(struct btree_update *as, ...@@ -1373,12 +1376,12 @@ static void bch2_insert_fixup_btree_ptr(struct btree_update *as,
} }
static void static void
__bch2_btree_insert_keys_interior(struct btree_update *as, bch2_btree_insert_keys_interior(struct btree_update *as,
struct btree_trans *trans, struct btree_trans *trans,
struct btree_path *path, struct btree_path *path,
struct btree *b, struct btree *b,
struct btree_node_iter node_iter, struct btree_node_iter node_iter,
struct keylist *keys) struct keylist *keys)
{ {
struct bkey_i *insert = bch2_keylist_front(keys); struct bkey_i *insert = bch2_keylist_front(keys);
struct bkey_packed *k; struct bkey_packed *k;
...@@ -1534,7 +1537,7 @@ static void btree_split_insert_keys(struct btree_update *as, ...@@ -1534,7 +1537,7 @@ static void btree_split_insert_keys(struct btree_update *as,
bch2_btree_node_iter_init(&node_iter, b, &bch2_keylist_front(keys)->k.p); bch2_btree_node_iter_init(&node_iter, b, &bch2_keylist_front(keys)->k.p);
__bch2_btree_insert_keys_interior(as, trans, path, b, node_iter, keys); bch2_btree_insert_keys_interior(as, trans, path, b, node_iter, keys);
BUG_ON(bch2_btree_node_check_topology(trans, b)); BUG_ON(bch2_btree_node_check_topology(trans, b));
} }
...@@ -1714,27 +1717,6 @@ static int btree_split(struct btree_update *as, struct btree_trans *trans, ...@@ -1714,27 +1717,6 @@ static int btree_split(struct btree_update *as, struct btree_trans *trans,
goto out; goto out;
} }
static void
bch2_btree_insert_keys_interior(struct btree_update *as,
struct btree_trans *trans,
struct btree_path *path,
struct btree *b,
struct keylist *keys)
{
struct btree_path *linked;
unsigned i;
__bch2_btree_insert_keys_interior(as, trans, path, b,
path->l[b->c.level].iter, keys);
btree_update_updated_node(as, b);
trans_for_each_path_with_node(trans, b, linked, i)
bch2_btree_node_iter_peek(&linked->l[b->c.level].iter, b);
bch2_trans_verify_paths(trans);
}
/** /**
* bch2_btree_insert_node - insert bkeys into a given btree node * bch2_btree_insert_node - insert bkeys into a given btree node
* *
...@@ -1755,7 +1737,8 @@ static int bch2_btree_insert_node(struct btree_update *as, struct btree_trans *t ...@@ -1755,7 +1737,8 @@ static int bch2_btree_insert_node(struct btree_update *as, struct btree_trans *t
struct keylist *keys) struct keylist *keys)
{ {
struct bch_fs *c = as->c; struct bch_fs *c = as->c;
struct btree_path *path = trans->paths + path_idx; struct btree_path *path = trans->paths + path_idx, *linked;
unsigned i;
int old_u64s = le16_to_cpu(btree_bset_last(b)->u64s); int old_u64s = le16_to_cpu(btree_bset_last(b)->u64s);
int old_live_u64s = b->nr.live_u64s; int old_live_u64s = b->nr.live_u64s;
int live_u64s_added, u64s_added; int live_u64s_added, u64s_added;
...@@ -1784,7 +1767,13 @@ static int bch2_btree_insert_node(struct btree_update *as, struct btree_trans *t ...@@ -1784,7 +1767,13 @@ static int bch2_btree_insert_node(struct btree_update *as, struct btree_trans *t
return ret; return ret;
} }
bch2_btree_insert_keys_interior(as, trans, path, b, keys); bch2_btree_insert_keys_interior(as, trans, path, b,
path->l[b->c.level].iter, keys);
trans_for_each_path_with_node(trans, b, linked, i)
bch2_btree_node_iter_peek(&linked->l[b->c.level].iter, b);
bch2_trans_verify_paths(trans);
live_u64s_added = (int) b->nr.live_u64s - old_live_u64s; live_u64s_added = (int) b->nr.live_u64s - old_live_u64s;
u64s_added = (int) le16_to_cpu(btree_bset_last(b)->u64s) - old_u64s; u64s_added = (int) le16_to_cpu(btree_bset_last(b)->u64s) - old_u64s;
...@@ -1798,6 +1787,7 @@ static int bch2_btree_insert_node(struct btree_update *as, struct btree_trans *t ...@@ -1798,6 +1787,7 @@ static int bch2_btree_insert_node(struct btree_update *as, struct btree_trans *t
bch2_maybe_compact_whiteouts(c, b)) bch2_maybe_compact_whiteouts(c, b))
bch2_trans_node_reinit_iter(trans, b); bch2_trans_node_reinit_iter(trans, b);
btree_update_updated_node(as, b);
bch2_btree_node_unlock_write(trans, path, b); bch2_btree_node_unlock_write(trans, path, b);
BUG_ON(bch2_btree_node_check_topology(trans, b)); BUG_ON(bch2_btree_node_check_topology(trans, b));
...@@ -1807,7 +1797,7 @@ static int bch2_btree_insert_node(struct btree_update *as, struct btree_trans *t ...@@ -1807,7 +1797,7 @@ static int bch2_btree_insert_node(struct btree_update *as, struct btree_trans *t
* We could attempt to avoid the transaction restart, by calling * We could attempt to avoid the transaction restart, by calling
* bch2_btree_path_upgrade() and allocating more nodes: * bch2_btree_path_upgrade() and allocating more nodes:
*/ */
if (b->c.level >= as->update_level) { if (b->c.level >= as->update_level_end) {
trace_and_count(c, trans_restart_split_race, trans, _THIS_IP_, b); trace_and_count(c, trans_restart_split_race, trans, _THIS_IP_, b);
return btree_trans_restart(trans, BCH_ERR_transaction_restart_split_race); return btree_trans_restart(trans, BCH_ERR_transaction_restart_split_race);
} }
...@@ -2519,9 +2509,11 @@ void bch2_btree_root_alloc_fake(struct bch_fs *c, enum btree_id id, unsigned lev ...@@ -2519,9 +2509,11 @@ void bch2_btree_root_alloc_fake(struct bch_fs *c, enum btree_id id, unsigned lev
static void bch2_btree_update_to_text(struct printbuf *out, struct btree_update *as) static void bch2_btree_update_to_text(struct printbuf *out, struct btree_update *as)
{ {
prt_printf(out, "%ps: btree=%s watermark=%s mode=%s nodes_written=%u cl.remaining=%u journal_seq=%llu\n", prt_printf(out, "%ps: btree=%s l=%u-%u watermark=%s mode=%s nodes_written=%u cl.remaining=%u journal_seq=%llu\n",
(void *) as->ip_started, (void *) as->ip_started,
bch2_btree_id_str(as->btree_id), bch2_btree_id_str(as->btree_id),
as->update_level_start,
as->update_level_end,
bch2_watermarks[as->watermark], bch2_watermarks[as->watermark],
bch2_btree_update_modes[as->mode], bch2_btree_update_modes[as->mode],
as->nodes_written, as->nodes_written,
......
...@@ -57,7 +57,8 @@ struct btree_update { ...@@ -57,7 +57,8 @@ struct btree_update {
unsigned took_gc_lock:1; unsigned took_gc_lock:1;
enum btree_id btree_id; enum btree_id btree_id;
unsigned update_level; unsigned update_level_start;
unsigned update_level_end;
struct disk_reservation disk_res; struct disk_reservation disk_res;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment