[PATCH v2 56/58] mtd: rawnand: nandsim: retain chip state across removal
From: James Hilliard
Date: Tue Nov 10 2026 - 02:54:02 EST
MTD device references can outlive device unregistration even when no
open file pins the simulator module. Disconnect before freeing the
simulated media, and retain the chip metadata until the final MTD put.
The lifetime core waits for remaining device references during module
unload.
Signed-off-by: James Hilliard <james.hilliard1@xxxxxxxxx>
---
drivers/mtd/nand/raw/nandsim.c | 24 ++++++++++++++++++++----
1 file changed, 20 insertions(+), 4 deletions(-)
diff --git a/drivers/mtd/nand/raw/nandsim.c b/drivers/mtd/nand/raw/nandsim.c
index 6716eafb4b00..0c8c741b2b85 100644
--- a/drivers/mtd/nand/raw/nandsim.c
+++ b/drivers/mtd/nand/raw/nandsim.c
@@ -2254,6 +2254,11 @@ static const struct nand_controller_ops ns_controller_ops = {
.exec_op = ns_exec_op,
};
+static void ns_chip_release(struct nand_chip *chip)
+{
+ kfree(nand_get_controller_data(chip));
+}
+
/*
* Module initialization function
*/
@@ -2263,6 +2268,7 @@ static int __init ns_init_module(void)
struct nand_chip *chip;
struct nandsim *ns;
int ret;
+ bool retained = false;
if (bus_width != 8 && bus_width != 16) {
NS_ERR("wrong bus width (%d), use only 8 or 16\n", bus_width);
@@ -2377,6 +2383,10 @@ static int __init ns_init_module(void)
ret = ns_parse_badblocks(ns, nsmtd);
if (ret)
goto free_ns_object;
+ ret = nand_set_release(chip, ns_chip_release);
+ if (ret)
+ goto free_ns_object;
+ retained = true;
/* Register NAND partitions */
ret = mtd_device_register(nsmtd, &ns->partitions[0], ns->nbparts);
@@ -2392,11 +2402,16 @@ static int __init ns_init_module(void)
unregister_mtd:
WARN_ON(mtd_device_unregister(nsmtd));
free_ns_object:
+ if (retained)
+ nand_disconnect(chip);
ns_free(ns);
free_ebw:
kfree(erase_block_wear);
cleanup_nand:
- nand_cleanup(chip);
+ if (retained)
+ mtd_put_master(nsmtd);
+ else
+ nand_cleanup(chip);
free_gp_list:
list_for_each_safe(pos, n, &grave_pages) {
list_del(pos);
@@ -2413,7 +2428,8 @@ static int __init ns_init_module(void)
kfree(list_entry(pos, struct weak_block, list));
}
free_ns_struct:
- kfree(ns);
+ if (!retained)
+ kfree(ns);
return ret;
}
@@ -2431,9 +2447,9 @@ static void __exit ns_cleanup_module(void)
ns_debugfs_remove(ns);
WARN_ON(mtd_device_unregister(nsmtd));
+ nand_disconnect(chip);
ns_free(ns);
kfree(erase_block_wear);
- nand_cleanup(chip);
list_for_each_safe(pos, n, &grave_pages) {
list_del(pos);
@@ -2450,7 +2466,7 @@ static void __exit ns_cleanup_module(void)
kfree(list_entry(pos, struct weak_block, list));
}
- kfree(ns);
+ mtd_put_master(nsmtd);
}
module_exit(ns_cleanup_module);
--
2.53.0