]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
mtd: nftl: reduce stack usage in NFTL_movebuf()
authorArnd Bergmann <arnd@arndb.de>
Tue, 10 Jun 2025 09:25:22 +0000 (11:25 +0200)
committerMiquel Raynal <miquel.raynal@bootlin.com>
Wed, 18 Jun 2025 09:16:35 +0000 (11:16 +0200)
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 <arnd@arndb.de>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
drivers/mtd/nftlcore.c

index 64d319e959b239bbab101cf71918080cd733f13f..868aa3d35d091eb76399aa794a21305bb7a89cb1 100644 (file)
@@ -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 */