[PATCH v3 02/27] mtd: spi-nor: sfdp: Garbage collection during sfdp parsing
Miquel Raynal <[email protected]> Tue, 04 Aug 2026 12:59:00 +0200
| Newsgroups | gmane.linux.kernel,gmane.linux.drivers.mtd |
|---|---|
| Message-ID | <20260804-winbond-v7-1-spi-nor-jv-cleanup-v3-2-542ce107bc92@bootlin.com> |
SFDP works as follows: 1- The header is read then parsed 2- If correct, the sfdp structure and the sfdp content table are allocated then filled 3- The mandatory BFPT table is parsed 4- The optional tables are then parsed as well Any failure in steps 1-3 leads to an error and an early return. The failure is not always fatal though, since the deprecated will fallback to the non SFDP definition (in the ID table, for legacy chips). In this case, the devm_ memory allocations for the SFDP table structure and table will remain in memory for the lifetime of the device but will never ever be accessed anymore (since they are incorrect). In this case, we shall free the memory manually since the device is not going out of scope anytime soon. The assignation of nor->sfdp is also moved just after BFPT table parsing, to avoid any dangling pointer upon partial failure. This is particularly important since the presence of valid SFDP support is checked using the following condition: `if (!nor->sfdp)`. Signed-off-by: Miquel Raynal <[email protected]> --- This change is particularly useful for the next patches, I don't think it is relevant to backport it. --- drivers/mtd/spi-nor/sfdp.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/drivers/mtd/spi-nor/sfdp.c b/drivers/mtd/spi-nor/sfdp.c index 6a571d8d822c..fd9f93da014d 100644 --- a/drivers/mtd/spi-nor/sfdp.c +++ b/drivers/mtd/spi-nor/sfdp.c @@ -1490,7 +1490,7 @@ int spi_nor_parse_sfdp(struct spi_nor *nor) psize, param_headers); if (err < 0) { dev_dbg(dev, "failed to read SFDP parameter headers\n"); - goto exit; + goto free_param_headers; } } @@ -1518,7 +1518,7 @@ int spi_nor_parse_sfdp(struct spi_nor *nor) sfdp = devm_kzalloc(dev, sizeof(*sfdp), GFP_KERNEL); if (!sfdp) { err = -ENOMEM; - goto exit; + goto free_param_headers; } /* @@ -1532,20 +1532,15 @@ int spi_nor_parse_sfdp(struct spi_nor *nor) sizeof(*sfdp->dwords), GFP_KERNEL); if (!sfdp->dwords) { err = -ENOMEM; - devm_kfree(dev, sfdp); - goto exit; + goto free_sfdp; } err = spi_nor_read_sfdp(nor, 0, sfdp_size, sfdp->dwords); if (err < 0) { dev_dbg(dev, "failed to read SFDP data\n"); - devm_kfree(dev, sfdp->dwords); - devm_kfree(dev, sfdp); - goto exit; + goto free_dwords; } - nor->sfdp = sfdp; - /* * Check other parameter headers to get the latest revision of * the basic flash parameter table. @@ -1563,7 +1558,9 @@ int spi_nor_parse_sfdp(struct spi_nor *nor) err = spi_nor_parse_bfpt(nor, bfpt_header); if (err) - goto exit; + goto free_dwords; + + nor->sfdp = sfdp; /* Parse optional parameter tables. */ for (i = 0; i < header.nph; i++) { @@ -1608,7 +1605,16 @@ int spi_nor_parse_sfdp(struct spi_nor *nor) } err = spi_nor_post_sfdp_fixups(nor); -exit: + + kfree(param_headers); + + return 0; + +free_dwords: + devm_kfree(dev, sfdp->dwords); +free_sfdp: + devm_kfree(dev, sfdp); +free_param_headers: kfree(param_headers); return err; } -- 2.54.0