* [PATCH 1/3] mtd: block2mtd: convert block2mtd_read() to folios
2026-10-15 3:34 [PATCH 0/3] mtd: block2mtd: convert to folios Tal Zussman
@ 2026-10-15 3:34 ` Tal Zussman
2026-10-15 3:34 ` [PATCH 2/3] mtd: block2mtd: convert _block2mtd_write() " Tal Zussman
2026-10-15 3:34 ` [PATCH 3/3] mtd: block2mtd: convert _block2mtd_erase() " Tal Zussman
2 siblings, 0 replies; 6+ messages in thread
From: Tal Zussman @ 2026-10-15 3:34 UTC (permalink / raw)
To: Joern Engel, Miquel Raynal, Richard Weinberger,
Vignesh Raghavendra
Cc: Matthew Wilcox (Oracle), linux-mtd, linux-kernel, Tal Zussman
Look the folio up with read_mapping_folio() instead of
read_mapping_page() and copy from it directly. This removes a hidden
compound_head() call per page.
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
---
drivers/mtd/devices/block2mtd.c | 28 +++++++++++-----------------
1 file changed, 11 insertions(+), 17 deletions(-)
diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c
index 03e80b2c4f5a..f28e49130197 100644
--- a/drivers/mtd/devices/block2mtd.c
+++ b/drivers/mtd/devices/block2mtd.c
@@ -106,30 +106,24 @@ static int block2mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
{
struct block2mtd_dev *dev = mtd->priv;
struct address_space *mapping = dev->bdev_file->f_mapping;
- struct page *page;
- pgoff_t index = from >> PAGE_SHIFT;
- int offset = from & (PAGE_SIZE-1);
- int cpylen;
+ struct folio *folio;
+ size_t offset, cpylen;
while (len) {
- if ((offset + len) > PAGE_SIZE)
- cpylen = PAGE_SIZE - offset; // multiple pages
- else
- cpylen = len; // this page
- len = len - cpylen;
-
- page = page_read(mapping, index);
- if (IS_ERR(page))
- return PTR_ERR(page);
+ folio = read_mapping_folio(mapping, from >> PAGE_SHIFT, NULL);
+ if (IS_ERR(folio))
+ return PTR_ERR(folio);
- memcpy(buf, page_address(page) + offset, cpylen);
- put_page(page);
+ offset = offset_in_folio(folio, from);
+ cpylen = min(len, folio_size(folio) - offset);
+ memcpy(buf, folio_address(folio) + offset, cpylen);
+ folio_put(folio);
if (retlen)
*retlen += cpylen;
buf += cpylen;
- offset = 0;
- index++;
+ from += cpylen;
+ len -= cpylen;
}
return 0;
}
--
2.39.5
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 2/3] mtd: block2mtd: convert _block2mtd_write() to folios
2026-10-15 3:34 [PATCH 0/3] mtd: block2mtd: convert to folios Tal Zussman
2026-10-15 3:34 ` [PATCH 1/3] mtd: block2mtd: convert block2mtd_read() " Tal Zussman
@ 2026-10-15 3:34 ` Tal Zussman
2026-10-15 3:34 ` [PATCH 3/3] mtd: block2mtd: convert _block2mtd_erase() " Tal Zussman
2 siblings, 0 replies; 6+ messages in thread
From: Tal Zussman @ 2026-10-15 3:34 UTC (permalink / raw)
To: Joern Engel, Miquel Raynal, Richard Weinberger,
Vignesh Raghavendra
Cc: Matthew Wilcox (Oracle), linux-mtd, linux-kernel, Tal Zussman
Write through a folio instead of a page, looking it up with
read_mapping_folio() instead of page_read(). This removes four hidden
compound_head() calls per page.
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
---
drivers/mtd/devices/block2mtd.c | 39 +++++++++++++++++----------------------
1 file changed, 17 insertions(+), 22 deletions(-)
diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c
index f28e49130197..910669d6bb94 100644
--- a/drivers/mtd/devices/block2mtd.c
+++ b/drivers/mtd/devices/block2mtd.c
@@ -133,38 +133,33 @@ static int block2mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
static int _block2mtd_write(struct block2mtd_dev *dev, const u_char *buf,
loff_t to, size_t len, size_t *retlen)
{
- struct page *page;
struct address_space *mapping = dev->bdev_file->f_mapping;
- pgoff_t index = to >> PAGE_SHIFT; // page index
- int offset = to & ~PAGE_MASK; // page offset
- int cpylen;
+ struct folio *folio;
+ size_t offset, cpylen;
+ void *p;
while (len) {
- if ((offset+len) > PAGE_SIZE)
- cpylen = PAGE_SIZE - offset; // multiple pages
- else
- cpylen = len; // this page
- len = len - cpylen;
-
- page = page_read(mapping, index);
- if (IS_ERR(page))
- return PTR_ERR(page);
+ folio = read_mapping_folio(mapping, to >> PAGE_SHIFT, NULL);
+ if (IS_ERR(folio))
+ return PTR_ERR(folio);
- if (memcmp(page_address(page)+offset, buf, cpylen)) {
- lock_page(page);
- memcpy(page_address(page) + offset, buf, cpylen);
- set_page_dirty(page);
- unlock_page(page);
+ offset = offset_in_folio(folio, to);
+ cpylen = min(len, folio_size(folio) - offset);
+ p = folio_address(folio) + offset;
+ if (memcmp(p, buf, cpylen)) {
+ folio_lock(folio);
+ memcpy(p, buf, cpylen);
+ folio_mark_dirty(folio);
+ folio_unlock(folio);
balance_dirty_pages_ratelimited(mapping);
}
- put_page(page);
+ folio_put(folio);
if (retlen)
*retlen += cpylen;
-
buf += cpylen;
- offset = 0;
- index++;
+ to += cpylen;
+ len -= cpylen;
}
return 0;
}
--
2.39.5
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 3/3] mtd: block2mtd: convert _block2mtd_erase() to folios
2026-10-15 3:34 [PATCH 0/3] mtd: block2mtd: convert to folios Tal Zussman
2026-10-15 3:34 ` [PATCH 1/3] mtd: block2mtd: convert block2mtd_read() " Tal Zussman
2026-10-15 3:34 ` [PATCH 2/3] mtd: block2mtd: convert _block2mtd_write() " Tal Zussman
@ 2026-10-15 3:34 ` Tal Zussman
2026-10-15 3:45 ` sashiko-bot
2 siblings, 1 reply; 6+ messages in thread
From: Tal Zussman @ 2026-10-15 3:34 UTC (permalink / raw)
To: Joern Engel, Miquel Raynal, Richard Weinberger,
Vignesh Raghavendra
Cc: Matthew Wilcox (Oracle), linux-mtd, linux-kernel, Tal Zussman
Erase through a folio instead of a page, and use memchr_inv() to check
whether a range still needs erasing instead of the open-coded scan.
This removes four hidden compound_head() calls per page, and the last
user of page_read(), so remove that too.
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
---
drivers/mtd/devices/block2mtd.c | 51 ++++++++++++++++++-----------------------
1 file changed, 22 insertions(+), 29 deletions(-)
diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c
index 910669d6bb94..a1d24fef415d 100644
--- a/drivers/mtd/devices/block2mtd.c
+++ b/drivers/mtd/devices/block2mtd.c
@@ -47,40 +47,33 @@ struct block2mtd_dev {
static LIST_HEAD(blkmtd_device_list);
-static struct page *page_read(struct address_space *mapping, pgoff_t index)
-{
- return read_mapping_page(mapping, index, NULL);
-}
-
/* erase a specified part of the device */
static int _block2mtd_erase(struct block2mtd_dev *dev, loff_t to, size_t len)
{
struct address_space *mapping = dev->bdev_file->f_mapping;
- struct page *page;
- pgoff_t index = to >> PAGE_SHIFT; // page index
- int pages = len >> PAGE_SHIFT;
- u_long *p;
- u_long *max;
-
- while (pages) {
- page = page_read(mapping, index);
- if (IS_ERR(page))
- return PTR_ERR(page);
-
- max = page_address(page) + PAGE_SIZE;
- for (p=page_address(page); p<max; p++)
- if (*p != -1UL) {
- lock_page(page);
- memset(page_address(page), 0xff, PAGE_SIZE);
- set_page_dirty(page);
- unlock_page(page);
- balance_dirty_pages_ratelimited(mapping);
- break;
- }
+ struct folio *folio;
+ size_t offset, chunk;
+ void *p;
+
+ while (len) {
+ folio = read_mapping_folio(mapping, to >> PAGE_SHIFT, NULL);
+ if (IS_ERR(folio))
+ return PTR_ERR(folio);
+
+ offset = offset_in_folio(folio, to);
+ chunk = min(len, folio_size(folio) - offset);
+ p = folio_address(folio) + offset;
+ if (memchr_inv(p, 0xff, chunk)) {
+ folio_lock(folio);
+ memset(p, 0xff, chunk);
+ folio_mark_dirty(folio);
+ folio_unlock(folio);
+ balance_dirty_pages_ratelimited(mapping);
+ }
+ folio_put(folio);
- put_page(page);
- pages--;
- index++;
+ to += chunk;
+ len -= chunk;
}
return 0;
}
--
2.39.5
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
^ permalink raw reply related [flat|nested] 6+ messages in thread* Re: [PATCH 3/3] mtd: block2mtd: convert _block2mtd_erase() to folios
2026-10-15 3:34 ` [PATCH 3/3] mtd: block2mtd: convert _block2mtd_erase() " Tal Zussman
@ 2026-10-15 3:45 ` sashiko-bot
2026-10-15 9:14 ` Miquel Raynal
0 siblings, 1 reply; 6+ messages in thread
From: sashiko-bot @ 2026-10-15 3:45 UTC (permalink / raw)
To: Tal Zussman, Joern Engel, Miquel Raynal, Richard Weinberger,
Vignesh Raghavendra
Cc: Matthew Wilcox (Oracle), linux-mtd
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] mm: missing folio->mapping re-validation after folio_lock()
--
commit 5d3ba379c345de78b1eb892e6685b2e8f75987f5
Author: Tal Zussman <tz2294@columbia.edu>
mtd: block2mtd: convert _block2mtd_erase() to folios
Erase through a folio instead of a page, and use memchr_inv() to check
whether a range still needs erasing instead of the open-coded scan.
This removes four hidden compound_head() calls per page, and the last
user of page_read(), so remove that too.
> diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c
> index 910669d6bb943..a1d24fef415dd 100644
> --- a/drivers/mtd/devices/block2mtd.c
> +++ b/drivers/mtd/devices/block2mtd.c
[ ... ]
> /* erase a specified part of the device */
> static int _block2mtd_erase(struct block2mtd_dev *dev, loff_t to, size_t len)
> {
> struct address_space *mapping = dev->bdev_file->f_mapping;
[ ... ]
> + while (len) {
> + folio = read_mapping_folio(mapping, to >> PAGE_SHIFT, NULL);
> + if (IS_ERR(folio))
> + return PTR_ERR(folio);
> +
> + offset = offset_in_folio(folio, to);
> + chunk = min(len, folio_size(folio) - offset);
> + p = folio_address(folio) + offset;
> + if (memchr_inv(p, 0xff, chunk)) {
> + folio_lock(folio);
> + memset(p, 0xff, chunk);
> + folio_mark_dirty(folio);
> + folio_unlock(folio);
[Severity: Medium]
Could _block2mtd_erase() modify a truncated folio here?
If the folio is truncated from the page cache while waiting for folio_lock(),
we could proceed with modifying the memory without it ever being written back
to the device. Should this re-validate that folio->mapping == mapping after
acquiring the lock?
> + balance_dirty_pages_ratelimited(mapping);
> + }
> + folio_put(folio);
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261014-block2mtd-folio-v1-0-19d24ae676ee@columbia.edu?part=3
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [PATCH 3/3] mtd: block2mtd: convert _block2mtd_erase() to folios
2026-10-15 3:45 ` sashiko-bot
@ 2026-10-15 9:14 ` Miquel Raynal
0 siblings, 0 replies; 6+ messages in thread
From: Miquel Raynal @ 2026-10-15 9:14 UTC (permalink / raw)
To: sashiko-bot
Cc: Tal Zussman, Joern Engel, Richard Weinberger, Vignesh Raghavendra,
sashiko-reviews, Matthew Wilcox, linux-mtd
Hi Tal,
On 15/10/2026 at 03:45:56 GMT, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [Medium] mm: missing folio->mapping re-validation after folio_lock()
TBH, I don't know the folio API so I'll let you determine whether this
is a real issue or not.
Miquèl
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
^ permalink raw reply [flat|nested] 6+ messages in thread