From: sashiko-bot@kernel.org
To: "James Hilliard" <james.hilliard1@gmail.com>,
"Miquel Raynal" <miquel.raynal@bootlin.com>,
"Richard Weinberger" <richard@nod.at>,
"Vignesh Raghavendra" <vigneshr@ti.com>
Cc: linux-mtd@lists.infradead.org,
"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
"Srinivas Kandagatla" <srini@kernel.org>,
"Tze Yee Ng" <tze.yee.ng@altera.com>
Subject: Re: [PATCH v4 03/58] mtd: separate class devices from retained backing objects
Date: Fri, 13 Nov 2026 19:16:47 +0000 [thread overview]
Message-ID: <sashiko-outbox-213533@kernel.org> (raw)
In-Reply-To: <20261113-submit-rawnand-retained-handle-lifetime-v1-v4-3-556b1d7c6221@gmail.com>
Thank you for your contribution! Sashiko AI review found 3 potential
issues to consider:
- [High] mtd: out-of-bounds access in gluebi_get_device() via
add_mtd_partitions()
- [Medium] mtd: concurrent child removal in add_mtd_partitions() deletes
all partitions
- [Medium] mtd: mtd_device_parse_register() and unregister check
device_is_registered()
--
commit 6ac4170246a3c7e1422d462f2c77f494c0bb8489
Author: James Hilliard <james.hilliard1@gmail.com>
mtd: separate class devices from retained backing objects
This commit allocates MTD class devices separately from struct mtd_info,
moves the MTD class and device release handling into a built-in helper,
and adds reference counting for backing master and partition metadata.
> diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
> index 620326279957f..dd404d36156ea 100644
> --- a/drivers/mtd/mtdcore.c
> +++ b/drivers/mtd/mtdcore.c
[ ... ]
> @@ -1150,7 +1200,7 @@ 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 (!mtd->dev || !device_is_registered(mtd->dev))
> ret = add_mtd_device(mtd);
> else
> ret = 0;
> @@ -1184,7 +1234,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 && mtd->dev && device_is_registered(mtd->dev)) {
> err = del_mtd_device(mtd);
> if (err)
> pr_err("Error when deleting MTD device (%d)\n", err);
> @@ -1225,7 +1275,7 @@ int mtd_device_unregister(struct mtd_info *master)
> if (err)
> return err;
>
> - if (!device_is_registered(&master->dev))
> + if (!master->dev || !device_is_registered(master->dev))
> return 0;
>
> return del_mtd_device(master);
[Severity: Medium]
Can checking device_is_registered(master->dev) instead of
master->registered cause mtd_device_unregister() to call del_mtd_device()
a second time and fail with -ENODEV?
With CONFIG_MTD_PARTITIONED_MASTER=y, mtd_device_parse_register() calls
add_mtd_device(mtd) before parsing and registering partitions. If
userspace (such as udevd on KOBJ_ADD) or an in-kernel consumer acquires a
handle on the master during that window and partition registration then
fails (for example with -EPROBE_DEFER), del_mtd_device(mtd) clears
mtd->registered and drops the initial refcnt without running
mtd_device_release(). Because mtd->dev remains registered until the
handle is put, a driver error path that calls mtd_device_unregister()
(such as physmap_flash_probe() -> physmap_flash_remove()) sees
device_is_registered(master->dev) == true and calls del_mtd_device(master)
again, returning -ENODEV. Wait-free unmanaged callers also return from
mtd_device_parse_register() with mtd->dev drvdata and mtd->nvmem still
attached to the mtd_info they are about to free, and a deferred probe
retry hits WARN_ONCE(mtd->dev) in add_mtd_device().
[ ... ]
> diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
> index c316cfe92c7e4..58d1343476912 100644
> --- a/drivers/mtd/mtdpart.c
> +++ b/drivers/mtd/mtdpart.c
[ ... ]
> @@ -419,35 +420,47 @@ int add_mtd_partitions(struct mtd_info *parent,
> nbparts, parent->name);
>
> for (i = 0; i < nbparts; i++) {
> + mutex_lock(&master->master.partitions_lock);
> + if (master->master.unregistering ||
> + (mtd_is_partition(parent) && !parent->registered)) {
> + ret = -ENODEV;
> + goto err_unlock;
> + }
> +
> child = allocate_partition(parent, parts + i, i, cur_offset);
> if (IS_ERR(child)) {
> ret = PTR_ERR(child);
> - goto err_del_partitions;
> + goto err_unlock;
> }
>
> if (IS_REACHABLE(CONFIG_MTD_VIRT_CONCAT)) {
> - if (mtd_virt_concat_add(child))
> + if (mtd_virt_concat_add(child)) {
> + mutex_unlock(&master->master.partitions_lock);
> continue;
> + }
> }
>
> - mutex_lock(&master->master.partitions_lock);
> list_add_tail(&child->part.node, &parent->partitions);
> - mutex_unlock(&master->master.partitions_lock);
>
> ret = add_mtd_device(child);
> if (ret) {
> - mutex_lock(&master->master.partitions_lock);
> list_del(&child->part.node);
> - mutex_unlock(&master->master.partitions_lock);
> -
> free_partition(child);
> - goto err_del_partitions;
> + goto err_unlock;
> }
>
> mtd_add_partition_attrs(child);
> + cur_offset = child->part.offset + child->part.size;
> +
> + /* Parsing drops the partition lock and may race with deletion. */
> + ret = PTR_ERR_OR_ZERO(get_mtd_device(child, -1));
> + if (ret)
> + goto err_unlock;
> + mutex_unlock(&master->master.partitions_lock);
>
> /* Look for subpartitions (skip if no maching parser found) */
> ret = parse_mtd_partitions(child, parts[i].types, NULL);
> + put_mtd_device(child);
[Severity: High]
Does calling get_mtd_device(child, -1) on every new partition cause an
out-of-bounds access in gluebi_get_device() when a gluebi MTD device is
partitioned?
__get_mtd_device(child) passes child to master->_get_device(mtd), whereas
__put_mtd_device(child) passes master to master->_put_device(master).
gluebi_get_device() applies container_of() directly to mtd without calling
mtd_get_master(mtd):
drivers/mtd/ubi/gluebi.c:gluebi_get_device() {
...
gluebi = container_of(mtd, struct gluebi_device, mtd);
mutex_lock(&devices_mutex);
if (gluebi->refcnt > 0) {
gluebi->refcnt += 1;
...
}
Because child is allocated by allocate_partition() as a standalone struct
mtd_info rather than embedded in struct gluebi_device, gluebi_get_device()
reads and writes past the end of child, and the paired put_mtd_device(child)
then decrements the master gluebi->refcnt in gluebi_put_device(master).
> if (ret < 0 && ret == -ENOENT) {
> pr_debug("Skip parsing subpartitions: %d\n", ret);
> continue;
> @@ -455,12 +468,12 @@ int add_mtd_partitions(struct mtd_info *parent,
> pr_err("Failed to parse subpartitions: %d\n", ret);
> goto err_del_partitions;
> }
> -
> - cur_offset = child->part.offset + child->part.size;
> }
>
> return 0;
>
> +err_unlock:
> + mutex_unlock(&master->master.partitions_lock);
> err_del_partitions:
> del_mtd_partitions(master);
[Severity: Medium]
If child is removed via BLKPG_DEL_PARTITION while partitions_lock is
dropped for parse_mtd_partitions(child, ...), does jumping to err_unlock
destroy all partitions on the root master device?
When a subpartition parser calls add_mtd_partitions(child, ...) after
child->registered has been cleared by mtd_del_partition(), the
!parent->registered check sets ret = -ENODEV and jumps to err_unlock.
That falls through to del_mtd_partitions(master) on the top-level master
instead of just skipping subpartitions for the removed child, and returns
-ENODEV to the outer add_mtd_partitions() loop (which only ignores
-ENOENT), failing the entire master registration.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261113-submit-rawnand-retained-handle-lifetime-v1-v4-0-556b1d7c6221@gmail.com?part=3
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
next prev parent reply other threads:[~2026-11-13 19:16 UTC|newest]
Thread overview: 61+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-13 18:14 [PATCH v4 00/58] mtd: rawnand: retain chip and controller state across removal James Hilliard
2026-11-13 18:14 ` [PATCH v4 01/58] nvmem: disconnect provider callbacks before unregister returns James Hilliard
2026-11-13 18:14 ` [PATCH v4 02/58] mtd: acquire an MTD handle from a referenced class device James Hilliard
2026-11-13 18:14 ` [PATCH v4 03/58] mtd: separate class devices from retained backing objects James Hilliard
2026-11-13 19:16 ` sashiko-bot [this message]
2026-11-13 18:14 ` [PATCH v4 04/58] mtd: retain virtual concatenations across component removal James Hilliard
2026-11-13 18:14 ` [PATCH v4 05/58] mtd: rawnand: separate hardware disconnection from cleanup James Hilliard
2026-11-13 18:14 ` [PATCH v4 06/58] mtd: rawnand: share retained chip and controller ownership James Hilliard
2026-11-13 18:14 ` [PATCH v4 07/58] mtd: rawnand: sunxi: retain chip state until the final MTD put James Hilliard
2026-11-13 18:14 ` [PATCH v4 08/58] mtd: rawnand: plat_nand: retain open-handle state on removal James Hilliard
2026-11-13 18:14 ` [PATCH v4 09/58] mtd: rawnand: gpio: " James Hilliard
2026-11-13 18:14 ` [PATCH v4 10/58] mtd: rawnand: stm32_fmc2: " James Hilliard
2026-11-13 18:14 ` [PATCH v4 11/58] mtd: rawnand: denali: retain chips across controller removal James Hilliard
2026-11-13 18:14 ` [PATCH v4 12/58] mtd: rawnand: arasan: " James Hilliard
2026-11-13 18:14 ` [PATCH v4 13/58] mtd: rawnand: mxic: retain open-handle state on removal James Hilliard
2026-11-13 18:14 ` [PATCH v4 14/58] mtd: rawnand: intel: " James Hilliard
2026-11-13 18:14 ` [PATCH v4 15/58] mtd: rawnand: tegra: " James Hilliard
2026-11-13 18:14 ` [PATCH v4 16/58] mtd: rawnand: mtk: retain chips across controller removal James Hilliard
2026-11-13 18:14 ` [PATCH v4 17/58] mtd: rawnand: rockchip: " James Hilliard
2026-11-13 18:14 ` [PATCH v4 18/58] mtd: rawnand: atmel: " James Hilliard
2026-11-13 18:14 ` [PATCH v4 19/58] mtd: rawnand: orion: retain open-handle state on removal James Hilliard
2026-11-13 18:14 ` [PATCH v4 20/58] mtd: rawnand: socrates: " James Hilliard
2026-11-13 18:14 ` [PATCH v4 21/58] mtd: rawnand: fsl_upm: " James Hilliard
2026-11-13 18:14 ` [PATCH v4 22/58] mtd: rawnand: pasemi: " James Hilliard
2026-11-13 18:14 ` [PATCH v4 23/58] mtd: rawnand: ams-delta: " James Hilliard
2026-11-13 18:14 ` [PATCH v4 24/58] mtd: rawnand: xway: " James Hilliard
2026-11-13 18:14 ` [PATCH v4 25/58] mtd: rawnand: hisi504: " James Hilliard
2026-11-13 18:14 ` [PATCH v4 26/58] mtd: rawnand: vf610: " James Hilliard
2026-11-13 18:14 ` [PATCH v4 27/58] mtd: rawnand: technologic: " James Hilliard
2026-11-13 18:39 ` sashiko-bot
2026-11-13 18:14 ` [PATCH v4 28/58] mtd: rawnand: loongson: " James Hilliard
2026-11-13 18:14 ` [PATCH v4 29/58] mtd: rawnand: ma35d1: " James Hilliard
2026-11-13 18:14 ` [PATCH v4 30/58] mtd: rawnand: pl35x: " James Hilliard
2026-11-13 18:14 ` [PATCH v4 31/58] mtd: rawnand: mxc: " James Hilliard
2026-11-13 18:14 ` [PATCH v4 32/58] mtd: rawnand: fsmc: " James Hilliard
2026-11-13 18:14 ` [PATCH v4 33/58] mtd: rawnand: gpmi: " James Hilliard
2026-11-13 18:14 ` [PATCH v4 34/58] mtd: rawnand: omap2: " James Hilliard
2026-11-13 18:14 ` [PATCH v4 35/58] mtd: rawnand: marvell: " James Hilliard
2026-11-13 18:14 ` [PATCH v4 36/58] mtd: rawnand: renesas: " James Hilliard
2026-11-13 18:14 ` [PATCH v4 37/58] mtd: rawnand: meson: " James Hilliard
2026-11-13 18:14 ` [PATCH v4 38/58] mtd: rawnand: cadence: " James Hilliard
2026-11-13 18:14 ` [PATCH v4 39/58] mtd: rawnand: qcom: " James Hilliard
2026-11-13 18:14 ` [PATCH v4 40/58] mtd: rawnand: cafe: " James Hilliard
2026-11-13 18:14 ` [PATCH v4 41/58] mtd: rawnand: brcmnand: " James Hilliard
2026-11-13 18:14 ` [PATCH v4 42/58] mtd: rawnand: au1550nd: retain chip state across removal James Hilliard
2026-11-13 18:14 ` [PATCH v4 43/58] mtd: rawnand: sharpsl: " James Hilliard
2026-11-13 18:15 ` [PATCH v4 44/58] mtd: rawnand: davinci: " James Hilliard
2026-11-13 18:15 ` [PATCH v4 45/58] mtd: rawnand: sh_flctl: " James Hilliard
2026-11-13 18:15 ` [PATCH v4 46/58] mtd: rawnand: lpc32xx_slc: " James Hilliard
2026-11-13 18:15 ` [PATCH v4 47/58] mtd: rawnand: lpc32xx_mlc: " James Hilliard
2026-11-13 18:15 ` [PATCH v4 48/58] mtd: rawnand: ndfc: " James Hilliard
2026-11-13 18:15 ` [PATCH v4 49/58] mtd: rawnand: txx9ndfmc: " James Hilliard
2026-11-13 18:15 ` [PATCH v4 50/58] mtd: rawnand: ingenic: " James Hilliard
2026-11-13 18:15 ` [PATCH v4 51/58] mtd: rawnand: mpc5121: " James Hilliard
2026-11-13 18:15 ` [PATCH v4 52/58] mtd: rawnand: bcm47xxnflash: " James Hilliard
2026-11-13 18:15 ` [PATCH v4 53/58] mtd: rawnand: fsl_elbc: " James Hilliard
2026-11-13 18:15 ` [PATCH v4 54/58] mtd: rawnand: fsl_ifc: " James Hilliard
2026-11-13 18:15 ` [PATCH v4 55/58] mtd: rawnand: r852: " James Hilliard
2026-11-13 18:15 ` [PATCH v4 56/58] mtd: rawnand: nandsim: " James Hilliard
2026-11-13 18:15 ` [PATCH v4 57/58] mtd: rawnand: cs553x: " James Hilliard
2026-11-13 18:15 ` [PATCH v4 58/58] mtd: rawnand: diskonchip: " James Hilliard
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=sashiko-outbox-213533@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=gregkh@linuxfoundation.org \
--cc=james.hilliard1@gmail.com \
--cc=linux-mtd@lists.infradead.org \
--cc=miquel.raynal@bootlin.com \
--cc=richard@nod.at \
--cc=sashiko-reviews@lists.linux.dev \
--cc=srini@kernel.org \
--cc=tze.yee.ng@altera.com \
--cc=vigneshr@ti.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox