[PATCH v2 1/4] mtd: block2mtd: retry if the page was dropped from the page cache

Tal Zussman tz2294 at columbia.edu
Fri Oct 16 12:11:07 PDT 2026


_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 at columbia.edu>
---
 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




More information about the linux-mtd mailing list