mirror of
https://github.com/torvalds/linux.git
synced 2026-11-06 21:58:01 +01:00
mm/page-flags: check page/folio->private instead of PG_private
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. Link: https://lore.kernel.org/20260920-remove-pg_private-v5-10-bb68b6a21869@nvidia.com Signed-off-by: Zi Yan <ziy@nvidia.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Acked-by: David Hildenbrand (Arm) <david@kernel.org> Assisted-by: LLM Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Masami Hiramatsu <mhiramat@kernel.org> Cc: Lorenzo Stoakes <ljs@kernel.org> Cc: "Matthew Wilcox (Oracle)" <willy@infradead.org> Cc: Jan Kara <jack@suse.cz> Cc: 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: 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>
This commit is contained in:
parent
96fd9017e3
commit
e01f7ddcb1
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -3005,9 +3005,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),
|
||||
|
|
@ -3045,10 +3045,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. */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -4845,7 +4845,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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user