zsmalloc uses PG_private to indicate first zpdesc in the zspage chain. Replace it with zpdesc->zspage->first_zpdesc == zpdesc. The check, is_first_zpdesc(), is only used in VM_BUG_ON(), so performance impact should be negligible. It prepares for a future commit that remove PG_private. No functional change intended. Assisted-by: Claude:claude-opus-4-8 Assisted-by: Codex:gpt-5 Signed-off-by: Zi Yan To: Minchan Kim To: Sergey Senozhatsky To: Andrew Morton Cc: linux-mm@kvack.org Cc: linux-kernel@vger.kernel.org --- mm/zpdesc.h | 2 +- mm/zsmalloc.c | 15 +++------------ 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/mm/zpdesc.h b/mm/zpdesc.h index b8258dc78548d..4fd81c2e80769 100644 --- a/mm/zpdesc.h +++ b/mm/zpdesc.h @@ -26,8 +26,8 @@ * with memcg_data. * * Page flags used: - * * PG_private identifies the first component page. * * PG_locked is used by page migration code. + * The first component page has zpdesc->zspage->first_zpdesc == zpdesc */ struct zpdesc { unsigned long flags; diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c index 8204b76f78308..e8ef227624efa 100644 --- a/mm/zsmalloc.c +++ b/mm/zsmalloc.c @@ -290,11 +290,6 @@ struct zs_pool { atomic_t compaction_in_progress; }; -static inline void zpdesc_set_first(struct zpdesc *zpdesc) -{ - SetPagePrivate(zpdesc_page(zpdesc)); -} - static inline void zpdesc_inc_zone_page_state(struct zpdesc *zpdesc) { inc_zone_page_state(zpdesc_page(zpdesc), NR_ZSPAGES); @@ -478,7 +473,7 @@ static void record_obj(unsigned long handle, unsigned long obj) static inline bool __maybe_unused is_first_zpdesc(struct zpdesc *zpdesc) { - return PagePrivate(zpdesc_page(zpdesc)); + return zpdesc->zspage->first_zpdesc == zpdesc; } /* Protected by class->lock */ @@ -848,9 +843,6 @@ static inline bool obj_allocated(struct zpdesc *zpdesc, void *obj, static void reset_zpdesc(struct zpdesc *zpdesc) { - struct page *page = zpdesc_page(zpdesc); - - ClearPagePrivate(page); zpdesc->zspage = NULL; zpdesc->next = NULL; /* PageZsmalloc is sticky until the page is freed to the buddy. */ @@ -1001,8 +993,8 @@ static void create_page_chain(struct size_class *class, struct zspage *zspage, * 1. all pages are linked together using zpdesc->next * 2. each sub-page point to zspage using zpdesc->zspage * - * we set PG_private to identify the first zpdesc (i.e. no other zpdesc - * has this flag set). + * The first zpdesc has its zspage->first_zpdesc set to itself, no + * other zpdesc has this set. */ for (i = 0; i < nr_zpdescs; i++) { zpdesc = zpdescs[i]; @@ -1010,7 +1002,6 @@ static void create_page_chain(struct size_class *class, struct zspage *zspage, zpdesc->next = NULL; if (i == 0) { zspage->first_zpdesc = zpdesc; - zpdesc_set_first(zpdesc); if (unlikely(class->objs_per_zspage == 1 && class->pages_per_zspage == 1)) SetZsHugePage(zspage); -- 2.53.0 A high-order AUX page sets PG_private on its first page and stores the order in first_page->private. Stop using PG_private and check first_page->private for AUX page order only ring buffer and its users. It prepares for a future commit that remove PG_private. No functional change intended. Assisted-by: Claude:claude-opus-4-8 Assisted-by: Codex:gpt-5 Signed-off-by: Zi Yan To: Peter Zijlstra To: Ingo Molnar To: Arnaldo Carvalho de Melo To: Namhyung Kim To: Thomas Gleixner To: Borislav Petkov To: Dave Hansen To: x86@kernel.org Cc: Mark Rutland Cc: Alexander Shishkin Cc: Jiri Olsa Cc: Ian Rogers Cc: Adrian Hunter Cc: James Clark Cc: "H. Peter Anvin" Cc: linux-perf-users@vger.kernel.org Cc: linux-kernel@vger.kernel.org --- arch/x86/events/intel/bts.c | 3 --- arch/x86/events/intel/pt.c | 6 ++---- kernel/events/ring_buffer.c | 7 +++---- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/arch/x86/events/intel/bts.c b/arch/x86/events/intel/bts.c index cbac54cb3a9ec..5849392cf26d5 100644 --- a/arch/x86/events/intel/bts.c +++ b/arch/x86/events/intel/bts.c @@ -66,9 +66,6 @@ static struct pmu bts_pmu; static int buf_nr_pages(struct page *page) { - if (!PagePrivate(page)) - return 1; - return 1 << page_private(page); } diff --git a/arch/x86/events/intel/pt.c b/arch/x86/events/intel/pt.c index b5726b50e77db..29d8b4a3560cd 100644 --- a/arch/x86/events/intel/pt.c +++ b/arch/x86/events/intel/pt.c @@ -774,8 +774,7 @@ static int topa_insert_pages(struct pt_buffer *buf, int cpu, gfp_t gfp) struct page *p; p = virt_to_page(buf->data_pages[buf->nr_pages]); - if (PagePrivate(p)) - order = page_private(p); + order = page_private(p); if (topa_table_full(topa)) { topa = topa_alloc(cpu, gfp); @@ -1289,8 +1288,7 @@ static int pt_buffer_try_single(struct pt_buffer *buf, int nr_pages) if (!intel_pt_validate_hw_cap(PT_CAP_single_range_output)) goto out; - if (PagePrivate(p)) - order = page_private(p); + order = page_private(p); if (1 << order != nr_pages) goto out; diff --git a/kernel/events/ring_buffer.c b/kernel/events/ring_buffer.c index 9fe92161715e0..061b5cb222266 100644 --- a/kernel/events/ring_buffer.c +++ b/kernel/events/ring_buffer.c @@ -630,11 +630,10 @@ static struct page *rb_alloc_aux_page(int node, int order) /* * Communicate the allocation size to the driver: * if we managed to secure a high-order allocation, - * set its first page's private to this order; - * !PagePrivate(page) means it's just a normal page. + * set its first page's private to this order, otherwise page's + * private remains zero. */ split_page(page, order); - SetPagePrivate(page); set_page_private(page, order); } @@ -645,7 +644,7 @@ static void rb_free_aux_page(struct perf_buffer *rb, int idx) { struct page *page = virt_to_page(rb->aux_pages[idx]); - ClearPagePrivate(page); + set_page_private(page, 0); __free_page(page); } -- 2.53.0 gnttab_alloc_pages() stores xen_page_foreign in allocated page->private. On 32-bit, a pointer to xen_page_foreign is stored; on 64-bit, xen_page_foreign is stored inline. Checking page->private != NULL is enough to tell whether a xen_page_foreign needs to be freed on 32-bit and page->private is zeroed unconditionally on 64-bit. It prepares for a future commit that remove PG_private. No funtional change intended. Assisted-by: Claude:claude-opus-4-8 Assisted-by: Codex:gpt-5 Signed-off-by: Zi Yan To: Juergen Gross To: Stefano Stabellini Cc: Oleksandr Tyshchenko Cc: xen-devel@lists.xenproject.org Cc: linux-kernel@vger.kernel.org --- drivers/xen/balloon.c | 5 +++++ drivers/xen/grant-table.c | 7 +++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index e7f1d4ca6d753..7f47b0ad05607 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c @@ -182,6 +182,11 @@ static struct page *balloon_retrieve(bool require_lowmem) __ClearPageOffline(page); dec_node_page_state(page, NR_BALLOON_PAGES); + /* + * clear page->private before giving it out, since it might be used to + * store xen_page_foreign info. + */ + set_page_private(page, 0); return page; } diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c index 35f879dc5dfb8..cc348ba2e0786 100644 --- a/drivers/xen/grant-table.c +++ b/drivers/xen/grant-table.c @@ -875,7 +875,7 @@ int gnttab_pages_set_private(int nr_pages, struct page **pages) set_page_private(pages[i], (unsigned long)foreign); #endif - SetPagePrivate(pages[i]); + /* Data is stored in page->private on 64-bit */ } return 0; @@ -1031,12 +1031,11 @@ void gnttab_pages_clear_private(int nr_pages, struct page **pages) int i; for (i = 0; i < nr_pages; i++) { - if (PagePrivate(pages[i])) { #if BITS_PER_LONG < 64 + if (page_private(pages[i])) kfree((void *)page_private(pages[i])); #endif - ClearPagePrivate(pages[i]); - } + set_page_private(pages[i], 0); } } EXPORT_SYMBOL_GPL(gnttab_pages_clear_private); -- 2.53.0 The point to a plaintext folio is stored in page->private and cannot be NULL, making PG_private redundant. It prepares for a future commit that remove PG_private. No funtional change intended. Assisted-by: Claude:claude-opus-4-8 Assisted-by: Codex:gpt-5 Signed-off-by: Zi Yan To: Eric Biggers To: "Theodore Y. Ts'o" To: Jaegeuk Kim Cc: linux-fscrypt@vger.kernel.org Cc: linux-kernel@vger.kernel.org --- fs/crypto/crypto.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index 570a2231c945a..c8a98dd94650f 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c @@ -73,7 +73,6 @@ void fscrypt_free_bounce_page(struct page *bounce_page) if (!bounce_page) return; set_page_private(bounce_page, (unsigned long)NULL); - ClearPagePrivate(bounce_page); mempool_free(bounce_page, fscrypt_bounce_page_pool); } EXPORT_SYMBOL(fscrypt_free_bounce_page); @@ -202,7 +201,6 @@ struct page *fscrypt_encrypt_pagecache_blocks(struct folio *folio, return ERR_PTR(err); } } - SetPagePrivate(ciphertext_page); set_page_private(ciphertext_page, (unsigned long)folio); return ciphertext_page; } -- 2.53.0 folio_change_private() should be used along with folio_attach_private() and folio_detach_private(), where adding and remove ->private content requires folio refcount change. add_hugetlb_folio() simply sets folio->private to NULL without refcount manipulation. Change it to direct assignment to avoid semantic confusion. It prepares for a future commit that remove PG_private. No funtional change intended. Assisted-by: Claude:claude-opus-4-8 Assisted-by: Codex:gpt-5 Signed-off-by: Zi Yan To: Muchun Song To: Oscar Salvador To: Andrew Morton Cc: David Hildenbrand Cc: linux-mm@kvack.org Cc: linux-kernel@vger.kernel.org --- mm/hugetlb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mm/hugetlb.c b/mm/hugetlb.c index a77c3c1cb8943..0abaeb47890cb 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -1433,10 +1433,10 @@ void add_hugetlb_folio(struct hstate *h, struct folio *folio, } __folio_set_hugetlb(folio); - folio_change_private(folio, NULL); + folio->private = NULL; /* - * We have to set hugetlb_vmemmap_optimized again as above - * folio_change_private(folio, NULL) cleared it. + * We have to set hugetlb_vmemmap_optimized again as hugetlb page flags + * are all cleared above. */ folio_set_hugetlb_vmemmap_optimized(folio); -- 2.53.0 f2fs sets its PAGE_PRIVATE_* flags in page->private and checking page->private != NULL is equivalent to checking PG_private. Change PagePrivate() to page_private(). Meanwhile, in set_page_private_##name(), page->private is first set to 0/NULL before an PAGE_PRIVATE_* flag is set, but it can cause confusion when PG_private is removed and page->private != NULL is used instead. Change it to initialize page->private to PAGE_PRIVATE_NOT_POINTER instead and retain the original semantics. 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 To: Jaegeuk Kim To: Chao Yu Cc: linux-f2fs-devel@lists.sourceforge.net Cc: linux-kernel@vger.kernel.org --- fs/f2fs/f2fs.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 8f3e632f315cc..edf01eb4b3b30 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -2643,7 +2643,7 @@ static inline bool folio_test_f2fs_##name(const struct folio *folio) \ } \ static inline bool page_private_##name(struct page *page) \ { \ - return PagePrivate(page) && \ + return page_private(page) && \ test_bit(PAGE_PRIVATE_NOT_POINTER, &page_private(page)) && \ test_bit(PAGE_PRIVATE_##flagname, &page_private(page)); \ } @@ -2662,9 +2662,9 @@ static inline void folio_set_f2fs_##name(struct folio *folio) \ } \ static inline void set_page_private_##name(struct page *page) \ { \ - if (!PagePrivate(page)) \ - attach_page_private(page, (void *)0); \ - set_bit(PAGE_PRIVATE_NOT_POINTER, &page_private(page)); \ + if (!page_private(page)) \ + attach_page_private(page, \ + (void *)BIT(PAGE_PRIVATE_NOT_POINTER)); \ set_bit(PAGE_PRIVATE_##flagname, &page_private(page)); \ } -- 2.53.0 erofs needs to traverse readahead folios in reverse order to achieve maximum performance by 1. reading all folios from readahead_folio(); 2. storing the prior folio pointer in folio->private; 3. traverse from the last folio to the first one. Add readahead_folio_reverse() to achieve the same function without using folio->private. It prepares for a future commit that replaces PG_private checks with !folio->private checks. After switching the checks, erofs's use of folio->private without bumping folio refcount can cause unexpected outcomes, e.g., in filemap_release_folio(), try_to_free_buffers() becomes reachable. No funtional change intended. Assisted-by: Claude:claude-opus-4-8 Assisted-by: Codex:gpt-5 Signed-off-by: Zi Yan To: Gao Xiang To: Chao Yu To: "Matthew Wilcox (Oracle)" To: Jan Kara Cc: Yue Hu Cc: Jeffle Xu Cc: Sandeep Dhavale Cc: Hongbo Li Cc: Chunhai Guo Cc: linux-erofs@lists.ozlabs.org Cc: linux-kernel@vger.kernel.org Cc: linux-fsdevel@vger.kernel.org Cc: linux-mm@kvack.org --- fs/erofs/zdata.c | 11 ++--------- include/linux/pagemap.h | 31 +++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c index 74520e9102596..b59f2745a8e72 100644 --- a/fs/erofs/zdata.c +++ b/fs/erofs/zdata.c @@ -1902,21 +1902,14 @@ static void z_erofs_readahead(struct readahead_control *rac) struct inode *realinode = erofs_real_inode(sharedinode, &need_iput); Z_EROFS_DEFINE_FRONTEND(f, realinode, sharedinode, readahead_pos(rac)); unsigned int nrpages = readahead_count(rac); - struct folio *head = NULL, *folio; + struct folio *folio; int err; trace_erofs_readahead(realinode, readahead_index(rac), nrpages, false); z_erofs_pcluster_readmore(&f, rac, true); - while ((folio = readahead_folio(rac))) { - folio->private = head; - head = folio; - } /* traverse in reverse order for best metadata I/O performance */ - while (head) { - folio = head; - head = folio_get_private(folio); - + while ((folio = readahead_folio_reverse(rac))) { err = z_erofs_scan_folio(&f, folio, true); if (err && err != -EINTR) erofs_err(realinode->i_sb, "readahead error at folio %lu @ nid %llu", diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h index 4e8b2b29f6d3e..90904a4d173b7 100644 --- a/include/linux/pagemap.h +++ b/include/linux/pagemap.h @@ -1549,6 +1549,37 @@ static inline struct folio *readahead_folio(struct readahead_control *ractl) return folio; } +/** + * readahead_folio_reverse - Get the next folio to read, from the tail. + * @ractl: The current readahead request. + * + * Like readahead_folio(), but walks the range back-to-front. The folio is + * returned locked with its refcount dropped; the caller unlocks it once I/O + * completes. Compound folios are returned once, at their head index. + * + * Context: The folio is locked. + * Return: A pointer to the next folio, or %NULL when done. + */ +static inline struct folio *readahead_folio_reverse(struct readahead_control *ractl) +{ + struct folio *folio; + + if (!ractl->_nr_pages) + return NULL; + + /* xa_load() follows sibling entries, so a tail index returns the head */ + folio = xa_load(&ractl->mapping->i_pages, + ractl->_index + ractl->_nr_pages - 1); + VM_WARN_ON_ONCE_FOLIO(!folio_test_locked(folio), folio); + + /* Shrink the window from the tail down to this folio's head index */ + ractl->_nr_pages = folio->index - ractl->_index; + ractl->_batch_count = 0; + + folio_put(folio); + return folio; +} + static inline unsigned int __readahead_batch(struct readahead_control *rac, struct page **array, unsigned int array_sz) { -- 2.53.0 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 To: Gao Xiang To: Chao Yu Cc: Yue Hu Cc: Jeffle Xu Cc: Sandeep Dhavale Cc: Hongbo Li Cc: Chunhai Guo Cc: linux-erofs@lists.ozlabs.org Cc: linux-kernel@vger.kernel.org --- fs/erofs/data.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/erofs/data.c b/fs/erofs/data.c index 9aa48c8d67d12..356665f025fb9 100644 --- a/fs/erofs/data.c +++ b/fs/erofs/data.c @@ -263,7 +263,8 @@ void erofs_onlinefolio_init(struct folio *folio) void *v; } u = { .o = ATOMIC_INIT(1) }; - 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) @@ -284,7 +285,7 @@ void erofs_onlinefolio_end(struct folio *folio, int err, bool dirty) if (v & (BIT(EROFS_ONLINEFOLIO_DIRTY) - 1)) 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 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. folio_set/clear_private() and Set/ClearPagePrivate() become no-ops. PG_private is no longer checked at page free time. KPF_PRIVATE exposes PG_private to userspace. Change its code logic to check folio->private != NULL and exclude non-pagecache, swapcache, hugetlb, and anon folios. One minor semantic change, for orphaned pagecache folios (mapping == NULL) with fs-private data will no longer have KPF_PRIVATE. Assisted-by: Claude:claude-opus-4-8 Assisted-by: Codex:gpt-5 Signed-off-by: Zi Yan To: Andrew Morton To: David Hildenbrand To: Steven Rostedt To: Masami Hiramatsu To: Lorenzo Stoakes To: "Matthew Wilcox (Oracle)" To: Jan Kara To: Johannes Weiner Cc: "Liam R. Howlett" Cc: Vlastimil Babka Cc: Mike Rapoport Cc: Suren Baghdasaryan Cc: Michal Hocko Cc: Mathieu Desnoyers Cc: Zi Yan Cc: Baolin Wang Cc: Nico Pache Cc: Ryan Roberts Cc: Dev Jain Cc: Barry Song Cc: Lance Yang Cc: Usama Arif Cc: Matthew Brost Cc: Joshua Hahn Cc: Rakie Kim Cc: Byungchul Park Cc: Gregory Price Cc: Ying Huang Cc: Alistair Popple Cc: Qi Zheng Cc: Shakeel Butt Cc: Kairui Song Cc: Axel Rasmussen Cc: Yuanchu Xie Cc: Wei Xu 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 | 6 +++++- include/linux/mm.h | 11 ++++++----- include/linux/page-flags.h | 26 +++++++++++++++++++++----- include/trace/events/pagemap.h | 4 +++- mm/huge_memory.c | 4 +++- mm/migrate.c | 3 ++- mm/page-writeback.c | 5 ++++- mm/vmscan.c | 3 ++- 8 files changed, 46 insertions(+), 16 deletions(-) diff --git a/fs/proc/page.c b/fs/proc/page.c index 260772b20bd99..abfa6f7d890cc 100644 --- a/fs/proc/page.c +++ b/fs/proc/page.c @@ -232,7 +232,11 @@ 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); + /* preserve the original KPF_PRIVATE semantics by excluding non pagecache folios */ + if (folio->mapping && !folio_test_anon(folio) && + (folio_get_private(folio) && !folio_test_swapcache(folio) && + !folio_test_hugetlb(folio))) + u |= BIT_ULL(KPF_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/mm.h b/include/linux/mm.h index 7fabe6c66b4b7..ebc035ac26ccc 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -2961,9 +2961,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), @@ -3003,8 +3003,9 @@ static inline int folio_expected_ref_count(const struct folio *folio) 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 from filesystem private data. */ + ref_count += !!folio->private && !folio_test_hugetlb(folio) && + !folio_test_swapcache(folio); } /* One reference per page table mapping. */ diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h index 7a863572adce7..8efc61f967302 100644 --- a/include/linux/page-flags.h +++ b/include/linux/page-flags.h @@ -578,7 +578,23 @@ FOLIO_FLAG(swapbacked, FOLIO_HEAD_PAGE) * for its own purposes. * - PG_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) +{ + return folio->private; +} + +static __always_inline int PagePrivate(const struct page *page) +{ + return !!page_private(page); +} + +/* 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 */ @@ -1170,7 +1186,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) @@ -1194,8 +1210,6 @@ 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_private - Determine if folio has private stuff * @folio: The folio to be checked @@ -1205,7 +1219,9 @@ 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->private && !folio_test_swapcache(folio) && + !folio_test_hugetlb(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..fb9abec40ec79 100644 --- a/include/trace/events/pagemap.h +++ b/include/trace/events/pagemap.h @@ -22,7 +22,9 @@ (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_test_private(folio) && \ + !folio_test_swapcache(folio) && \ + !folio_test_hugetlb(folio) ? PAGEMAP_BUFFERS : 0) \ ) TRACE_EVENT(mm_lru_insertion, diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 21c92ee48e469..d21a9b8f40d15 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -4799,7 +4799,9 @@ 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_test_private(folio) && + !folio_test_swapcache(folio) && + !folio_test_hugetlb(folio)) && folio_expected_ref_count(folio) != folio_ref_count(folio)) goto next; diff --git a/mm/migrate.c b/mm/migrate.c index b937cbd764808..ad5daef8721cf 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -1330,7 +1330,8 @@ 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_test_private(src) && !folio_test_swapcache(src) && + !folio_test_hugetlb(src)) { try_to_free_buffers(src); goto out; } diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 47495be68598f..b44468383f900 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -2706,7 +2706,10 @@ 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_test_private(folio) && + !folio_test_swapcache(folio) && + !folio_test_hugetlb(folio))); if (mapping->host) { /* !PageAnon && !swapper_space */ diff --git a/mm/vmscan.c b/mm/vmscan.c index 17d2b793cbfc4..ab059a2c6ea35 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -954,7 +954,8 @@ 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_test_private(folio) && !folio_test_swapcache(folio) && + !folio_test_hugetlb(folio))) return; mapping = folio_mapping(folio); -- 2.53.0 folio_test_fs_private() wraps folio->private != NULL check and excludes swapcache and hugetlb folios, since swapcache uses swp_entry_t overlapping with folio->private and hugetlb sets its own flags in folio->private. Replace open code with the helper, since core MM does this check frequently. No functional change intended. Assisted-by: Claude:claude-opus-4-8 Assisted-by: Codex:gpt-5 Signed-off-by: Zi Yan To: Andrew Morton To: David Hildenbrand To: Steven Rostedt To: Masami Hiramatsu To: Lorenzo Stoakes Cc: "Liam R. Howlett" Cc: Vlastimil Babka Cc: Mike Rapoport Cc: Suren Baghdasaryan Cc: Michal Hocko Cc: Mathieu Desnoyers Cc: Zi Yan Cc: Baolin Wang Cc: Nico Pache Cc: Ryan Roberts Cc: Dev Jain Cc: Barry Song Cc: Lance Yang Cc: Usama Arif Cc: Matthew Brost Cc: Joshua Hahn Cc: Rakie Kim Cc: Byungchul Park Cc: Gregory Price Cc: Ying Huang Cc: Alistair Popple 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 | 3 +-- include/linux/mm.h | 3 +-- include/linux/page-flags.h | 21 ++++++++++++++++++--- include/trace/events/pagemap.h | 4 +--- mm/huge_memory.c | 4 +--- mm/migrate.c | 3 +-- 6 files changed, 23 insertions(+), 15 deletions(-) diff --git a/fs/proc/page.c b/fs/proc/page.c index abfa6f7d890cc..aab0e20b8f9fa 100644 --- a/fs/proc/page.c +++ b/fs/proc/page.c @@ -234,8 +234,7 @@ u64 stable_page_flags(const struct page *page) u |= kpf_copy_bit(k, KPF_OWNER_2, PG_owner_2); /* preserve the original KPF_PRIVATE semantics by excluding non pagecache folios */ if (folio->mapping && !folio_test_anon(folio) && - (folio_get_private(folio) && !folio_test_swapcache(folio) && - !folio_test_hugetlb(folio))) + folio_test_fs_private(folio)) u |= BIT_ULL(KPF_PRIVATE); u |= kpf_copy_bit(k, KPF_PRIVATE_2, PG_private_2); u |= kpf_copy_bit(k, KPF_OWNER_PRIVATE, PG_owner_priv_1); diff --git a/include/linux/mm.h b/include/linux/mm.h index ebc035ac26ccc..a93eaf7aae545 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -3004,8 +3004,7 @@ static inline int folio_expected_ref_count(const struct folio *folio) /* One reference per page from the pagecache. */ ref_count += !!folio->mapping << order; /* One reference from filesystem private data. */ - ref_count += !!folio->private && !folio_test_hugetlb(folio) && - !folio_test_swapcache(folio); + ref_count += folio_test_fs_private(folio); } /* One reference per page table mapping. */ diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h index 8efc61f967302..0e3628ea080c4 100644 --- a/include/linux/page-flags.h +++ b/include/linux/page-flags.h @@ -1210,6 +1210,23 @@ static __always_inline void __ClearPageAnonExclusive(struct page *page) (0xffUL /* order */ | 1UL << PG_has_hwpoisoned | \ 1UL << PG_large_rmappable | 1UL << PG_partially_mapped) +/** + * folio_test_fs_private - check if the folio has filesystem private data + * @folio: The folio to check. + * + * Use this in code that may encounter swapcache or hugetlb folios but only + * wants to detect filesystem private data. 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. + * + * Return: true if folio->private is set and the folio is neither swapcache + * nor hugetlb. + */ +static inline bool folio_test_fs_private(const struct folio *folio) +{ + return folio_test_private(folio) && !folio_test_swapcache(folio) && + !folio_test_hugetlb(folio); +} /** * folio_has_private - Determine if folio has private stuff * @folio: The folio to be checked @@ -1219,9 +1236,7 @@ static __always_inline void __ClearPageAnonExclusive(struct page *page) */ static inline int folio_has_private(const struct folio *folio) { - return (!!folio->private && !folio_test_swapcache(folio) && - !folio_test_hugetlb(folio)) || - folio_test_private_2(folio); + return folio_test_fs_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 fb9abec40ec79..5425ef7bbae6e 100644 --- a/include/trace/events/pagemap.h +++ b/include/trace/events/pagemap.h @@ -22,9 +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) && \ - !folio_test_swapcache(folio) && \ - !folio_test_hugetlb(folio) ? PAGEMAP_BUFFERS : 0) \ + (folio_test_fs_private(folio) ? PAGEMAP_BUFFERS : 0) \ ) TRACE_EVENT(mm_lru_insertion, diff --git a/mm/huge_memory.c b/mm/huge_memory.c index d21a9b8f40d15..7f8e99cdeacb8 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -4799,9 +4799,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) && - !folio_test_swapcache(folio) && - !folio_test_hugetlb(folio)) && + if (!folio_test_fs_private(folio) && folio_expected_ref_count(folio) != folio_ref_count(folio)) goto next; diff --git a/mm/migrate.c b/mm/migrate.c index ad5daef8721cf..014fcb745d210 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -1330,8 +1330,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) && !folio_test_swapcache(src) && - !folio_test_hugetlb(src)) { + if (folio_test_fs_private(src)) { try_to_free_buffers(src); goto out; } -- 2.53.0 They are no-ops now. Remove them. Assisted-by: Claude:claude-opus-4-8 Assisted-by: Codex:gpt-5 Signed-off-by: Zi Yan To: Trond Myklebust To: Anna Schumaker To: "Matthew Wilcox (Oracle)" To: Jan Kara To: Andrew Morton To: David Hildenbrand Cc: Zi Yan Cc: Matthew Brost Cc: Joshua Hahn Cc: Rakie Kim Cc: Byungchul Park Cc: Gregory Price Cc: Ying Huang Cc: Alistair Popple Cc: linux-nfs@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: linux-fsdevel@vger.kernel.org Cc: linux-mm@kvack.org --- fs/nfs/write.c | 2 -- include/linux/pagemap.h | 4 +--- mm/migrate.c | 1 - 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/fs/nfs/write.c b/fs/nfs/write.c index d2b03ceaeb4f1..d7e50ecb4edc3 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -717,7 +717,6 @@ static void nfs_inode_add_request(struct nfs_page *req) nfs_lock_request(req); spin_lock(&mapping->i_private_lock); set_bit(PG_MAPPED, &req->wb_flags); - folio_set_private(folio); folio->private = req; spin_unlock(&mapping->i_private_lock); atomic_long_inc(&nfsi->nrequests); @@ -744,7 +743,6 @@ static void nfs_inode_remove_request(struct nfs_page *req) spin_lock(&mapping->i_private_lock); if (likely(folio)) { folio->private = NULL; - folio_clear_private(folio); clear_bit(PG_MAPPED, &req->wb_head->wb_flags); } spin_unlock(&mapping->i_private_lock); diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h index 90904a4d173b7..5ca5aa365f319 100644 --- a/include/linux/pagemap.h +++ b/include/linux/pagemap.h @@ -594,7 +594,6 @@ static inline void folio_attach_private(struct folio *folio, void *data) { folio_get(folio); folio->private = data; - folio_set_private(folio); } /** @@ -629,9 +628,8 @@ static inline void *folio_detach_private(struct folio *folio) { void *data = folio_get_private(folio); - if (!folio_test_private(folio)) + if (!data) return NULL; - folio_clear_private(folio); folio->private = NULL; folio_put(folio); diff --git a/mm/migrate.c b/mm/migrate.c index 014fcb745d210..1d84766f12a18 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -838,7 +838,6 @@ void folio_migrate_flags(struct folio *newfolio, struct folio *folio) */ if (folio_test_swapcache(folio)) folio_clear_swapcache(folio); - folio_clear_private(folio); /* page->private contains hugetlb specific flags */ if (!folio_test_hugetlb(folio)) -- 2.53.0 PG_private is going to be removed and its check is replaced by checking page->private != NULL. Replace page_buffers() with page_private() and delete page_buffers(), since only two users left and both can be converted to use page_private(). Assisted-by: Claude:claude-opus-4-8 Assisted-by: Codex:gpt-5 Signed-off-by: Zi Yan To: Song Liu To: Yu Kuai To: Ilya Dryomov To: Alex Markuze To: Viacheslav Dubeyko Cc: Li Nan Cc: Xiao Ni Cc: linux-raid@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: ceph-devel@vger.kernel.org --- drivers/md/md-bitmap.c | 6 +++--- fs/ceph/addr.c | 4 +--- include/linux/buffer_head.h | 6 ------ 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c index 0f02e2956398d..affd4807013e1 100644 --- a/drivers/md/md-bitmap.c +++ b/drivers/md/md-bitmap.c @@ -516,7 +516,7 @@ static void end_bitmap_write(struct bio *bio) static void write_file_page(struct bitmap *bitmap, struct page *page, int wait) { - struct buffer_head *bh = page_buffers(page); + struct buffer_head *bh = (struct buffer_head *)page_private(page); while (bh && bh->b_blocknr) { atomic_inc(&bitmap->pending_writes); @@ -535,10 +535,10 @@ static void free_buffers(struct page *page) { struct buffer_head *bh; - if (!PagePrivate(page)) + if (!page_private(page)) return; - bh = page_buffers(page); + bh = (struct buffer_head *)page_private(page); while (bh) { struct buffer_head *next = bh->b_this_page; free_buffer_head(bh); diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index ecf33b66610c8..92074db8732ac 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -70,9 +70,7 @@ static int ceph_netfs_check_write_begin(struct file *file, loff_t pos, unsigned static inline struct ceph_snap_context *page_snap_context(struct page *page) { - if (PagePrivate(page)) - return (void *)page->private; - return NULL; + return (void *)page->private; } /* diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h index 8b23bc9a244cb..5cf0b8c058ce0 100644 --- a/include/linux/buffer_head.h +++ b/include/linux/buffer_head.h @@ -175,12 +175,6 @@ static inline unsigned long bh_offset(const struct buffer_head *bh) return (unsigned long)(bh)->b_data & (page_size(bh->b_page) - 1); } -/* If we *know* page->private refers to buffer_heads */ -#define page_buffers(page) \ - ({ \ - BUG_ON(!PagePrivate(page)); \ - ((struct buffer_head *)page_private(page)); \ - }) #define folio_buffers(folio) folio_get_private(folio) void buffer_check_dirty_writeback(struct folio *folio, -- 2.53.0 PG_private is going to be deleted. Adjust related comments to refer to page/folio->private instead. Assisted-by: Claude:claude-opus-4-8 Assisted-by: Codex:gpt-5 Signed-off-by: Zi Yan To: Ilya Dryomov To: Alex Markuze To: Viacheslav Dubeyko To: Trond Myklebust To: Anna Schumaker To: Richard Weinberger To: Andrew Morton To: David Hildenbrand Cc: Zhihao Cheng Cc: Lorenzo Stoakes Cc: "Liam R. Howlett" Cc: Vlastimil Babka Cc: Mike Rapoport Cc: Suren Baghdasaryan Cc: Michal Hocko Cc: ceph-devel@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: linux-nfs@vger.kernel.org Cc: linux-mtd@lists.infradead.org Cc: linux-mm@kvack.org --- fs/ceph/addr.c | 4 ++-- fs/nfs/file.c | 4 ++-- fs/ubifs/file.c | 6 +++--- include/linux/mm.h | 6 +++--- include/linux/mm_types.h | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index 92074db8732ac..a4a463a9cef0a 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -122,8 +122,8 @@ static bool ceph_dirty_folio(struct address_space *mapping, struct folio *folio) spin_unlock(&ci->i_ceph_lock); /* - * Reference snap context in folio->private. Also set - * PagePrivate so that we get invalidate_folio callback. + * Reference snap context in folio->private. folio_attach_private() + * triggers invalidate_folio callback. */ VM_WARN_ON_FOLIO(folio->private, folio); folio_attach_private(folio, snapc); diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 851d93a099889..fa3389d766d52 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -485,7 +485,7 @@ static int nfs_write_end(const struct kiocb *iocb, * Partially or wholly invalidate a page * - Release the private state associated with a page if undergoing complete * page invalidation - * - Called if either PG_private or PG_fscache is set on the page + * - Called if either folio->private or PG_fscache is set on the page * - Caller holds page lock */ static void nfs_invalidate_folio(struct folio *folio, size_t offset, @@ -556,7 +556,7 @@ static void nfs_check_dirty_writeback(struct folio *folio, * Attempt to clear the private state associated with a page when an error * occurs that requires the cached contents of an inode to be written back or * destroyed - * - Called if either PG_private or fscache is set on the page + * - Called if either page->private or fscache is set on the page * - Caller holds page lock * - Return 0 if successful, -error otherwise */ diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c index e73c28b12f97f..61d6a56b8c8a4 100644 --- a/fs/ubifs/file.c +++ b/fs/ubifs/file.c @@ -12,14 +12,14 @@ * This file implements VFS file and inode operations for regular files, device * nodes and symlinks as well as address space operations. * - * UBIFS uses 2 page flags: @PG_private and @PG_checked. @PG_private is set if + * UBIFS uses folio->private and page flag @PG_checked. folio->private is set if * the page is dirty and is used for optimization purposes - dirty pages are * not budgeted so the flag shows that 'ubifs_write_end()' should not release * the budget for this page. The @PG_checked flag is set if full budgeting is * required for the page e.g., when it corresponds to a file hole or it is * beyond the file size. The budgeting is done in 'ubifs_write_begin()', because * it is OK to fail in this function, and the budget is released in - * 'ubifs_write_end()'. So the @PG_private and @PG_checked flags carry + * 'ubifs_write_end()'. So the folio->private and @PG_checked flags carry * information about how the page was budgeted, to make it possible to release * the budget properly. * @@ -1509,7 +1509,7 @@ static vm_fault_t ubifs_vm_page_mkwrite(struct vm_fault *vmf) * * At the moment we do not know whether the folio is dirty or not, so we * assume that it is not and budget for a new folio. We could look at - * the @PG_private flag and figure this out, but we may race with write + * folio->private and figure this out, but we may race with write * back and the folio state may change by the time we lock it, so this * would need additional care. We do not bother with this at the * moment, although it might be good idea to do. Instead, we allocate diff --git a/include/linux/mm.h b/include/linux/mm.h index a93eaf7aae545..fc33cc1914273 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -2073,8 +2073,8 @@ vm_fault_t finish_fault(struct vm_fault *vmf); * * A pagecache page contains an opaque `private' member, which belongs to the * page's address_space. Usually, this is the address of a circular list of - * the page's disk buffers. PG_private must be set to tell the VM to call - * into the filesystem to release these pages. + * the page's disk buffers. It tells the VM to call into the filesystem to + * release these pages. * * A folio may belong to an inode's memory mapping. In this case, * folio->mapping points to the inode, and folio->index is the file @@ -2085,7 +2085,7 @@ vm_fault_t finish_fault(struct vm_fault *vmf); * case PG_swapcache is set, and page->private is an offset into the swapcache. * * In either case (swapcache or inode backed), the pagecache itself holds one - * reference to the page. Setting PG_private should also increment the + * reference to the page. Setting page->private should also increment the * refcount. The each user mapping also has a reference to the page. * * The pagecache pages are stored in a per-mapping radix tree, which is diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index b5d4cd3b067bf..f15290dde16d3 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -108,7 +108,7 @@ struct page { }; /** * @private: Mapping-private opaque data. - * Usually used for buffer_heads if PagePrivate. + * Usually used for buffer_heads. * Used for swp_entry_t if swapcache flag set. * Indicates order in the buddy system if PageBuddy * or on pcp_llist. @@ -675,7 +675,7 @@ static inline void ptdesc_pmd_pts_init(struct ptdesc *ptdesc) #define STRUCT_PAGE_MAX_SHIFT (order_base_2(sizeof(struct page))) /* - * page_private can be used on tail pages. However, PagePrivate is only + * page_private can be used on tail pages. However, it is only * checked by the VM on the head page. So page_private on the tail pages * should be used for data that's ancillary to the head page (eg attaching * buffer heads to tail pages after attaching buffer heads to the head page) -- 2.53.0 folio->private != NULL indicates a folio carries private data, replacing PG_private. All PG_private users are converted. Remove PG_private and reserve the space as __PG_folio for future use. Also update files in Documentation. hugetlbfs_reserv.rst is outdated and left unchanged. It should be rewritten. Assisted-by: Claude:claude-opus-4-8 Assisted-by: Codex:gpt-5 Signed-off-by: Zi Yan To: Andrew Morton To: Baoquan He To: Mike Rapoport To: Pasha Tatashin To: Pratyush Yadav To: Jonathan Corbet To: "Matthew Wilcox (Oracle)" To: Jan Kara To: David Hildenbrand To: Steven Rostedt To: Masami Hiramatsu Cc: Dave Young Cc: Shuah Khan Cc: Lorenzo Stoakes Cc: "Liam R. Howlett" Cc: Vlastimil Babka Cc: Suren Baghdasaryan Cc: Michal Hocko Cc: Mathieu Desnoyers Cc: kexec@lists.infradead.org Cc: linux-doc@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: linux-fsdevel@vger.kernel.org Cc: linux-mm@kvack.org Cc: linux-trace-kernel@vger.kernel.org --- Documentation/admin-guide/kdump/vmcoreinfo.rst | 2 +- Documentation/filesystems/vfs.rst | 6 +++--- include/linux/page-flags.h | 19 ++----------------- include/trace/events/mmflags.h | 2 +- kernel/vmcore_info.c | 1 - 5 files changed, 7 insertions(+), 23 deletions(-) diff --git a/Documentation/admin-guide/kdump/vmcoreinfo.rst b/Documentation/admin-guide/kdump/vmcoreinfo.rst index 7663c610fe901..5f1df6d080508 100644 --- a/Documentation/admin-guide/kdump/vmcoreinfo.rst +++ b/Documentation/admin-guide/kdump/vmcoreinfo.rst @@ -325,7 +325,7 @@ NR_FREE_PAGES On linux-2.6.21 or later, the number of free pages is in vm_stat[NR_FREE_PAGES]. Used to get the number of free pages. -PG_lru|PG_private|PG_swapcache|PG_swapbacked|PG_hwpoison|PG_head_mask +PG_lru|PG_swapcache|PG_swapbacked|PG_hwpoison|PG_head_mask -------------------------------------------------------------------------- Page attributes. These flags are used to filter various unnecessary for diff --git a/Documentation/filesystems/vfs.rst b/Documentation/filesystems/vfs.rst index e7677423a20f7..5cc07f82fe371 100644 --- a/Documentation/filesystems/vfs.rst +++ b/Documentation/filesystems/vfs.rst @@ -649,8 +649,8 @@ Writeback. The first can be used independently to the others. The VM can try to release clean pages in order to reuse them. To do this it can call -->release_folio on clean folios with the private -flag set. Clean pages without PagePrivate and with no external references +->release_folio on clean folios with folio->private set. Clean pages +without folio->private set and with no external references will be released without notice being given to the address_space. To achieve this functionality, pages need to be placed on an LRU with @@ -674,7 +674,7 @@ filemap_fdatawait_range, to wait for all writeback to complete. An address_space handler may attach extra information to a page, typically using the 'private' field in the 'struct page'. If such -information is attached, the PG_Private flag should be set. This will +information is attached, non-NULL 'private' field will cause various VM routines to make extra calls into the address_space handler to deal with that data. diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h index 0e3628ea080c4..eb2961ed61018 100644 --- a/include/linux/page-flags.h +++ b/include/linux/page-flags.h @@ -44,10 +44,6 @@ * Consequently, PG_reserved for a page mapped into user space can indicate * the zero page, the vDSO, MMIO pages or device memory. * - * The PG_private bitflag is set on pagecache pages if they contain filesystem - * specific data (which is normally at page->private). It can be used by - * private allocations for its own usage. - * * During initiation of disk I/O, PG_locked is set. This bit is set before I/O * and cleared when writeback _starts_ or when read _completes_. PG_writeback * is set before writeback starts and cleared when it finishes. @@ -105,7 +101,7 @@ enum pageflags { PG_owner_2, /* Owner use. If pagecache, fs may use */ PG_arch_1, PG_reserved, - PG_private, /* If pagecache, has fs-private data */ + __PG_folio, /* Do not use: reserved for folio identification */ PG_private_2, /* If pagecache, has fs aux data */ PG_reclaim, /* To be reclaimed asap */ PG_swapbacked, /* Page is backed by RAM/swap */ @@ -576,7 +572,7 @@ 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 */ static __always_inline bool folio_test_private(const struct folio *folio) @@ -584,17 +580,6 @@ static __always_inline bool folio_test_private(const struct folio *folio) return folio->private; } -static __always_inline int PagePrivate(const struct page *page) -{ - return !!page_private(page); -} - -/* 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 */ diff --git a/include/trace/events/mmflags.h b/include/trace/events/mmflags.h index 935893e5ea53b..caf090cd6f85e 100644 --- a/include/trace/events/mmflags.h +++ b/include/trace/events/mmflags.h @@ -144,7 +144,7 @@ TRACE_DEFINE_ENUM(___GFP_LAST_BIT); DEF_PAGEFLAG_NAME(owner_2), \ DEF_PAGEFLAG_NAME(arch_1), \ DEF_PAGEFLAG_NAME(reserved), \ - DEF_PAGEFLAG_NAME(private), \ + { 1UL << __PG_folio, "folio" }, \ DEF_PAGEFLAG_NAME(private_2), \ DEF_PAGEFLAG_NAME(writeback), \ DEF_PAGEFLAG_NAME(head), \ diff --git a/kernel/vmcore_info.c b/kernel/vmcore_info.c index 8614430ca212a..5a417f8a922ab 100644 --- a/kernel/vmcore_info.c +++ b/kernel/vmcore_info.c @@ -216,7 +216,6 @@ static int __init crash_save_vmcoreinfo_init(void) VMCOREINFO_LENGTH(free_area.free_list, MIGRATE_TYPES); VMCOREINFO_NUMBER(NR_FREE_PAGES); VMCOREINFO_NUMBER(PG_lru); - VMCOREINFO_NUMBER(PG_private); VMCOREINFO_NUMBER(PG_swapcache); VMCOREINFO_NUMBER(PG_swapbacked); #define PAGE_SLAB_MAPCOUNT_VALUE (PGTY_slab << 24) -- 2.53.0