[PATCH RFC 00/14] Remove PG_private by using page/folio->private checks instead
Zi Yan
ziy at nvidia.com
Fri Jul 31 19:13:23 PDT 2026
Hi all,
This patchset removes PG_private to make space for upcoming PG_folio
(reserved as __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.
Overview
===
Most code uses folio_attach/detach/change_private() functions, so folio
refcount is increased and decreased when folio->private is set and reset,
respectively. There is no need to change them.
Changes are needed for exceptional users:
1. zsmalloc uses PG_private to indicate first component zpdesc page and
page->private is used to store zspage in zpdesc. To remove PG_private,
is_first_zpdesc() is changed to zpdesc->zspage->first_zpdesc == zpdesc
instead of checking PG_private.
2. kernel/events/ring_buffer.c stores page order in page->private.
Replacing PG_private with page->private != NULL works.
3. drivers/xen/grant-table.c stores xen_page_foreign in page->private,
where on 32-bit, a pointer to xen_page_foreign is stored; on 64-bit,
page->private is used as xen_page_foreign. PG_private check is replaced
by page->private != NULL on 32-bit for xen_page_foreign deallocation.
On 64-bit, page->private is cleared unconditionally since {domid=0,
gref=0} (xen_page_foreign can be 0) is valid.
4. fs/crypto/crypto.c stores a folio pointer in page->private, PG_private
checks are replaced by page->private != NULL.
5. fs/erofs has two different uses:
5a. folio->private is used to form a reversed list of
the outputs of readahead_folio(). readahead_folio_reverse() is added to
output folios in reversed order, so that ->private is no longer needed.
5b. folio->private is used as an in-flight I/O counter. Convert the
code to use folio_attach/detach/get_private().
6. fs/nfs/write.c: folio refcount maintenance is in a bigger scope than
folio->private. So folio_attach/detach/get_private() is not used.
Nothing to change.
7. fs/f2fs uses attach_page_private() to first reset folio->private then
immediately sets PAGE_PRIVATE_NOT_POINTER bit on it. Change it to use
attach_page_private() to set PAGE_PRIVATE_NOT_POINTER bit directly to
avoid folio->private == NULL gap inside set_page_private_##name().
8. hugetlb uses folio_change_private(folio, NULL) without folio refcount
maintenance. Change it to folio->private = NULL.
After the above changes, PG_private ops are converted to
page/folio->private ops.
folio_test_fs_private() is added to check filesystem-only private data by
excluding swapcache and hugetlb folios, because swapcache folios overlap
swp_entry_t swap with ->private and hugetlb sets its own flags in
->private.
Note
===
1. KPF_PRIVATE has a minor semantic change. Since PG_private will be
removed, KPF_PRIVATE represents pagecache folios whose ->mapping is not
NULL and with ->private set. Currently KPF_PRIVATE can be set for
orphaned pagecache folios with ->mapping == NULL.
2. Documentation/mm/hugetlbfs_reserv.rst is outdated, so I did not remove
PG_private related text. It should be rewritten.
3. PG_folio is planned to be set on every page from a folio in
page_rmappable_folio(), so folios with any order (currently
PG_large_rmappable is used to identify >0 order folios) can be
identified, vm_insert_*() can correctly reject all folios, and rmap code
can accept only folios. Eventually, page_folio() will return NULL for
non-folio pages.
Tests
===
1. allmodconfig build passed.
2. zsmalloc is tested using ext4 on a 1GB lz4 zram:
2a. zram load + zsmalloc compaction;
2b. concurrent zspage migration via memory compaction;
2c. confirmed that multi-page zspages actually formed.
Details: https://github.com/x-y-z/linux-dev/blob/b4/remove-pg_private/test_zsmalloc.md
3. erofs is tested on images created with -C4096 and lz4hc, lzma,
deflate, and zstd algorithms:
3a. cold read of all files, verify checksums match source;
3b. readahead + reclaim/migration race.
Details: https://github.com/x-y-z/linux-dev/blob/b4/remove-pg_private/test_erofs.md
4. fscrypt is tested on software-encrypted ext4 with writes to exercise
bounce pages.
Details: https://github.com/x-y-z/linux-dev/blob/b4/remove-pg_private/test_fscrypt.md
5. f2fs is tested on an image with inline_data,compress_algorithm=lz4:
5a. INLINE_INODE — lots of tiny files;
5b. REF_RESOURCE + general writeback — buffered write churn with fsync;
5c. ONGOING_MIGRATION — force GC / page migration;
5d. ATOMIC_WRITE — atomic-write ioctl path.
Details: https://github.com/x-y-z/linux-dev/blob/b4/remove-pg_private/test_f2fs.md
(I did not run xfstests)
6. MM selftests passed.
LLM use
===
Claude was used to form a concrete plan on what code needs to be changed
and how to change them. The plan was reviewed by Codex until no issue was
spotted.
Plan is at: https://github.com/x-y-z/linux-dev/blob/b4/remove-pg_private/plan.md
I then followed the plan to make code changes. I did bounce ideas with
Claude how to change fs/erofs, since I did not like the original idea.
After each change, I asked Claude to review my code and git commit message.
I also asked Claude to give me test plans (see above).
At last, Codex was used to review all patches.
Comments and suggestions are welcome. Thanks.
Assisted-by: Claude:claude-opus-4-8
Assisted-by: Codex:gpt-5
Signed-off-by: Zi Yan <ziy at nvidia.com>
---
Zi Yan (14):
mm/zsmalloc: replace PG_private with pointer comparison
perf/ring_buffer: stop using PG_private as AUX page high-order marker
xen/grant-table: stop setting PG_private on pages for grant mapping
fs/crypto: stop setting PG_private on bounce page
mm/hugetlb: use direct assignment instead of folio_change_private()
fs/f2fs: stop using PG_private
fs/erofs: mm/pagemap: add readahead_folio_reverse() to avoid folio->private
fs/erofs: use folio_attach/detach_private() instead of direct assignment
mm/page-flags: check page/folio->private instead of PG_private
mm/page-flags: introduce folio_test_fs_private()
treewide: remove folio_set/clear_private()
treewide: replace PagePrivate() with page_private()
treewide: adjust comments on PagePrivate and PG_private
mm/page-flags: remove PG_private
Documentation/admin-guide/kdump/vmcoreinfo.rst | 2 +-
Documentation/filesystems/vfs.rst | 6 ++--
arch/x86/events/intel/bts.c | 3 --
arch/x86/events/intel/pt.c | 6 ++--
drivers/md/md-bitmap.c | 6 ++--
drivers/xen/balloon.c | 5 ++++
drivers/xen/grant-table.c | 7 ++---
fs/ceph/addr.c | 8 ++----
fs/crypto/crypto.c | 2 --
fs/erofs/data.c | 5 ++--
fs/erofs/zdata.c | 11 ++------
fs/f2fs/f2fs.h | 8 +++---
fs/nfs/file.c | 4 +--
fs/nfs/write.c | 2 --
fs/proc/page.c | 5 +++-
fs/ubifs/file.c | 6 ++--
include/linux/buffer_head.h | 6 ----
include/linux/mm.h | 16 +++++------
include/linux/mm_types.h | 4 +--
include/linux/page-flags.h | 38 ++++++++++++++++++--------
include/linux/pagemap.h | 35 ++++++++++++++++++++++--
include/trace/events/mmflags.h | 2 +-
include/trace/events/pagemap.h | 2 +-
kernel/events/ring_buffer.c | 7 ++---
kernel/vmcore_info.c | 1 -
mm/huge_memory.c | 2 +-
mm/hugetlb.c | 6 ++--
mm/migrate.c | 3 +-
mm/page-writeback.c | 5 +++-
mm/vmscan.c | 3 +-
mm/zpdesc.h | 2 +-
mm/zsmalloc.c | 15 ++--------
32 files changed, 127 insertions(+), 106 deletions(-)
---
base-commit: bcd5eb68a6a189497eb26c1b9f622538aa48895d
change-id: 20260728-remove-pg_private-cfe926c7f83c
Best regards,
--
Yan, Zi
More information about the linux-mtd
mailing list