Commit 677bdb73 authored by Alan Huang's avatar Alan Huang Committed by Kent Overstreet
Browse files

bcachefs: Fix deadlock

This fixes two deadlocks:

1.pcpu_alloc_mutex involved one as pointed by syzbot[1]
2.recursion deadlock.

The root cause is that we hold the bc lock during alloc_percpu, fix it
by following the pattern used by __btree_node_mem_alloc().

[1] https://lore.kernel.org/all/66f97d9a.050a0220.6bad9.001d.GAE@google.com/T/



Reported-by: default avatar <syzbot+fe63f377148a6371a9db@syzkaller.appspotmail.com>
Tested-by: default avatar <syzbot+fe63f377148a6371a9db@syzkaller.appspotmail.com>
Signed-off-by: default avatarAlan Huang <mmpgouride@gmail.com>
Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent 7909d1fb
Loading
Loading
Loading
Loading
+5 −4
Original line number Diff line number Diff line
@@ -203,7 +203,7 @@ struct btree *__bch2_btree_node_mem_alloc(struct bch_fs *c)
		return NULL;
	}

	bch2_btree_lock_init(&b->c, 0);
	bch2_btree_lock_init(&b->c, 0, GFP_KERNEL);

	__bch2_btree_node_to_freelist(bc, b);
	return b;
@@ -795,17 +795,18 @@ struct btree *bch2_btree_node_mem_alloc(struct btree_trans *trans, bool pcpu_rea
		}

	b = __btree_node_mem_alloc(c, GFP_NOWAIT|__GFP_NOWARN);
	if (!b) {
	if (b) {
		bch2_btree_lock_init(&b->c, pcpu_read_locks ? SIX_LOCK_INIT_PCPU : 0, GFP_NOWAIT);
	} else {
		mutex_unlock(&bc->lock);
		bch2_trans_unlock(trans);
		b = __btree_node_mem_alloc(c, GFP_KERNEL);
		if (!b)
			goto err;
		bch2_btree_lock_init(&b->c, pcpu_read_locks ? SIX_LOCK_INIT_PCPU : 0, GFP_KERNEL);
		mutex_lock(&bc->lock);
	}

	bch2_btree_lock_init(&b->c, pcpu_read_locks ? SIX_LOCK_INIT_PCPU : 0);

	BUG_ON(!six_trylock_intent(&b->c.lock));
	BUG_ON(!six_trylock_write(&b->c.lock));

+1 −1
Original line number Diff line number Diff line
@@ -156,7 +156,7 @@ bkey_cached_alloc(struct btree_trans *trans, struct btree_path *path, unsigned k
	}

	if (ck) {
		bch2_btree_lock_init(&ck->c, pcpu_readers ? SIX_LOCK_INIT_PCPU : 0);
		bch2_btree_lock_init(&ck->c, pcpu_readers ? SIX_LOCK_INIT_PCPU : 0, GFP_KERNEL);
		ck->c.cached = true;
		goto lock;
	}
+3 −2
Original line number Diff line number Diff line
@@ -7,9 +7,10 @@
static struct lock_class_key bch2_btree_node_lock_key;

void bch2_btree_lock_init(struct btree_bkey_cached_common *b,
			  enum six_lock_init_flags flags)
			  enum six_lock_init_flags flags,
			  gfp_t gfp)
{
	__six_lock_init(&b->lock, "b->c.lock", &bch2_btree_node_lock_key, flags);
	__six_lock_init(&b->lock, "b->c.lock", &bch2_btree_node_lock_key, flags, gfp);
	lockdep_set_notrack_class(&b->lock);
}

+1 −1
Original line number Diff line number Diff line
@@ -13,7 +13,7 @@
#include "btree_iter.h"
#include "six.h"

void bch2_btree_lock_init(struct btree_bkey_cached_common *, enum six_lock_init_flags);
void bch2_btree_lock_init(struct btree_bkey_cached_common *, enum six_lock_init_flags, gfp_t gfp);

void bch2_trans_unlock_noassert(struct btree_trans *);
void bch2_trans_unlock_write(struct btree_trans *);
+3 −2
Original line number Diff line number Diff line
@@ -850,7 +850,8 @@ void six_lock_exit(struct six_lock *lock)
EXPORT_SYMBOL_GPL(six_lock_exit);

void __six_lock_init(struct six_lock *lock, const char *name,
		     struct lock_class_key *key, enum six_lock_init_flags flags)
		     struct lock_class_key *key, enum six_lock_init_flags flags,
		     gfp_t gfp)
{
	atomic_set(&lock->state, 0);
	raw_spin_lock_init(&lock->wait_lock);
@@ -873,7 +874,7 @@ void __six_lock_init(struct six_lock *lock, const char *name,
		 * failure if they wish by checking lock->readers, but generally
		 * will not want to treat it as an error.
		 */
		lock->readers = alloc_percpu(unsigned);
		lock->readers = alloc_percpu_gfp(unsigned, gfp);
	}
#endif
}
Loading