bcachefs: Also show when blocked on write locks

This consolidates some of the btree node lock path, so that when we're
blocked taking a write lock on a node it shows up in
bch2_btree_trans_to_text(), along with intent and read locks.

Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
This commit is contained in:
Kent Overstreet 2022-02-15 22:28:37 -05:00 committed by Kent Overstreet
parent 8be1aff009
commit c7ce27328b
5 changed files with 41 additions and 41 deletions

View file

@ -150,7 +150,7 @@ void __bch2_btree_node_lock_write(struct btree_trans *trans, struct btree *b)
else
this_cpu_sub(*b->c.lock.readers, readers);
btree_node_lock_type(trans->c, b, SIX_LOCK_write);
six_lock_write(&b->c.lock, NULL, NULL);
if (!b->c.lock.readers)
atomic64_add(__SIX_VAL(read_lock, readers),
@ -289,9 +289,7 @@ bool __bch2_btree_node_lock(struct btree_trans *trans,
unsigned long ip)
{
struct btree_path *linked, *deadlock_path = NULL;
u64 start_time = local_clock();
unsigned reason = 9;
bool ret;
/* Check if it's safe to block: */
trans_for_each_path(trans, linked) {
@ -368,23 +366,8 @@ bool __bch2_btree_node_lock(struct btree_trans *trans,
return false;
}
if (six_trylock_type(&b->c.lock, type))
return true;
trans->locking_path_idx = path->idx;
trans->locking_pos = pos;
trans->locking_btree_id = path->btree_id;
trans->locking_level = level;
trans->locking = b;
ret = six_lock_type(&b->c.lock, type, should_sleep_fn, p) == 0;
trans->locking = NULL;
if (ret)
bch2_time_stats_update(&trans->c->times[lock_to_time_stat(type)],
start_time);
return ret;
return btree_node_lock_type(trans, path, b, pos, level,
type, should_sleep_fn, p);
}
/* Btree iterator locking: */
@ -3191,6 +3174,7 @@ void bch2_btree_trans_to_text(struct printbuf *out, struct bch_fs *c)
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);
@ -3227,10 +3211,11 @@ void bch2_btree_trans_to_text(struct printbuf *out, struct bch_fs *c)
b = READ_ONCE(trans->locking);
if (b) {
path = &trans->paths[trans->locking_path_idx];
pr_buf(out, " locking path %u %c l=%u %s:",
pr_buf(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);

View file

@ -127,23 +127,35 @@ static inline enum bch_time_stats lock_to_time_stat(enum six_lock_type type)
}
}
/*
* wrapper around six locks that just traces lock contended time
*/
static inline void __btree_node_lock_type(struct bch_fs *c, struct btree *b,
enum six_lock_type type)
static inline bool btree_node_lock_type(struct btree_trans *trans,
struct btree_path *path,
struct btree *b,
struct bpos pos, unsigned level,
enum six_lock_type type,
six_lock_should_sleep_fn should_sleep_fn, void *p)
{
u64 start_time = local_clock();
struct bch_fs *c = trans->c;
u64 start_time;
bool ret;
six_lock_type(&b->c.lock, type, NULL, NULL);
bch2_time_stats_update(&c->times[lock_to_time_stat(type)], start_time);
}
if (six_trylock_type(&b->c.lock, type))
return true;
static inline void btree_node_lock_type(struct bch_fs *c, struct btree *b,
enum six_lock_type type)
{
if (!six_trylock_type(&b->c.lock, type))
__btree_node_lock_type(c, b, type);
start_time = local_clock();
trans->locking_path_idx = path->idx;
trans->locking_pos = pos;
trans->locking_btree_id = path->btree_id;
trans->locking_level = level;
trans->locking_lock_type = type;
trans->locking = b;
ret = six_lock_type(&b->c.lock, type, should_sleep_fn, p) == 0;
trans->locking = NULL;
if (ret)
bch2_time_stats_update(&c->times[lock_to_time_stat(type)], start_time);
return ret;
}
/*

View file

@ -383,6 +383,7 @@ struct btree_trans {
struct bpos locking_pos;
u8 locking_btree_id;
u8 locking_level;
u8 locking_lock_type;
pid_t pid;
int srcu_idx;

View file

@ -607,8 +607,8 @@ static void btree_update_nodes_written(struct btree_update *as)
* we're in journal error state:
*/
btree_node_lock_type(c, b, SIX_LOCK_intent);
btree_node_lock_type(c, b, SIX_LOCK_write);
six_lock_intent(&b->c.lock, NULL, NULL);
six_lock_write(&b->c.lock, NULL, NULL);
mutex_lock(&c->btree_interior_update_lock);
list_del(&as->write_blocked_list);
@ -662,7 +662,7 @@ static void btree_update_nodes_written(struct btree_update *as)
for (i = 0; i < as->nr_new_nodes; i++) {
b = as->new_nodes[i];
btree_node_lock_type(c, b, SIX_LOCK_read);
six_lock_read(&b->c.lock, NULL, NULL);
btree_node_write_if_need(c, b, SIX_LOCK_read);
six_unlock_read(&b->c.lock);
}

View file

@ -169,7 +169,7 @@ static int __btree_node_flush(struct journal *j, struct journal_entry_pin *pin,
struct btree_write *w = container_of(pin, struct btree_write, journal);
struct btree *b = container_of(w, struct btree, writes[i]);
btree_node_lock_type(c, b, SIX_LOCK_read);
six_lock_read(&b->c.lock, NULL, NULL);
bch2_btree_node_write_cond(c, b,
(btree_current_write(b) == w && w->journal.seq == seq));
six_unlock_read(&b->c.lock);
@ -626,8 +626,10 @@ static inline int trans_lock_write(struct btree_trans *trans)
if (have_conflicting_read_lock(trans, i->path))
goto fail;
__btree_node_lock_type(trans->c, insert_l(i)->b,
SIX_LOCK_write);
btree_node_lock_type(trans, i->path,
insert_l(i)->b,
i->path->pos, i->level,
SIX_LOCK_write, NULL, NULL);
}
bch2_btree_node_prep_for_write(trans, i->path, insert_l(i)->b);