Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bcachefs: Ensure bch2_btree_node_get() calls relock() after unlock()

Fix a bug where bch2_btree_node_get() might call bch2_trans_unlock() (in
fill) without calling bch2_trans_relock(); this is a bug when it's done
in the core btree code.

Also, twea bch2_btree_node_mem_alloc() to drop btree locks before doing
a blocking memory allocation.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>

+19 -12
+19 -12
fs/bcachefs/btree_cache.c
··· 587 587 goto got_node; 588 588 } 589 589 590 - b = __btree_node_mem_alloc(c, __GFP_NOWARN); 590 + b = __btree_node_mem_alloc(c, GFP_NOWAIT|__GFP_NOWARN); 591 591 if (!b) { 592 592 mutex_unlock(&bc->lock); 593 + bch2_trans_unlock(trans); 593 594 b = __btree_node_mem_alloc(c, GFP_KERNEL); 594 595 if (!b) 595 596 goto err; ··· 619 618 620 619 mutex_unlock(&bc->lock); 621 620 622 - if (btree_node_data_alloc(c, b, __GFP_NOWARN|GFP_KERNEL)) 623 - goto err; 621 + if (btree_node_data_alloc(c, b, GFP_NOWAIT|__GFP_NOWARN)) { 622 + bch2_trans_unlock(trans); 623 + if (btree_node_data_alloc(c, b, GFP_KERNEL|__GFP_NOWARN)) 624 + goto err; 625 + } 624 626 625 627 mutex_lock(&bc->lock); 626 628 bc->used++; ··· 816 812 struct btree_cache *bc = &c->btree_cache; 817 813 struct btree *b; 818 814 struct bset_tree *t; 815 + bool need_relock = false; 819 816 int ret; 820 817 821 818 EBUG_ON(level >= BTREE_MAX_DEPTH); ··· 830 825 */ 831 826 b = bch2_btree_node_fill(trans, path, k, path->btree_id, 832 827 level, lock_type, true); 828 + need_relock = true; 833 829 834 830 /* We raced and found the btree node in the cache */ 835 831 if (!b) ··· 869 863 870 864 six_unlock_type(&b->c.lock, lock_type); 871 865 bch2_trans_unlock(trans); 866 + need_relock = true; 872 867 873 868 bch2_btree_node_wait_on_read(b); 874 869 ··· 877 870 * should_be_locked is not set on this path yet, so we need to 878 871 * relock it specifically: 879 872 */ 880 - if (trans) { 881 - int ret = bch2_trans_relock(trans) ?: 882 - bch2_btree_path_relock_intent(trans, path); 883 - if (ret) { 884 - BUG_ON(!trans->restarted); 885 - return ERR_PTR(ret); 886 - } 887 - } 888 - 889 873 if (!six_relock_type(&b->c.lock, lock_type, seq)) 890 874 goto retry; 875 + } 876 + 877 + if (unlikely(need_relock)) { 878 + int ret = bch2_trans_relock(trans) ?: 879 + bch2_btree_path_relock_intent(trans, path); 880 + if (ret) { 881 + six_unlock_type(&b->c.lock, lock_type); 882 + return ERR_PTR(ret); 883 + } 891 884 } 892 885 893 886 prefetch(b->aux_data);