From: Zi Yan <ziy@nvidia.com>
To: David Hildenbrand <david@kernel.org>,
"Matthew Wilcox (Oracle)" <willy@infradead.org>,
Andrew Morton <akpm@linux-foundation.org>,
Muchun Song <muchun.song@linux.dev>,
Lorenzo Stoakes <ljs@kernel.org>,
"Liam R. Howlett" <liam@infradead.org>,
Vlastimil Babka <vbabka@kernel.org>,
Mike Rapoport <rppt@kernel.org>,
Suren Baghdasaryan <surenb@google.com>,
Michal Hocko <mhocko@suse.com>,
Baolin Wang <baolin.wang@linux.alibaba.com>,
Nico Pache <nico.pache@linux.dev>,
Ryan Roberts <ryan.roberts@arm.com>, Dev Jain <dev.jain@arm.com>,
Barry Song <baohua@kernel.org>,
Lance Yang <lance.yang@linux.dev>,
Usama Arif <usama.arif@linux.dev>,
Gregory Price <gourry@gourry.net>,
Ying Huang <ying.huang@linux.alibaba.com>,
Alistair Popple <apopple@nvidia.com>,
Johannes Weiner <hannes@cmpxchg.org>,
Qi Zheng <qi.zheng@linux.dev>,
Shakeel Butt <shakeel.butt@linux.dev>,
Kairui Song <kasong@tencent.com>
Cc: linux-mm@kvack.org, linux-kernel@vger.kernel.org,
Zi Yan <ziy@nvidia.com>, Steven Rostedt <rostedt@goodmis.org>,
Masami Hiramatsu <mhiramat@kernel.org>, Jan Kara <jack@suse.cz>,
Mathieu Desnoyers <mathieu.desnoyers@efficios.com>,
Matthew Brost <matthew.brost@intel.com>,
Joshua Hahn <joshua.hahnjy@gmail.com>,
Rakie Kim <rakie.kim@sk.com>, Byungchul Park <byungchul@sk.com>,
Axel Rasmussen <axelrasmussen@google.com>,
Yuanchu Xie <yuanchu@google.com>, Wei Xu <weixugc@google.com>,
linux-fsdevel@vger.kernel.org,
linux-trace-kernel@vger.kernel.org
Subject: [PATCH v5 10/17] mm/page-flags: check page/folio->private instead of PG_private
Date: Sun, 20 Sep 2026 22:28:06 -0400 [thread overview]
Message-ID: <20260920-remove-pg_private-v5-10-bb68b6a21869@nvidia.com> (raw)
In-Reply-To: <20260920-remove-pg_private-v5-0-bb68b6a21869@nvidia.com>
After the changes of the prior commits, page/folio->private != NULL is now
equivalent to checking PG_private.
Stop checking PG_private on pages and folios and use page/folio->private
instead, except swapcache and hugetlb folios, because the former uses a
field (swp_entry_t swap) overlapping with ->private and the latter sets its
flags in ->private. Exclude swapcache and hugetlb when the code is meant to
check PG_private only. PG_swapcache and folio->swap.val cannot be set/clear
as a whole, so excluding swapcache with folio_test_swapcache() is not
reliable. Instead, use folio_test_swapbacked(), since PG_swapbacked is
stable when a folio is added to/removed from swapcache. Add a helper,
folio_has_attached_private(), for this check.
folio_test_private() and PagePrivate() now read folio/page->private plainly
instead of an atomic read of PG_private bit, so KCSAN complains about
possible data races. Annotate them with data_race().
folio_expected_ref_count() can be called without the folio lock, so
annotate folio->mapping with data_race() while at it.
folio_set/clear_private() and Set/ClearPagePrivate() become no-ops.
PG_private is no longer checked at page free time. They will be removed in
an upcoming commit.
Remove KPF_PRIVATE since PG_private is no longer used.
Assisted-by: LLM
Signed-off-by: Zi Yan <ziy@nvidia.com>
To: Andrew Morton <akpm@linux-foundation.org>
To: David Hildenbrand <david@kernel.org>
To: Steven Rostedt <rostedt@goodmis.org>
To: Masami Hiramatsu <mhiramat@kernel.org>
To: Lorenzo Stoakes <ljs@kernel.org>
To: "Matthew Wilcox (Oracle)" <willy@infradead.org>
To: Jan Kara <jack@suse.cz>
To: Johannes Weiner <hannes@cmpxchg.org>
Cc: "Liam R. Howlett" <liam@infradead.org>
Cc: Vlastimil Babka <vbabka@kernel.org>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Zi Yan <ziy@nvidia.com>
Cc: Baolin Wang <baolin.wang@linux.alibaba.com>
Cc: Nico Pache <nico.pache@linux.dev>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Cc: Dev Jain <dev.jain@arm.com>
Cc: Barry Song <baohua@kernel.org>
Cc: Lance Yang <lance.yang@linux.dev>
Cc: Usama Arif <usama.arif@linux.dev>
Cc: Matthew Brost <matthew.brost@intel.com>
Cc: Joshua Hahn <joshua.hahnjy@gmail.com>
Cc: Rakie Kim <rakie.kim@sk.com>
Cc: Byungchul Park <byungchul@sk.com>
Cc: Gregory Price <gourry@gourry.net>
Cc: Ying Huang <ying.huang@linux.alibaba.com>
Cc: Alistair Popple <apopple@nvidia.com>
Cc: Qi Zheng <qi.zheng@linux.dev>
Cc: Shakeel Butt <shakeel.butt@linux.dev>
Cc: Kairui Song <kasong@tencent.com>
Cc: Axel Rasmussen <axelrasmussen@google.com>
Cc: Yuanchu Xie <yuanchu@google.com>
Cc: Wei Xu <weixugc@google.com>
Cc: linux-kernel@vger.kernel.org
Cc: linux-fsdevel@vger.kernel.org
Cc: linux-mm@kvack.org
Cc: linux-trace-kernel@vger.kernel.org
---
fs/proc/page.c | 1 -
include/linux/kernel-page-flags.h | 1 -
include/linux/mm.h | 19 ++++++++-----
include/linux/page-flags.h | 57 ++++++++++++++++++++++++++++++++++-----
include/trace/events/pagemap.h | 2 +-
mm/huge_memory.c | 2 +-
mm/migrate.c | 2 +-
mm/page-writeback.c | 2 +-
mm/vmscan.c | 2 +-
tools/mm/page-types.c | 2 --
10 files changed, 68 insertions(+), 22 deletions(-)
diff --git a/fs/proc/page.c b/fs/proc/page.c
index 260772b20bd99..f90e1030825e9 100644
--- a/fs/proc/page.c
+++ b/fs/proc/page.c
@@ -232,7 +232,6 @@ u64 stable_page_flags(const struct page *page)
u |= kpf_copy_bit(k, KPF_RESERVED, PG_reserved);
u |= kpf_copy_bit(k, KPF_OWNER_2, PG_owner_2);
- u |= kpf_copy_bit(k, KPF_PRIVATE, PG_private);
u |= kpf_copy_bit(k, KPF_PRIVATE_2, PG_private_2);
u |= kpf_copy_bit(k, KPF_OWNER_PRIVATE, PG_owner_priv_1);
u |= kpf_copy_bit(k, KPF_ARCH, PG_arch_1);
diff --git a/include/linux/kernel-page-flags.h b/include/linux/kernel-page-flags.h
index 196778a087c4d..fe5ab6e50bd70 100644
--- a/include/linux/kernel-page-flags.h
+++ b/include/linux/kernel-page-flags.h
@@ -11,7 +11,6 @@
#define KPF_RESERVED 32
#define KPF_MLOCKED 33
#define KPF_OWNER_2 34
-#define KPF_PRIVATE 35
#define KPF_PRIVATE_2 36
#define KPF_OWNER_PRIVATE 37
#define KPF_ARCH 38
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 66d384da4433b..d9392ac8dff9f 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -3004,9 +3004,9 @@ static inline bool folio_maybe_mapped_shared(struct folio *folio)
* @folio: the folio
*
* Calculate the expected folio refcount, taking references from the pagecache,
- * swapcache, PG_private and page table mappings into account. Useful in
- * combination with folio_ref_count() to detect unexpected references (e.g.,
- * GUP or other temporary references).
+ * swapcache, private data (folio->private != NULL) and page table mappings into
+ * account. Useful in combination with folio_ref_count() to detect unexpected
+ * references (e.g., GUP or other temporary references).
*
* Does currently not consider references from the LRU cache. If the folio
* was isolated from the LRU (which is the case during migration or split),
@@ -3044,10 +3044,15 @@ static inline int folio_expected_ref_count(const struct folio *folio)
ref_count += folio_test_swapcache(folio) << order;
if (!folio_test_anon(folio)) {
- /* One reference per page from the pagecache. */
- ref_count += !!folio->mapping << order;
- /* One reference from PG_private. */
- ref_count += folio_test_private(folio);
+ /*
+ * One reference per page from the pagecache.
+ * Use data_race() since folio might not be locked.
+ */
+ ref_count += !!data_race(folio->mapping) << order;
+ /*
+ * One reference from filesystem private data.
+ */
+ ref_count += folio_has_attached_private(folio);
}
/* One reference per page table mapping. */
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
index 7080a6a1a79e7..6d839f50bdcb7 100644
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -575,9 +575,31 @@ FOLIO_FLAG(swapbacked, FOLIO_HEAD_PAGE)
/*
* Private page markings that may be used by the filesystem that owns the page
* for its own purposes.
- * - PG_private and PG_private_2 cause release_folio() and co to be invoked
+ * - folio->private and PG_private_2 cause release_folio() and co to be invoked
*/
-PAGEFLAG(Private, private, PF_ANY)
+
+static __always_inline bool folio_test_private(const struct folio *folio)
+{
+ /*
+ * data_race() is added for readers without holding the folio lock.
+ * Only the NULL/non-NULL answer is used and both are valid while
+ * private is being attached or detached, so the race is benign.
+ */
+ return data_race(folio->private);
+}
+
+static __always_inline int PagePrivate(const struct page *page)
+{
+ /* See folio_test_private() for data_race() use */
+ return !!data_race(page->private);
+}
+
+/* no-ops during transition */
+static __always_inline void folio_set_private(struct folio *folio) { }
+static __always_inline void folio_clear_private(struct folio *folio) { }
+static __always_inline void SetPagePrivate(struct page *page) { }
+static __always_inline void ClearPagePrivate(struct page *page) { }
+
FOLIO_FLAG(private_2, FOLIO_HEAD_PAGE)
/* owner_2 can be set on tail pages for anon memory */
@@ -1169,7 +1191,7 @@ static __always_inline void __ClearPageAnonExclusive(struct page *page)
*/
#define PAGE_FLAGS_CHECK_AT_FREE \
(1UL << PG_lru | 1UL << PG_locked | \
- 1UL << PG_private | 1UL << PG_private_2 | \
+ 1UL << PG_private_2 | \
1UL << PG_writeback | 1UL << PG_reserved | \
1UL << PG_active | \
1UL << PG_unevictable | __PG_MLOCKED | LRU_GEN_MASK)
@@ -1193,8 +1215,31 @@ static __always_inline void __ClearPageAnonExclusive(struct page *page)
(0xffUL /* order */ | 1UL << PG_has_hwpoisoned | \
1UL << PG_large_rmappable | 1UL << PG_partially_mapped)
-#define PAGE_FLAGS_PRIVATE \
- (1UL << PG_private | 1UL << PG_private_2)
+/**
+ * folio_has_attached_private - check if the folio has private data attached
+ * @folio: The folio to check.
+ *
+ * Use this in code that may encounter swapcache or hugetlb folios but only
+ * wants to detect attached private data.
+ *
+ * Return: true if the folio has private data attached.
+ */
+static inline bool folio_has_attached_private(const struct folio *folio)
+{
+ /*
+ * Swapcache stores swp_entry_t in folio->swap, a union with
+ * folio->private, and hugetlb stores its own flags in folio->private;
+ * both are excluded.
+ *
+ * NOTE: For swapcache, folio->swap.val PG_swapcache are not set as
+ * a whole, so folio_test_swapcache() is not reliable to exclude
+ * swapcache. Use folio_test_swapbacked() instead, since it remains set
+ * when a folio is added to/removed from swapcache.
+ */
+
+ return folio_test_private(folio) && !folio_test_swapbacked(folio) &&
+ !folio_test_hugetlb(folio);
+}
/**
* folio_has_private - Determine if folio has private stuff
* @folio: The folio to be checked
@@ -1204,7 +1249,7 @@ static __always_inline void __ClearPageAnonExclusive(struct page *page)
*/
static inline int folio_has_private(const struct folio *folio)
{
- return !!(folio->flags.f & PAGE_FLAGS_PRIVATE);
+ return folio_has_attached_private(folio) || folio_test_private_2(folio);
}
#undef PF_ANY
diff --git a/include/trace/events/pagemap.h b/include/trace/events/pagemap.h
index 36c3a90f0acca..5d47b774633a4 100644
--- a/include/trace/events/pagemap.h
+++ b/include/trace/events/pagemap.h
@@ -22,7 +22,7 @@
(folio_test_swapcache(folio) ? PAGEMAP_SWAPCACHE : 0) | \
(folio_test_swapbacked(folio) ? PAGEMAP_SWAPBACKED : 0) | \
(folio_test_mappedtodisk(folio) ? PAGEMAP_MAPPEDDISK : 0) | \
- (folio_test_private(folio) ? PAGEMAP_BUFFERS : 0) \
+ (folio_has_attached_private(folio) ? PAGEMAP_BUFFERS : 0) \
)
TRACE_EVENT(mm_lru_insertion,
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 30b7c63b0e359..8aa2daba37391 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -4846,7 +4846,7 @@ static int split_huge_pages_pid(int pid, unsigned long vaddr_start,
* will try to drop it before split and then check if the folio
* can be split or not. So skip the check here.
*/
- if (!folio_test_private(folio) &&
+ if (!folio_has_attached_private(folio) &&
folio_expected_ref_count(folio) != folio_ref_count(folio))
goto next;
diff --git a/mm/migrate.c b/mm/migrate.c
index a369d0c95c386..b7b92925a28c3 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -1327,7 +1327,7 @@ static int migrate_folio_unmap(new_folio_t get_new_folio,
* free the metadata, so the page can be freed.
*/
if (!src->mapping) {
- if (folio_test_private(src)) {
+ if (folio_has_attached_private(src)) {
try_to_free_buffers(src);
goto out;
}
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index eeab25d6ce364..499a35473e4f3 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -2705,7 +2705,7 @@ bool filemap_dirty_folio(struct address_space *mapping, struct folio *folio)
if (folio_test_set_dirty(folio))
return false;
- __folio_mark_dirty(folio, mapping, !folio_test_private(folio));
+ __folio_mark_dirty(folio, mapping, !folio_has_attached_private(folio));
if (mapping->host) {
/* !PageAnon && !swapper_space */
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 80041e2b8049c..dd6261c862794 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -1029,7 +1029,7 @@ static void folio_check_dirty_writeback(struct folio *folio,
*writeback = folio_test_writeback(folio);
/* Verify dirty/writeback state if the filesystem supports it */
- if (!folio_test_private(folio))
+ if (!folio_has_attached_private(folio))
return;
mapping = folio_mapping(folio);
diff --git a/tools/mm/page-types.c b/tools/mm/page-types.c
index 7fc5a8be5997f..47e4781c5fc38 100644
--- a/tools/mm/page-types.c
+++ b/tools/mm/page-types.c
@@ -73,7 +73,6 @@
#define KPF_RESERVED 32
#define KPF_MLOCKED 33
#define KPF_OWNER_2 34
-#define KPF_PRIVATE 35
#define KPF_PRIVATE_2 36
#define KPF_OWNER_PRIVATE 37
#define KPF_ARCH 38
@@ -131,7 +130,6 @@ static const char * const page_flag_names[] = {
[KPF_RESERVED] = "r:reserved",
[KPF_MLOCKED] = "m:mlocked",
[KPF_OWNER_2] = "d:owner_2",
- [KPF_PRIVATE] = "P:private",
[KPF_PRIVATE_2] = "p:private_2",
[KPF_OWNER_PRIVATE] = "O:owner_private",
[KPF_ARCH] = "h:arch",
--
2.53.0
next prev parent reply other threads:[~2026-09-21 2:28 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-21 2:27 [PATCH v5 00/17] Remove PG_private by using page/folio->private checks instead Zi Yan
2026-09-21 2:27 ` [PATCH v5 01/17] mm/zsmalloc: replace PG_private with pointer comparison Zi Yan
2026-09-21 6:02 ` Lance Yang
2026-09-21 2:27 ` [PATCH v5 02/17] perf/ring_buffer: stop using PG_private as AUX page high-order marker Zi Yan
2026-09-21 6:19 ` Lance Yang
2026-09-21 2:27 ` [PATCH v5 03/17] xen/grant-table: stop setting PG_private on pages for grant mapping Zi Yan
2026-09-21 7:00 ` Lance Yang
2026-09-21 2:28 ` [PATCH v5 04/17] fscrypt: stop setting PG_private on bounce page Zi Yan
2026-09-21 7:03 ` Lance Yang
2026-09-21 2:28 ` [PATCH v5 05/17] mm/hugetlb: use direct assignment instead of folio_change_private() Zi Yan
2026-09-21 7:11 ` Lance Yang
2026-09-21 2:28 ` [PATCH v5 06/17] f2fs: stop using PG_private Zi Yan
2026-09-21 7:24 ` Lance Yang
2026-09-21 2:28 ` [PATCH v5 07/17] f2fs: convert the ->private flag helpers to folio-only Zi Yan
2026-09-21 7:39 ` Lance Yang
2026-09-21 2:28 ` [PATCH v5 08/17] erofs: mm/pagemap: add readahead_folio_last() to avoid folio->private Zi Yan
2026-09-21 8:20 ` Lance Yang
2026-09-21 2:28 ` [PATCH v5 09/17] erofs: use folio_attach/detach_private() instead of direct assignment Zi Yan
2026-09-21 8:45 ` Lance Yang
2026-09-21 2:28 ` Zi Yan [this message]
2026-09-21 9:22 ` [PATCH v5 10/17] mm/page-flags: check page/folio->private instead of PG_private David Hildenbrand (Arm)
2026-09-21 2:28 ` [PATCH v5 11/17] treewide: remove folio_set/clear_private() usage Zi Yan
2026-09-21 2:28 ` [PATCH v5 12/17] ceph: replace PagePrivate() with page_private() Zi Yan
2026-09-21 2:28 ` [PATCH v5 13/17] md: Use folio_alloc_buffers() Zi Yan
2026-09-21 9:23 ` David Hildenbrand (Arm)
2026-09-21 2:28 ` [PATCH v5 14/17] md: Use folio APIs in free_page() Zi Yan
2026-09-21 2:28 ` [PATCH v5 15/17] md: Remove the last use of page_buffers() Zi Yan
2026-09-21 2:28 ` [PATCH v5 16/17] treewide: remove PagePrivate() and PG_private from comments and docs Zi Yan
2026-09-21 2:28 ` [PATCH v5 17/17] mm/page-flags: remove PG_private Zi Yan
2026-09-21 2:55 ` sashiko-bot
2026-09-21 15:36 ` Zi Yan
2026-09-21 4:08 ` [PATCH v5 00/17] Remove PG_private by using page/folio->private checks instead Andrew Morton
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260920-remove-pg_private-v5-10-bb68b6a21869@nvidia.com \
--to=ziy@nvidia.com \
--cc=akpm@linux-foundation.org \
--cc=apopple@nvidia.com \
--cc=axelrasmussen@google.com \
--cc=baohua@kernel.org \
--cc=baolin.wang@linux.alibaba.com \
--cc=byungchul@sk.com \
--cc=david@kernel.org \
--cc=dev.jain@arm.com \
--cc=gourry@gourry.net \
--cc=hannes@cmpxchg.org \
--cc=jack@suse.cz \
--cc=joshua.hahnjy@gmail.com \
--cc=kasong@tencent.com \
--cc=lance.yang@linux.dev \
--cc=liam@infradead.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=linux-trace-kernel@vger.kernel.org \
--cc=ljs@kernel.org \
--cc=mathieu.desnoyers@efficios.com \
--cc=matthew.brost@intel.com \
--cc=mhiramat@kernel.org \
--cc=mhocko@suse.com \
--cc=muchun.song@linux.dev \
--cc=nico.pache@linux.dev \
--cc=qi.zheng@linux.dev \
--cc=rakie.kim@sk.com \
--cc=rostedt@goodmis.org \
--cc=rppt@kernel.org \
--cc=ryan.roberts@arm.com \
--cc=shakeel.butt@linux.dev \
--cc=surenb@google.com \
--cc=usama.arif@linux.dev \
--cc=vbabka@kernel.org \
--cc=weixugc@google.com \
--cc=willy@infradead.org \
--cc=ying.huang@linux.alibaba.com \
--cc=yuanchu@google.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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®