From d22d5f47ecb2c4e140c0ee52204f4dd8fd0e85eb Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 10 Jun 2025 11:25:22 +0200 Subject: [PATCH] mtd: nftl: reduce stack usage in NFTL_movebuf() The code in the ntfl write function is rather complex, and it contains a 512 byte on-stack buffer. The combination of these two leads to using more than the per-function stack warning limit in some configurations, especially with KASAN enabled: drivers/mtd/nftlcore.c:673:12: error: stack frame size (1328) exceeds limit (1280) in 'nftl_writeblock' [-Werror,-Wframe-larger-than] Avoid this warning by moving the on-stack buffer into a separate function that only copies one part of the device to another. This does not really help with the total maximum stack usage in the (non-KASAN) normal case, but it does two things: - no single function has more than the warning limit - the complexity goes down, so the parent function ends up spilling few local variables, and the total actually goes down slightly. Signed-off-by: Arnd Bergmann Signed-off-by: Miquel Raynal --- drivers/mtd/nftlcore.c | 43 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c index 64d319e959b23..868aa3d35d091 100644 --- a/drivers/mtd/nftlcore.c +++ b/drivers/mtd/nftlcore.c @@ -228,6 +228,25 @@ static u16 NFTL_findfreeblock(struct NFTLrecord *nftl, int desperate ) return BLOCK_NIL; } +static noinline_for_stack void NFTL_move_block(struct mtd_info *mtd, loff_t src, loff_t dst) +{ + unsigned char movebuf[512]; + struct nftl_oob oob; + size_t retlen; + int ret; + + ret = mtd_read(mtd, src, 512, &retlen, movebuf); + if (ret < 0 && !mtd_is_bitflip(ret)) { + ret = mtd_read(mtd, src, 512, &retlen, movebuf); + if (ret != -EIO) + printk("Error went away on retry.\n"); + } + memset(&oob, 0xff, sizeof(struct nftl_oob)); + oob.b.Status = oob.b.Status1 = SECTOR_USED; + + nftl_write(mtd, dst, 512, &retlen, movebuf, (char *)&oob); +} + static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned pendingblock ) { struct mtd_info *mtd = nftl->mbd.mtd; @@ -389,9 +408,6 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p */ pr_debug("Folding chain %d into unit %d\n", thisVUC, targetEUN); for (block = 0; block < nftl->EraseSize / 512 ; block++) { - unsigned char movebuf[512]; - int ret; - /* If it's in the target EUN already, or if it's pending write, do nothing */ if (BlockMap[block] == targetEUN || (pendingblock == (thisVUC * (nftl->EraseSize / 512) + block))) { @@ -403,25 +419,8 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p if (BlockMap[block] == BLOCK_NIL) continue; - ret = mtd_read(mtd, - (nftl->EraseSize * BlockMap[block]) + (block * 512), - 512, - &retlen, - movebuf); - if (ret < 0 && !mtd_is_bitflip(ret)) { - ret = mtd_read(mtd, - (nftl->EraseSize * BlockMap[block]) + (block * 512), - 512, - &retlen, - movebuf); - if (ret != -EIO) - printk("Error went away on retry.\n"); - } - memset(&oob, 0xff, sizeof(struct nftl_oob)); - oob.b.Status = oob.b.Status1 = SECTOR_USED; - - nftl_write(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + - (block * 512), 512, &retlen, movebuf, (char *)&oob); + NFTL_move_block(mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512), + (nftl->EraseSize * targetEUN) + (block * 512)); } /* add the header so that it is now a valid chain */ -- 2.47.2