From c82c2054cd7e7483ddf5f45ba0712378cdedeb9d Mon Sep 17 00:00:00 2001 From: Coly Li Date: Apr 13 2024 06:51:56 +0000 Subject: bcache: fixup btree_cache_wait list damage (git-fixes). --- diff --git a/patches.suse/bcache-fixup-btree_cache_wait-list-damage-f085.patch b/patches.suse/bcache-fixup-btree_cache_wait-list-damage-f085.patch new file mode 100644 index 0000000..bb46137 --- /dev/null +++ b/patches.suse/bcache-fixup-btree_cache_wait-list-damage-f085.patch @@ -0,0 +1,119 @@ +From f0854489fc07d2456f7cc71a63f4faf9c716ffbe Mon Sep 17 00:00:00 2001 +From: Mingzhe Zou +Date: Thu, 15 Jun 2023 20:12:23 +0800 +Subject: [PATCH] bcache: fixup btree_cache_wait list damage +Git-commit: f0854489fc07d2456f7cc71a63f4faf9c716ffbe +Patch-mainline: v6.5-rc1 +References: git-fixes + +We get a kernel crash about "list_add corruption. next->prev should be +prev (ffff9c801bc01210), but was ffff9c77b688237c. +(next=ffffae586d8afe68)." + +crash> struct list_head 0xffff9c801bc01210 +struct list_head { + next = 0xffffae586d8afe68, + prev = 0xffffae586d8afe68 +} +crash> struct list_head 0xffff9c77b688237c +struct list_head { + next = 0x0, + prev = 0x0 +} +crash> struct list_head 0xffffae586d8afe68 +struct list_head struct: invalid kernel virtual address: ffffae586d8afe68 type: "gdb_readmem_callback" +Cannot access memory at address 0xffffae586d8afe68 + +[230469.019492] Call Trace: +[230469.032041] prepare_to_wait+0x8a/0xb0 +[230469.044363] ? bch_btree_keys_free+0x6c/0xc0 [escache] +[230469.056533] mca_cannibalize_lock+0x72/0x90 [escache] +[230469.068788] mca_alloc+0x2ae/0x450 [escache] +[230469.080790] bch_btree_node_get+0x136/0x2d0 [escache] +[230469.092681] bch_btree_check_thread+0x1e1/0x260 [escache] +[230469.104382] ? finish_wait+0x80/0x80 +[230469.115884] ? bch_btree_check_recurse+0x1a0/0x1a0 [escache] +[230469.127259] kthread+0x112/0x130 +[230469.138448] ? kthread_flush_work_fn+0x10/0x10 +[230469.149477] ret_from_fork+0x35/0x40 + +bch_btree_check_thread() and bch_dirty_init_thread() may call +mca_cannibalize() to cannibalize other cached btree nodes. Only one thread +can do it at a time, so the op of other threads will be added to the +btree_cache_wait list. + +We must call finish_wait() to remove op from btree_cache_wait before free +it's memory address. Otherwise, the list will be damaged. Also should call +bch_cannibalize_unlock() to release the btree_cache_alloc_lock and wake_up +other waiters. + +Fixes: 8e7102273f59 ("bcache: make bch_btree_check() to be multithreaded") +Fixes: b144e45fc576 ("bcache: make bch_sectors_dirty_init() to be multithreaded") +Cc: stable@vger.kernel.org +Signed-off-by: Mingzhe Zou +Signed-off-by: Coly Li +Link: https://lore.kernel.org/r/20230615121223.22502-7-colyli@suse.de +Signed-off-by: Jens Axboe + +--- + drivers/md/bcache/btree.c | 11 ++++++++++- + drivers/md/bcache/btree.h | 1 + + drivers/md/bcache/writeback.c | 10 ++++++++++ + 3 files changed, 21 insertions(+), 1 deletion(-) + +--- a/drivers/md/bcache/btree.c ++++ b/drivers/md/bcache/btree.c +@@ -885,7 +885,7 @@ static struct btree *mca_cannibalize(str + * cannibalize_bucket() will take. This means every time we unlock the root of + * the btree, we need to release this lock if we have it held. + */ +-static void bch_cannibalize_unlock(struct cache_set *c) ++void bch_cannibalize_unlock(struct cache_set *c) + { + spin_lock(&c->btree_cannibalize_lock); + if (c->btree_cache_alloc_lock == current) { +@@ -1970,6 +1970,15 @@ static int bch_btree_check_thread(void * + c->gc_stats.nodes++; + bch_btree_op_init(&op, 0); + ret = bcache_btree(check_recurse, p, c->root, &op); ++ /* ++ * The op may be added to cache_set's btree_cache_wait ++ * in mca_cannibalize(), must ensure it is removed from ++ * the list and release btree_cache_alloc_lock before ++ * free op memory. ++ * Otherwise, the btree_cache_wait will be damaged. ++ */ ++ bch_cannibalize_unlock(c); ++ finish_wait(&c->btree_cache_wait, &(&op)->wait); + if (ret) + goto out; + } +--- a/drivers/md/bcache/btree.h ++++ b/drivers/md/bcache/btree.h +@@ -282,6 +282,7 @@ void bch_initial_gc_finish(struct cache_ + void bch_moving_gc(struct cache_set *c); + int bch_btree_check(struct cache_set *c); + void bch_initial_mark_key(struct cache_set *c, int level, struct bkey *k); ++void bch_cannibalize_unlock(struct cache_set *c); + + static inline void wake_up_gc(struct cache_set *c) + { +--- a/drivers/md/bcache/writeback.c ++++ b/drivers/md/bcache/writeback.c +@@ -890,6 +890,16 @@ static int bch_root_node_dirty_init(stru + if (ret < 0) + pr_warn("sectors dirty init failed, ret=%d!\n", ret); + ++ /* ++ * The op may be added to cache_set's btree_cache_wait ++ * in mca_cannibalize(), must ensure it is removed from ++ * the list and release btree_cache_alloc_lock before ++ * free op memory. ++ * Otherwise, the btree_cache_wait will be damaged. ++ */ ++ bch_cannibalize_unlock(c); ++ finish_wait(&c->btree_cache_wait, &(&op.op)->wait); ++ + return ret; + } + diff --git a/series.conf b/series.conf index de38029..1b03493 100644 --- a/series.conf +++ b/series.conf @@ -42382,6 +42382,7 @@ patches.suse/bcache-Remove-dead-references-to-cache_readaheads-ccb8.patch patches.suse/bcache-Remove-unnecessary-NULL-point-check-in-node-a-028d.patch patches.suse/bcache-Fix-__bch_btree_node_alloc-to-make-the-failur-80fc.patch + patches.suse/bcache-fixup-btree_cache_wait-list-damage-f085.patch patches.suse/nvme-core-fix-memory-leak-in-dhchap_secret_store.patch patches.suse/nvme-core-fix-memory-leak-in-dhchap_ctrl_secret.patch patches.suse/nvme-core-fix-dev_pm_qos-memleak.patch