mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Itai Handler <itai.handler@gmail.com>
To: mwalle@kernel.org, pratyush@kernel.org
Cc: miquel.raynal@bootlin.com, richard@nod.at, vigneshr@ti.com,
	takahiro.kuwano@infineon.com, linux-mtd@lists.infradead.org,
	linux-kernel@vger.kernel.org, stable@vger.kernel.org,
	tudor.ambarus@linaro.org
Subject: [PATCH v4] mtd: spi-nor: take the flash lock in spi_nor_restore()
Date: Sun,  4 Oct 2026 13:43:11 +0300	[thread overview]
Message-ID: <20261004104311.2196527-1-itai.handler@gmail.com> (raw)

spi_nor_shutdown() and spi_nor_remove() reach the chip through
spi_nor_restore() without holding nor->lock, which every other path to
the flash takes through spi_nor_prep_and_lock(). Both run with the MTD
device still registered, so another thread can be mid-operation.

Neither outcome of that race is good. While the chip is busy the
address mode exit is typically ignored, so the restore is silently
dropped and the chip is left in 4-byte addressing, which a kexec then
hands to a kernel that cannot read it. The soft reset is typically
accepted even while busy, so it instead aborts an in-flight erase part
way through.

Take the lock in spi_nor_restore(); both callers are teardown paths
that can sleep and neither already holds it. Waiting is deliberate: a
partially erased sector cannot be undone from here, and the wait is
bounded by the one operation already in flight. If the lock cannot be
taken the restore is skipped with a warning.

Requests arriving after the restore are a separate problem: they race
with device removal itself rather than with the restore.

Fixes: 59b356ffd0b0 ("mtd: m25p80: restore the status of SPI flash when exiting")
Cc: stable@vger.kernel.org
Assisted-by: Claude Opus 5
Signed-off-by: Itai Handler <itai.handler@gmail.com>
---
Changes in v4:
- Correct what v3 claimed a busy chip does. v3 said it "ignores
  everything but status reads", which is roughly right for the address
  mode exit but wrong for the soft reset: that one is accepted while
  busy and aborts an in-flight erase. This strengthens the case for
  taking the lock rather than weakening it, but the old wording was
  not accurate and the comment now says both halves.
- Lock inside spi_nor_restore() instead of adding a
  spi_nor_restore_locked() wrapper around it. The _locked suffix
  conventionally means "the caller holds the lock", which is the
  opposite of what that wrapper did, and spi_nor_restore() is static
  with only the two teardown callers.
- Handle the spi_nor_prep_and_lock() error return instead of ignoring
  it, and warn when the restore is skipped.
- Say what happens to an operation that is already in flight, which
  Michael asked about on v3. Short answer: it is waited for, because
  an erase cannot be cancelled safely.
- Rebased on mainline. v3 depended on the spi_nor_rww_start_exclusive()
  mutex leak fix, which has since merged as 44b8a0bf5f96 ("mtd:
  spi-nor: core: Fix mutex leak in spi_nor_rww_start_exclusive()"), so
  this no longer depends on anything unmerged. Note that it is not yet
  in a released tag: v7.3-rc5 does not have it.

Link to v3:
  https://lore.kernel.org/r/20260915113811.2429311-1-itai.handler@gmail.com
Link to v2:
  https://lore.kernel.org/r/20260914081149.1916589-1-itai.handler@gmail.com

 drivers/mtd/spi-nor/core.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
index 8bc117b..94dbf1b 100644
--- a/drivers/mtd/spi-nor/core.c
+++ b/drivers/mtd/spi-nor/core.c
@@ -3455,6 +3455,21 @@ static void spi_nor_restore(struct spi_nor *nor)
 {
 	int ret;
 
+	/*
+	 * The MTD device is still registered here, so another thread may
+	 * have an operation in flight. Wait for it rather than cut in:
+	 * while the chip is busy the address mode exit below is typically
+	 * ignored, which silently loses the restore, and the soft reset is
+	 * typically accepted, which aborts an erase part way through.
+	 */
+	ret = spi_nor_prep_and_lock(nor);
+	if (ret) {
+		dev_warn(nor->dev,
+			 "Failed to lock flash, skipping restore, err = %d\n",
+			 ret);
+		return;
+	}
+
 	/* restore the addressing mode */
 	if (nor->addr_nbytes == 4 && !(nor->flags & SNOR_F_4B_OPCODES) &&
 	    nor->flags & SNOR_F_BROKEN_RESET) {
@@ -3470,6 +3485,8 @@ static void spi_nor_restore(struct spi_nor *nor)
 
 	if (nor->flags & SNOR_F_SOFT_RESET)
 		spi_nor_soft_reset(nor);
+
+	spi_nor_unlock_and_unprep(nor);
 }
 
 static const struct flash_info *spi_nor_match_name(struct spi_nor *nor,

base-commit: 6addb4f385570ebc11c4eb499a4f1c149f313e84

             reply	other threads:[~2026-10-04 10:43 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-04 10:43 Itai Handler [this message]
2026-10-04 10:56 ` sashiko-bot

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=20261004104311.2196527-1-itai.handler@gmail.com \
    --to=itai.handler@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mtd@lists.infradead.org \
    --cc=miquel.raynal@bootlin.com \
    --cc=mwalle@kernel.org \
    --cc=pratyush@kernel.org \
    --cc=richard@nod.at \
    --cc=stable@vger.kernel.org \
    --cc=takahiro.kuwano@infineon.com \
    --cc=tudor.ambarus@linaro.org \
    --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

all inboxes | Powered by JetHome®