Re: [PATCH RFC 08/14] fs/erofs: use folio_attach/detach_private() instead of direct assignment

"Zi Yan" <[email protected]>
Newsgroups org.kernel.vger.linux-kernel,org.kvack.linux-mm,org.ozlabs.lists.linux-erofs
Message-ID <[email protected]>
On Mon Aug 3, 2026 at 7:40 PM EDT, Gao Xiang wrote:
> Hi Zi,
>
> On Fri, Jul 31, 2026 at 10:13:31PM -0400, Zi Yan wrote:
>> erofs_onelinefolio_init/split/end() use folio->private without setting
>> PG_private or increase folio refcount and it works. But after PG_private is
>> replaced by checking folio->private in a future commit, it can break
>> folio_expected_ref_count(), since the folio has private data without
>> elevated refcount. Change it now.
>> 
>> It prepares for a future commit that removes PG_private.
>> 
>> No funtional change intended.
>> 
>> Assisted-by: Claude:claude-opus-4-8
>> Assisted-by: Codex:gpt-5
>> Signed-off-by: Zi Yan <[email protected]>
>> To: Gao Xiang <[email protected]>
>> To: Chao Yu <[email protected]>
>> Cc: Yue Hu <[email protected]>
>> Cc: Jeffle Xu <[email protected]>
>> Cc: Sandeep Dhavale <[email protected]>
>> Cc: Hongbo Li <[email protected]>
>> Cc: Chunhai Guo <[email protected]>
>> Cc: [email protected]
>> Cc: [email protected]
>
> It looks fine as long as PG_private flag will be removed in the
> follow-up patches:
>

Hi Gao,

Sashiko spot an issue in this patch[1]. Basically, ->private can be 0 if
I/O completes without any issue or being dirty and it causes
folio_detach_private() not to folio_put(). My fix is to add a bias, 1,
to the counter, so that ->private stays non NULL throughout online folio
process. The revised patch is below. Let me know your thoughts. Thanks.

[1] https://sashiko.dev/#/patchset/20260731-remove-pg_private-v1-0-142c97ba3562%40nvidia.com?part=8

From d8fadd13fee03e72c03a718af65ed41927ccbcca Mon Sep 17 00:00:00 2001
From: Zi Yan <[email protected]>
Date: Thu, 30 Jul 2026 11:04:00 -0400
Subject: [PATCH] erofs: use folio_attach/detach_private() instead of direct
 assignment

erofs_onlinefolio_init/split/end() use folio->private without setting
PG_private or increasing folio refcount and it works. But after PG_private
is replaced by checking folio->private in a future commit, it can break
folio_expected_ref_count(), since the folio has private data without
elevated refcount. Change them to use folio_attach/detach_private().

Furthermore, because folio->private is used to store in-flight I/O counter
and the counter reaches 0 when all I/O completes successfully without error
or being dirty, ->private=0 causes folio_detach_private() to not drop the
elevated folio refcount. Solve this issue by using bias=1 for the counter,
so that ->private stays non NULL throughout every attach-to-detach process.
Add a macro EROFS_ONLINEFOLIO_BIAS=1. While at it, fix the comment about
->private bit layout and add EROFS_ONLINEFOLIO_COUNT_MASK.

It prepares for a future commit that removes PG_private.

Assisted-by: Claude:claude-opus-4-8
Assisted-by: Codex:gpt-5
Signed-off-by: Zi Yan <[email protected]>
To: Gao Xiang <[email protected]>
To: Chao Yu <[email protected]>
Cc: Yue Hu <[email protected]>
Cc: Jeffle Xu <[email protected]>
Cc: Sandeep Dhavale <[email protected]>
Cc: Hongbo Li <[email protected]>
Cc: Chunhai Guo <[email protected]>
Cc: [email protected]
Cc: [email protected]
---
 fs/erofs/data.c | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/fs/erofs/data.c b/fs/erofs/data.c
index 9aa48c8d67d12..81e9dab247e0f 100644
--- a/fs/erofs/data.c
+++ b/fs/erofs/data.c
@@ -251,19 +251,23 @@ int erofs_map_dev(struct super_block *sb, struct erofs_map_dev *map)
 /*
  * bit 30: I/O error occurred on this folio
  * bit 29: CPU has dirty data in D-cache (needs aliasing handling);
- * bit 0 - 29: remaining parts to complete this folio
+ * bit 0 - 28: remaining parts to complete this folio, biased by 1 so that
+ *	       ->private stays non-NULL while the folio is attached
  */
 #define EROFS_ONLINEFOLIO_EIO		30
 #define EROFS_ONLINEFOLIO_DIRTY		29
+#define EROFS_ONLINEFOLIO_COUNT_MASK	(BIT(EROFS_ONLINEFOLIO_DIRTY) - 1)
+#define EROFS_ONLINEFOLIO_BIAS		1
 
 void erofs_onlinefolio_init(struct folio *folio)
 {
 	union {
 		atomic_t o;
 		void *v;
-	} u = { .o = ATOMIC_INIT(1) };
+	} u = { .o = ATOMIC_INIT(1 + EROFS_ONLINEFOLIO_BIAS) };
 
-	folio->private = u.v;	/* valid only if file-backed folio is locked */
+	/* valid only if file-backed folio is locked */
+	folio_attach_private(folio, u.v);
 }
 
 void erofs_onlinefolio_split(struct folio *folio)
@@ -277,14 +281,14 @@ void erofs_onlinefolio_end(struct folio *folio, int err, bool dirty)
 
 	do {
 		orig = atomic_read((atomic_t *)&folio->private);
-		DBG_BUGON(orig <= 0);
+		DBG_BUGON((orig & EROFS_ONLINEFOLIO_COUNT_MASK) <= EROFS_ONLINEFOLIO_BIAS);
 		v = dirty << EROFS_ONLINEFOLIO_DIRTY;
 		v |= (orig - 1) | (!!err << EROFS_ONLINEFOLIO_EIO);
 	} while (atomic_cmpxchg((atomic_t *)&folio->private, orig, v) != orig);
 
-	if (v & (BIT(EROFS_ONLINEFOLIO_DIRTY) - 1))
+	if ((v & EROFS_ONLINEFOLIO_COUNT_MASK) != EROFS_ONLINEFOLIO_BIAS)
 		return;
-	folio->private = 0;
+	folio_detach_private(folio);
 	if (v & BIT(EROFS_ONLINEFOLIO_DIRTY))
 		flush_dcache_folio(folio);
 	folio_end_read(folio, !(v & BIT(EROFS_ONLINEFOLIO_EIO)));
-- 
2.53.0




-- 
Best Regards,
Yan, Zi
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.