]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
mtd: core: skip badblocks increment for blocks already known bad
authorWang Zhaolong <wangzhaolong@huaweicloud.com>
Tue, 2 Sep 2025 09:27:32 +0000 (17:27 +0800)
committerMiquel Raynal <miquel.raynal@bootlin.com>
Thu, 11 Sep 2025 15:34:15 +0000 (17:34 +0200)
Repeatedly marking the same eraseblock bad inflates
mtd->ecc_stats.badblocks because mtd_block_markbad() unconditionally
increments the counter on success, while some implementations (e.g.
NAND) return 0 both when the block was already bad and when it has just
been marked[1].

Fix by checking if the block is already bad before calling
->_block_markbad() when _block_isbad is available. Only skip the counter
increment when we can confirm the block was already bad. In all other
cases continue incrementing the counter.

This keeps the logic centralized in mtdcore without requiring driver
changes.

Link: https://lore.kernel.org/all/ef573188-9815-4a6b-bad1-3d8ff7c9b16f@huaweicloud.com/
Signed-off-by: Wang Zhaolong <wangzhaolong@huaweicloud.com>
Reviewed-by: Zhihao Cheng <chengzhihao1@huawei.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
drivers/mtd/mtdcore.c

index fe42f20fefaca89344a014ee46b176748b1680f5..64808493b4f5ead22222616a732b5544c6d98539 100644 (file)
@@ -2389,6 +2389,7 @@ EXPORT_SYMBOL_GPL(mtd_block_isbad);
 int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs)
 {
        struct mtd_info *master = mtd_get_master(mtd);
+       loff_t moffs;
        int ret;
 
        if (!master->_block_markbad)
@@ -2401,7 +2402,15 @@ int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs)
        if (mtd->flags & MTD_SLC_ON_MLC_EMULATION)
                ofs = (loff_t)mtd_div_by_eb(ofs, mtd) * master->erasesize;
 
-       ret = master->_block_markbad(master, mtd_get_master_ofs(mtd, ofs));
+       moffs = mtd_get_master_ofs(mtd, ofs);
+
+       if (master->_block_isbad) {
+               ret = master->_block_isbad(master, moffs);
+               if (ret > 0)
+                       return 0;
+       }
+
+       ret = master->_block_markbad(master, moffs);
        if (ret)
                return ret;