mirror of
https://github.com/torvalds/linux.git
synced 2025-04-12 16:47:42 +00:00
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: syzbot+fe63f377148a6371a9db@syzkaller.appspotmail.com Tested-by: syzbot+fe63f377148a6371a9db@syzkaller.appspotmail.com Signed-off-by: Alan Huang <mmpgouride@gmail.com> Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
parent
7909d1fb90
commit
677bdb7346
@ -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));
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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 *);
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -164,18 +164,19 @@ enum six_lock_init_flags {
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
/**
|
||||
* six_lock_init - initialize a six lock
|
||||
* @lock: lock to initialize
|
||||
* @flags: optional flags, i.e. SIX_LOCK_INIT_PCPU
|
||||
*/
|
||||
#define six_lock_init(lock, flags) \
|
||||
#define six_lock_init(lock, flags, gfp) \
|
||||
do { \
|
||||
static struct lock_class_key __key; \
|
||||
\
|
||||
__six_lock_init((lock), #lock, &__key, flags); \
|
||||
__six_lock_init((lock), #lock, &__key, flags, gfp); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user