Re: [PATCH] fix: mtd: mtd_device_parse_register: fix refcount imbalance on add_mtd_device failure and multi-call scenarios

From: WenTao Liang

Date: Sun Jun 28 2026 - 00:02:16 EST




> 2026年6月26日 23:13,WenTao Liang <vulab@xxxxxxxxxxx> 写道:
>
> add_mtd_device initializes mtd->refcnt via kref_init unconditionally. The
> cleanup in the out label only calls del_mtd_device when
> device_is_registered is true. When add_mtd_device fails before
> device_register, the refcnt is left at 1 (leak). Conversely, when
> CONFIG_MTD_PARTITIONED_MASTER is disabled and the device was already
> registered by a prior call, the error path incorrectly calls
> del_mtd_device without a matching add_mtd_device in this invocation,
> causing a refcount underflow.
>
> Track whether add_mtd_device succeeded in this invocation with a
> registered flag, and only call del_mtd_device on error when registered is
> true.
>
> Cc: stable@xxxxxxxxxxxxxxx
> Fixes: 1c4c215cbdcb ("mtd: add new API for handling MTD registration")
> Signed-off-by: WenTao Liang <vulab@xxxxxxxxxxx>
> ---
> drivers/mtd/mtdcore.c | 10 +++++++---
> 1 file changed, 7 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
> index 576537774628..59d8a6c61f55 100644
> --- a/drivers/mtd/mtdcore.c
> +++ b/drivers/mtd/mtdcore.c
> @@ -1108,6 +1108,7 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types,
> int nr_parts)
> {
> int ret, err;
> + bool registered = false;
>
> mtd_set_dev_defaults(mtd);
>
> @@ -1119,6 +1120,7 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types,
> ret = add_mtd_device(mtd);
> if (ret)
> goto out;
> + registered = true;
> }
>
> if (IS_REACHABLE(CONFIG_MTD_VIRT_CONCAT)) {
> @@ -1136,9 +1138,11 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types,
> ret = 0;
> else if (nr_parts)
> ret = add_mtd_partitions(mtd, parts, nr_parts);
> - else if (!device_is_registered(&mtd->dev))
> + else if (!device_is_registered(&mtd->dev)) {
> ret = add_mtd_device(mtd);
> - else
> + if (!ret)
> + registered = true;
> + } else
> ret = 0;
>
> if (ret)
> @@ -1170,7 +1174,7 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types,
> nvmem_unregister(mtd->otp_factory_nvmem);
> }
>
> - if (ret && device_is_registered(&mtd->dev)) {
> + if (ret && registered) {
> err = del_mtd_device(mtd);
> if (err)
> pr_err("Error when deleting MTD device (%d)\n", err);
> --
> 2.39.5 (Apple Git-154)

Please ignore this patch. I will resend a proper version after
learning the kernel submission process.

Apologies for the noise.

Best regards,
WenTao Liang