[PATCH v2 1/4] mtd: block2mtd: retry if the page was dropped from the page cache
From: Tal Zussman
Date: Fri Oct 16 2026 - 15:14:28 EST
_block2mtd_write() and _block2mtd_erase() look a page up, decide it
needs changing, and only then lock it. invalidate_bdev(), from
BLKFLSBUF or device removal, can drop the page from the page cache in
between, since it is clean and unlocked. The write then goes into a
page nothing references and is lost. Check that the page is still in
the mapping after locking it and retry the lookup if not. The page can
be a tail page of a large folio, whose own mapping field holds the
TAIL_MAPPING poison value, so compare the folio's mapping.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Tal Zussman <tz2294@xxxxxxxxxxxx>
---
drivers/mtd/devices/block2mtd.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c
index 03e80b2c4f5a..ca72110b07d6 100644
--- a/drivers/mtd/devices/block2mtd.c
+++ b/drivers/mtd/devices/block2mtd.c
@@ -63,6 +63,7 @@ static int _block2mtd_erase(struct block2mtd_dev *dev, loff_t to, size_t len)
u_long *max;
while (pages) {
+retry:
page = page_read(mapping, index);
if (IS_ERR(page))
return PTR_ERR(page);
@@ -71,6 +72,11 @@ static int _block2mtd_erase(struct block2mtd_dev *dev, loff_t to, size_t len)
for (p=page_address(page); p<max; p++)
if (*p != -1UL) {
lock_page(page);
+ if (page_folio(page)->mapping != mapping) {
+ unlock_page(page);
+ put_page(page);
+ goto retry;
+ }
memset(page_address(page), 0xff, PAGE_SIZE);
set_page_dirty(page);
unlock_page(page);
@@ -152,12 +158,18 @@ static int _block2mtd_write(struct block2mtd_dev *dev, const u_char *buf,
cpylen = len; // this page
len = len - cpylen;
+retry:
page = page_read(mapping, index);
if (IS_ERR(page))
return PTR_ERR(page);
if (memcmp(page_address(page)+offset, buf, cpylen)) {
lock_page(page);
+ if (page_folio(page)->mapping != mapping) {
+ unlock_page(page);
+ put_page(page);
+ goto retry;
+ }
memcpy(page_address(page) + offset, buf, cpylen);
set_page_dirty(page);
unlock_page(page);
--
2.39.5