Re: [PATCH v4 00/16] Remove PG_private by using page/folio->private checks instead

From: Zi Yan

Date: Tue Sep 15 2026 - 14:30:23 EST


On 13 Sep 2026, at 23:39, Andrew Morton wrote:

> On Sun, 13 Sep 2026 22:23:58 -0400 Zi Yan <ziy@xxxxxxxxxx> wrote:
>
>> This patchset removes PG_private to make space for upcoming PG_folio for
>> identifying pages from a folio (more details in Note below). Instead of
>> checking PG_private, all code is changed to check page/folio->private !=
>> NULL instead.
>>
>> MM people are cc'd on all patches and subsystem people are cc'd on the
>> cover letter and corresponding patches.
>>
>> Patch 6 is picked up separately in f2fs tree, but since mm-new does not
>> have it yet, it is sent for MM testing.
>
> AI review claims to have found a pre-existing critical level deadlock
> in f2fs:
>
> https://sashiko.dev/#/patchset/20260913-remove-pg_private-v4-0-848550f7574e@xxxxxxxxxx
>

drop non f2fs people and lists

Hi Chao, Jaegeuk, and Daeho,

I used LLM locally and discovered the deadlock issue in f2fs (sashiko's report
is overwritten. The fix is below, let me know your thoughts. Thanks.

It applies on top of my other f2fs patches.


From f0c1e94d229a97614738d5c317187bf42a3ff2b2 Mon Sep 17 00:00:00 2001
From: Zi Yan <ziy@xxxxxxxxxx>
Date: Tue, 15 Sep 2026 13:43:35 -0400
Subject: [PATCH] f2fs: fix potential deadlocks in cancel_cluster_writeback()

When f2fs_write_compressed_pages() fails to submit a compressed page, it
calls cancel_cluster_writeback() to end writeback and lock all pages.

cancel_cluster_writeback() relocks unlocked folios in [0, submitted), while
still holding the locks of the folios in [submitted, cluster_size).
The folio locks are no longer held in order of ascending index, violating
the requirement of folio_lock().

cancel_cluster_writeback() also ends folio writeback after taking its lock
for folios in [0, submitted). A deadlock can happen if one like
truncate_inode_pages_range() takes the folio lock and is waiting for the
completion of folio writeback forever.

Fix both by ending writeback and dropping all folio locks first, then
retaking them in ascending index order.

Fixes: 2174035a7f11 ("f2fs: clear writeback when compression failed")
Cc: stable@xxxxxxxxxxxxxxx
Assisted-by: LLM
Signed-off-by: Zi Yan <ziy@xxxxxxxxxx>
To: Jaegeuk Kim <jaegeuk@xxxxxxxxxx>
To: Chao Yu <chao@xxxxxxxxxx>
To: Daeho Jeong <daehojeong@xxxxxxxxxx>
Cc: linux-f2fs-devel@xxxxxxxxxxxxxxxxxxxxx
Cc: linux-kernel@xxxxxxxxxxxxxxx
---
fs/f2fs/compress.c | 20 +++++++++++++++-----
1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c
index 09d9b8d0fdcce..88797dedc96bf 100644
--- a/fs/f2fs/compress.c
+++ b/fs/f2fs/compress.c
@@ -1062,18 +1062,28 @@ static void cancel_cluster_writeback(struct compress_ctx *cc,
f2fs_io_schedule_timeout(DEFAULT_SCHEDULE_TIMEOUT);
}

- /* Cancel writeback and stay locked. */
+ /*
+ * Cancel writeback and lock every folio in the cluster.
+ * Drop the locks on [submitted, cluster_size) before retaking dropped
+ * locks on [0, submitted) to prevent deadlocks.
+ */
for (i = 0; i < cc->cluster_size; i++) {
struct folio *folio = page_folio(cc->rpages[i]);

- if (i < submitted) {
+ if (i < submitted)
inode_inc_dirty_pages(cc->inode);
- folio_lock(folio);
- }
- folio_clear_f2fs_gcing(folio);
+ else
+ folio_unlock(folio);
if (folio_test_writeback(folio))
folio_end_writeback(folio);
}
+ /* Retake all folio locks in ascending order */
+ for (i = 0; i < cc->cluster_size; i++) {
+ struct folio *folio = page_folio(cc->rpages[i]);
+
+ folio_lock(folio);
+ folio_clear_f2fs_gcing(folio);
+ }
}

static void set_cluster_dirty(struct compress_ctx *cc)
--
2.53.0



Best Regards,
Yan, Zi