mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] erofs: fix folio reuse from a different address_space in erofs_bread()
@ 2026-09-30 11:21 Binglei Wang
  2026-09-30 17:27 ` Gao Xiang
  0 siblings, 1 reply; 8+ messages in thread
From: Binglei Wang @ 2026-09-30 11:21 UTC (permalink / raw)
  To: xiang, chao, linux-kernel
  Cc: zbestahu, jefflexu, dhavale, hongbohbli, guochunhai, liubo03,
	linux-erofs, l3b2w1

From: Binglei Wang <l3b2w1@gmail.com>

erofs_bread() reuses a cached folio on page index match without checking folio->mapping.

xattr.c calls erofs_init_metabuf() twice on the same buffer without erofs_put_metabuf();
the two in_metabox sources differ, so buf->mapping can switch
while buf->page still belongs to the old address_space.
The next erofs_bread() then reads the wrong mapping, dropping shared xattrs with METABOX.

We require folio->mapping == buf->mapping in the reuse check;
otherwise drop the cached folio and re-read via the slow path.

Fixes: 414091322c63 ("erofs: implement metadata compression")
Cc: Bo Liu (OpenAnolis) <liubo03@inspur.com>
Signed-off-by: Binglei Wang <l3b2w1@gmail.com>
---
 fs/erofs/data.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/fs/erofs/data.c b/fs/erofs/data.c
index be63b89f0862..d8b6523bc218 100644
--- a/fs/erofs/data.c
+++ b/fs/erofs/data.c
@@ -33,8 +33,13 @@ void *erofs_bread(struct erofs_buf *buf, erofs_off_t offset, bool need_kmap)
 	if (buf->page) {
 		folio = page_folio(buf->page);
-		if (folio_file_page(folio, index) != buf->page)
+		if (folio->mapping != buf->mapping) {
+			/* the cached folio belongs to another address_space */
+			erofs_put_metabuf(buf);
+			folio = NULL;
+		} else if (folio_file_page(folio, index) != buf->page) {
 			erofs_unmap_metabuf(buf);
+		}
 	}
 	if (!folio || !folio_contains(folio, index)) {
 		erofs_put_metabuf(buf);
--
2.43.0


^ permalink raw reply	[flat|nested] 8+ messages in thread
* [PATCH] erofs: fix folio reuse from a different address_space in erofs_bread()
@ 2026-09-30  3:37 binglei wang
  2026-09-30  7:52 ` Gao Xiang
  0 siblings, 1 reply; 8+ messages in thread
From: binglei wang @ 2026-09-30  3:37 UTC (permalink / raw)
  To: xiang, chao, linux-erofs
  Cc: zbestahu, jefflexu, dhavale, hongbohbli, guochunhai, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 2189 bytes --]

erofs_bread() caches the last folio in struct erofs_buf and reuses it when
the next request lands on the same folio, but the reuse predicate only
compares the page index; it never checks that the cached folio still
belongs to buf->mapping.  Correctness therefore relies on an invariant
that is nowhere enforced.

fs/erofs/xattr.c already breaks it: erofs_xattr_iter_inline() and
erofs_xattr_iter_shared() call erofs_init_metabuf() on the same buffer
with no intervening erofs_put_metabuf(), and their in_metabox arguments
come from different sources (per-inode vs per-fs).  When the two differ,
buf->mapping is switched while buf->page still holds a folio of the
previous address_space, so the next erofs_bread() can return data from
the wrong one.

This is observable with METABOX enabled, where shared xattrs silently
disappear on the mounted fs, while the same tree built without METABOX
reports them fine.

Fix it by validating the address_space in the reuse predicate too: if the
cached folio belongs to another mapping, drop it so that the existing
slow path re-reads from buf->mapping.  Reading folio->mapping is safe
here because a reference on the cached folio is still held; if the folio
was already truncated, folio->mapping is NULL and the slow path is taken,
which is the safe direction.

Fixes: 414091322c63 ("erofs: implement metadata compression")
Cc: Bo Liu (OpenAnolis) <liubo03@inspur.com>
Signed-off-by: Binglei Wang <l3b2w1@gmail.com>
---
 fs/erofs/data.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/fs/erofs/data.c b/fs/erofs/data.c
