All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] mtd: block2mtd: convert to folios
@ 2026-10-15  3:34 Tal Zussman
  2026-10-15  3:34 ` [PATCH 1/3] mtd: block2mtd: convert block2mtd_read() " Tal Zussman
                   ` (2 more replies)
  0 siblings, 3 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

block2mtd still goes through the page wrappers around the folio page
cache API, each of which hides a compound_head() call. Convert the read,
write and erase paths to use folios directly. This removes a
compound_head() call per page in the read path and four per page in the
write and erase paths, and leaves the driver with no struct page usage.

Tested on KVM with the MTD test modules and fsx/fsstress on UBIFS with
no errors.

The numbers below are from mtd_speedtest, in MiB/s, by folio size,
except the last row, which is from the MEMERASE ioctl:

+------------------------------+-------+--------+---------+---------+
| Test                         | Folio |   Base | Patched |  Change |
+------------------------------+-------+--------+---------+---------+
| Eraseblock read (128 KiB)    |   4K  |  12545 |   12863 |   +2.5% |
|                              |  16K  |  12998 |   17229 |  +32.6% |
|                              |  64K  |  13009 |   19135 |  +47.1% |
+------------------------------+-------+--------+---------+---------+
| Eraseblock write (128 KiB)   |   4K  |   8773 |    8063 |  noisy* |
|                              |  16K  |   9529 |   13448 |  +41.1% |
|                              |  64K  |   9636 |   15934 |  +65.4% |
+------------------------------+-------+--------+---------+---------+
| Page read (512 B)            |   4K  |   3332 |    3501 |   +5.1% |
|                              |  16K  |   3332 |    3462 |   +3.9% |
|                              |  64K  |   3330 |    3479 |   +4.5% |
+------------------------------+-------+--------+---------+---------+
| Page write (512 B)           |   4K  |   2001 |    2054 |   +2.6% |
|                              |  16K  |   2000 |    2059 |   +3.0% |
|                              |  64K  |   2001 |    2064 |   +3.1% |
+------------------------------+-------+--------+---------+---------+
| 2-page read (1 KiB)          |   4K  |   5262 |    5436 |   +3.3% |
|                              |  16K  |   5292 |    5327 |   +0.7% |
|                              |  64K  |   5312 |    5385 |   +1.4% |
+------------------------------+-------+--------+---------+---------+
| 2-page write (1 KiB)         |   4K  |   3635 |    3712 |   +2.1% |
|                              |  16K  |   3650 |    3725 |   +2.1% |
|                              |  64K  |   3665 |    3768 |   +2.8% |
+------------------------------+-------+--------+---------+---------+
| Erase, blocks hold data      |   4K  |  15013 |  ~15900 |   ~+6%* |
| (mtd_speedtest)              |  16K  |  15222 |   22849 |  +50.1% |
|                              |  64K  |  15280 |   24233 |  +58.6% |
+------------------------------+-------+--------+---------+---------+
| Erase, already erased        |   4K  |   9558 |   13727 |  +43.6% |
| (MEMERASE ioctl)             |  16K  |   9558 |   16580 |  +73.5% |
|                              |  64K  |   9626 |   17754 |  +84.4% |
+------------------------------+-------+--------+---------+---------+

---
Tal Zussman (3):
      mtd: block2mtd: convert block2mtd_read() to folios
      mtd: block2mtd: convert _block2mtd_write() to folios
      mtd: block2mtd: convert _block2mtd_erase() to folios

 drivers/mtd/devices/block2mtd.c | 120 +++++++++++++++++-----------------------
 1 file changed, 51 insertions(+), 69 deletions(-)
---
base-commit: 2f7fa8d90694d21dce68ceabd8383252b111cfea
change-id: 20261012-block2mtd-folio-9ccb6639c05a

Best regards,
--  
Tal Zussman <tz2294@columbia.edu>


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [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

end of thread, other threads:[~2026-10-15  9:14 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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 ` [PATCH 3/3] mtd: block2mtd: convert _block2mtd_erase() " Tal Zussman
2026-10-15  3:45   ` sashiko-bot
2026-10-15  9:14     ` Miquel Raynal

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.