[PATCH v4 1/2] mtd: spi-nor: core: Fix mutex leak in spi_nor_rww_start_exclusive()

Runyu Xiao <[email protected]>
Newsgroups org.infradead.lists.linux-mtd,org.kernel.vger.linux-kernel,org.kernel.vger.stable
Message-ID <[email protected]>
The RWW wait helpers must not block while evaluating the condition.
spi_nor_rww_start_exclusive() used mutex_lock() directly and could return
with nor->lock still held.

Switch the four RWW start helpers to conditional scoped mutex guards so
the wait condition never sleeps and nor->lock is released before return.

Fixes: 74df43b3f626 ("mtd: spi-nor: Enhance locking to support reads while writes")
Cc: [email protected]
Signed-off-by: Runyu Xiao <[email protected]>

Changes in v4:
- Use the original RWW locking commit in Fixes and update the subject.
- Apply the locking fix to all RWW start helpers used as wait conditions.
- Keep commit 03e7bb864d9a ("mtd: spi-nor: use scope-based mutex
  cleanup helpers") as a stable prerequisite because it adds cleanup.h.
---
 drivers/mtd/spi-nor/core.c | 84 ++++++++++++++++++++------------------
 1 file changed, 45 insertions(+), 39 deletions(-)

diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
index ccf4396cdcd0..d5c6a925862e 100644
--- a/drivers/mtd/spi-nor/core.c
+++ b/drivers/mtd/spi-nor/core.c
@@ -1273,14 +1273,15 @@ static bool spi_nor_rww_start_io(struct spi_nor *nor)
 {
 	struct spi_nor_rww *rww = &nor->rww;
 
-	guard(mutex)(&nor->lock);
-
-	if (rww->ongoing_io)
-		return false;
+	scoped_guard(mutex_try, &nor->lock) {
+		if (rww->ongoing_io)
+			return false;
 
-	rww->ongoing_io = true;
+		rww->ongoing_io = true;
+		return true;
+	}
 
-	return true;
+	return false;
 }
 
 static void spi_nor_rww_end_io(struct spi_nor *nor)
@@ -1310,16 +1311,17 @@ static bool spi_nor_rww_start_exclusive(struct spi_nor *nor)
 {
 	struct spi_nor_rww *rww = &nor->rww;
 
-	mutex_lock(&nor->lock);
-
-	if (rww->ongoing_io || rww->ongoing_rd || rww->ongoing_pe)
-		return false;
+	scoped_guard(mutex_try, &nor->lock) {
+		if (rww->ongoing_io || rww->ongoing_rd || rww->ongoing_pe)
+			return false;
 
-	rww->ongoing_io = true;
-	rww->ongoing_rd = true;
-	rww->ongoing_pe = true;
+		rww->ongoing_io = true;
+		rww->ongoing_rd = true;
+		rww->ongoing_pe = true;
+		return true;
+	}
 
-	return true;
+	return false;
 }
 
 static void spi_nor_rww_end_exclusive(struct spi_nor *nor)
@@ -1369,23 +1371,25 @@ static bool spi_nor_rww_start_pe(struct spi_nor *nor, loff_t start, size_t len)
 	u8 first, last;
 	int bank;
 
-	guard(mutex)(&nor->lock);
+	scoped_guard(mutex_try, &nor->lock) {
+		if (rww->ongoing_io || rww->ongoing_rd || rww->ongoing_pe)
+			return false;
 
-	if (rww->ongoing_io || rww->ongoing_rd || rww->ongoing_pe)
-		return false;
+		spi_nor_offset_to_banks(nor->params->bank_size, start, len,
+					&first, &last);
+		for (bank = first; bank <= last; bank++) {
+			if (rww->used_banks & BIT(bank))
+				return false;
 
-	spi_nor_offset_to_banks(nor->params->bank_size, start, len, &first, &last);
-	for (bank = first; bank <= last; bank++) {
-		if (rww->used_banks & BIT(bank))
-			return false;
+			used_banks |= BIT(bank);
+		}
 
-		used_banks |= BIT(bank);
+		rww->used_banks |= used_banks;
+		rww->ongoing_pe = true;
+		return true;
 	}
 
-	rww->used_banks |= used_banks;
-	rww->ongoing_pe = true;
-
-	return true;
+	return false;
 }
 
 static void spi_nor_rww_end_pe(struct spi_nor *nor, loff_t start, size_t len)
@@ -1440,24 +1444,26 @@ static bool spi_nor_rww_start_rd(struct spi_nor *nor, loff_t start, size_t len)
 	u8 first, last;
 	int bank;
 
-	guard(mutex)(&nor->lock);
+	scoped_guard(mutex_try, &nor->lock) {
+		if (rww->ongoing_io || rww->ongoing_rd)
+			return false;
 
-	if (rww->ongoing_io || rww->ongoing_rd)
-		return false;
+		spi_nor_offset_to_banks(nor->params->bank_size, start, len,
+					&first, &last);
+		for (bank = first; bank <= last; bank++) {
+			if (rww->used_banks & BIT(bank))
+				return false;
 
-	spi_nor_offset_to_banks(nor->params->bank_size, start, len, &first, &last);
-	for (bank = first; bank <= last; bank++) {
-		if (rww->used_banks & BIT(bank))
-			return false;
+			used_banks |= BIT(bank);
+		}
 
-		used_banks |= BIT(bank);
+		rww->used_banks |= used_banks;
+		rww->ongoing_io = true;
+		rww->ongoing_rd = true;
+		return true;
 	}
 
-	rww->used_banks |= used_banks;
-	rww->ongoing_io = true;
-	rww->ongoing_rd = true;
-
-	return true;
+	return false;
 }
 
 static void spi_nor_rww_end_rd(struct spi_nor *nor, loff_t start, size_t len)
-- 
2.34.1

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.