index be63b89f0862..d8b6523bc218 100644
--- a/fs/erofs/data.c
+++ b/fs/erofs/data.c
@@ -33,8 +33,13 @@ void *erofs_bread(struct erofs_buf *buf,
erofs_off_t offset, bool need_kmap)

  if (buf->page) {
  folio = page_folio(buf->page);
- if (folio_file_page(folio, index) != buf->page)
+ if (folio->mapping != buf->mapping) {
+ /* the cached folio belongs to another address_space */
+ erofs_put_metabuf(buf);
+ folio = NULL;
+ } else if (folio_file_page(folio, index) != buf->page) {
  erofs_unmap_metabuf(buf);
+ }
  }
  if (!folio || !folio_contains(folio, index)) {
  erofs_put_metabuf(buf);
-- 
2.33.0

[-- Attachment #2: 0001-erofs-fix-folio-reuse-from-a-different-address_space.patch --]
[-- Type: text/x-diff, Size: 2442 bytes --]

From a17eaf6b476a66e6bc6d85c569584911accb05bf Mon Sep 17 00:00:00 2001
From: Binglei Wang <l3b2w1@gmail.com>
Date: Wed, 30 Sep 2026 10:34:48 +0800
Subject: [PATCH] erofs: fix folio reuse from a different address_space in
 erofs_bread()

erofs_bread() caches the last folio in struct erofs_buf and reuses it when
the next request lands on the same folio, but the reuse predicate only
compares the page index; it never checks that the cached folio still
belongs to buf->mapping.  Correctness therefore relies on an invariant
that is nowhere enforced.

fs/erofs/xattr.c already breaks it: erofs_xattr_iter_inline() and
erofs_xattr_iter_shared() call erofs_init_metabuf() on the same buffer
with no intervening erofs_put_metabuf(), and their in_metabox arguments
come from different sources (per-inode vs per-fs).  When the two differ,
buf->mapping is switched while buf->page still holds a folio of the
previous address_space, so the next erofs_bread() can return data from
the wrong one.

This is observable with METABOX enabled, where shared xattrs silently
disappear on the mounted fs, while the same tree built without METABOX
reports them fine.

Fix it by validating the address_space in the reuse predicate too: if the
cached folio belongs to another mapping, drop it so that the existing
slow path re-reads from buf->mapping.  Reading folio->mapping is safe
here because a reference on the cached folio is still held; if the folio
was already truncated, folio->mapping is NULL and the slow path is taken,
which is the safe direction.

Fixes: 414091322c63 ("erofs: implement metadata compression")
Cc: Bo Liu (OpenAnolis) <liubo03@inspur.com>
Signed-off-by: Binglei Wang <l3b2w1@gmail.com>
---
 fs/erofs/data.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/fs/erofs/data.c b/fs/erofs/data.c
index be63b89f0862..d8b6523bc218 100644
--- a/fs/erofs/data.c
+++ b/fs/erofs/data.c
@@ -33,8 +33,13 @@ void *erofs_bread(struct erofs_buf *buf, erofs_off_t offset, bool need_kmap)
 
 	if (buf->page) {
 		folio = page_folio(buf->page);
-		if (folio_file_page(folio, index) != buf->page)
+		if (folio->mapping != buf->mapping) {
+			/* the cached folio belongs to another address_space */
+			erofs_put_metabuf(buf);
+			folio = NULL;
+		} else if (folio_file_page(folio, index) != buf->page) {
 			erofs_unmap_metabuf(buf);
+		}
 	}
 	if (!folio || !folio_contains(folio, index)) {
 		erofs_put_metabuf(buf);
-- 
2.33.0


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

end of thread, other threads:[~2026-10-01  6:02 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-30 11:21 [PATCH] erofs: fix folio reuse from a different address_space in erofs_bread() Binglei Wang
2026-09-30 17:27 ` Gao Xiang
2026-09-30 19:19   ` [PATCH v2] " Binglei Wang
2026-09-30 20:29     ` Gao Xiang
2026-10-01  6:01       ` Binglei Wang
  -- strict thread matches above, loose matches on Subject: below --
2026-09-30  3:37 [PATCH] " binglei wang
2026-09-30  7:52 ` Gao Xiang
2026-09-30 11:29   ` binglei wang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®