ubi: fastmap: Fix missed fm_anchor PEB in wear-leveling after disabling fastmap
authorZhihao Cheng <chengzhihao1@huawei.com>
Tue, 9 Aug 2022 07:06:19 +0000 (15:06 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 11 Mar 2023 12:57:25 +0000 (13:57 +0100)
[ Upstream commit 76f9476ece445a07aeb72df9d896cd563fb5b50f ]

After disabling fastmap(ubi->fm_disabled = 1), fastmap won't be updated,
fm_anchor PEB is missed being scheduled for erasing. Besides, fm_anchor
PEB may have smallest erase count, it doesn't participate wear-leveling.
The difference of erase count between fm_anchor PEB and other PEBs will
be larger and larger later on.

In which situation fastmap can be disabled? Initially, we have an UBI
image with fastmap. Then the image will be atttached without module
parameter 'fm_autoconvert', ubi turns to full scanning mode in one
random attaching process(eg. bad fastmap caused by powercut), ubi
fastmap is disabled since then.

Fix it by not getting fm_anchor if fastmap is disabled in
ubi_refill_pools().

Fetch a reproducer in [Link].

Link: https://bugzilla.kernel.org/show_bug.cgi?id=216341
Fixes: 4b68bf9a69d22d ("ubi: Select fastmap anchor PEBs considering ...")
Signed-off-by: Zhihao Cheng <chengzhihao1@huawei.com>
Signed-off-by: Richard Weinberger <richard@nod.at>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/mtd/ubi/fastmap-wl.c

index 053ab52668e8bf3c1b8f39b8430e56fbdd9161a5..69592be33adfcc7480cf4a2e2c7161d8c759fbc8 100644 (file)
@@ -146,13 +146,15 @@ void ubi_refill_pools(struct ubi_device *ubi)
        if (ubi->fm_anchor) {
                wl_tree_add(ubi->fm_anchor, &ubi->free);
                ubi->free_count++;
+               ubi->fm_anchor = NULL;
        }
 
-       /*
-        * All available PEBs are in ubi->free, now is the time to get
-        * the best anchor PEBs.
-        */
-       ubi->fm_anchor = ubi_wl_get_fm_peb(ubi, 1);
+       if (!ubi->fm_disabled)
+               /*
+                * All available PEBs are in ubi->free, now is the time to get
+                * the best anchor PEBs.
+                */
+               ubi->fm_anchor = ubi_wl_get_fm_peb(ubi, 1);
 
        for (;;) {
                enough = 0;