| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/09/01 03:41 | flow | patch-triage |
2mArgs:null Results: {
"EnableConfigs": [
"EROFS_FS",
"EROFS_FS_ZIP",
"FS_ENCRYPTION",
"HUGETLBFS",
"TRANSPARENT_HUGEPAGE",
"ZSMALLOC"
],
"FocusSymbols": [
"erofs_onlinefolio_init",
"erofs_onlinefolio_end",
"fscrypt_encrypt_pagecache_blocks",
"fscrypt_free_bounce_page",
"add_hugetlb_folio",
"folio_migrate_flags",
"stable_page_flags"
],
"KMSANReasoning": "The patch eliminates the PG_private page flag in favor of directly using folio-\u003eprivate (and folio_test_fs_private()), adjusting the mm subsystem, filesystems (Ceph, EROFS, F2FS, NFS, UBIFS), drivers, and tracing infrastructure accordingly.\n\nThese changes refactor internal kernel page/folio metadata management and page cache readahead iteration. They do not introduce or modify any user-space copy paths (no risk of uninitialized struct/padding info-leaks), do not introduce uninitialized stack or heap allocations, and do not introduce conditional branching on uninitialized data. Any potential regressions (such as refcount imbalances, page cache state inconsistencies, or NULL pointer dereferences) are covered by KASAN, LOCKDEP, and internal MM assertions. Therefore, a dedicated KMSAN fuzzing session is not warranted.",
"NeedsKMSAN": false,
"Reasoning": "The patch removes the PG_private page flag across the kernel in favor of direct folio-\u003eprivate and page_private checks, implements a reverse readahead iterator (readahead_folio_last) for pagemaps, updates online folio handling in EROFS, updates ciphertext bounce page handling in fscrypt, and adjusts HugeTLB/migration/zsmalloc metadata tracking. These are reachable, functional changes in core memory management and filesystems that should be fuzzed.",
"WorthFuzzing": true
} |
| 1/1 | 2026/09/01 03:41 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit 421bcb73cd4f011e8a27d95d741dbb1eb94e34c6\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Tue Sep 1 03:41:49 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/Documentation/admin-guide/kdump/vmcoreinfo.rst b/Documentation/admin-guide/kdump/vmcoreinfo.rst\nindex 7663c610fe901..5f1df6d080508 100644\n--- a/Documentation/admin-guide/kdump/vmcoreinfo.rst\n+++ b/Documentation/admin-guide/kdump/vmcoreinfo.rst\n@@ -325,7 +325,7 @@ NR_FREE_PAGES\n On linux-2.6.21 or later, the number of free pages is in\n vm_stat[NR_FREE_PAGES]. Used to get the number of free pages.\n \n-PG_lru|PG_private|PG_swapcache|PG_swapbacked|PG_hwpoison|PG_head_mask\n+PG_lru|PG_swapcache|PG_swapbacked|PG_hwpoison|PG_head_mask\n --------------------------------------------------------------------------\n \n Page attributes. These flags are used to filter various unnecessary for\ndiff --git a/Documentation/filesystems/vfs.rst b/Documentation/filesystems/vfs.rst\nindex d3a93eec3945f..dec7816303c6a 100644\n--- a/Documentation/filesystems/vfs.rst\n+++ b/Documentation/filesystems/vfs.rst\n@@ -649,8 +649,8 @@ Writeback.\n \n The first can be used independently to the others. The VM can try to\n release clean pages in order to reuse them. To do this it can call\n--\u003erelease_folio on clean folios with the private\n-flag set. Clean pages without PagePrivate and with no external references\n+-\u003erelease_folio on clean folios with folio-\u003eprivate set. Clean pages\n+without folio-\u003eprivate set and with no external references\n will be released without notice being given to the address_space.\n \n To achieve this functionality, pages need to be placed on an LRU with\n@@ -674,7 +674,7 @@ filemap_fdatawait_range, to wait for all writeback to complete.\n \n An address_space handler may attach extra information to a page,\n typically using the 'private' field in the 'struct page'. If such\n-information is attached, the PG_Private flag should be set. This will\n+information is attached, non-NULL 'private' field will\n cause various VM routines to make extra calls into the address_space\n handler to deal with that data.\n \ndiff --git a/arch/x86/events/intel/bts.c b/arch/x86/events/intel/bts.c\nindex cbac54cb3a9ec..5849392cf26d5 100644\n--- a/arch/x86/events/intel/bts.c\n+++ b/arch/x86/events/intel/bts.c\n@@ -66,9 +66,6 @@ static struct pmu bts_pmu;\n \n static int buf_nr_pages(struct page *page)\n {\n-\tif (!PagePrivate(page))\n-\t\treturn 1;\n-\n \treturn 1 \u003c\u003c page_private(page);\n }\n \ndiff --git a/arch/x86/events/intel/pt.c b/arch/x86/events/intel/pt.c\nindex 5754cd4055628..49349afee6119 100644\n--- a/arch/x86/events/intel/pt.c\n+++ b/arch/x86/events/intel/pt.c\n@@ -781,8 +781,7 @@ static int topa_insert_pages(struct pt_buffer *buf, int cpu, gfp_t gfp)\n \tstruct page *p;\n \n \tp = virt_to_page(buf-\u003edata_pages[buf-\u003enr_pages]);\n-\tif (PagePrivate(p))\n-\t\torder = page_private(p);\n+\torder = page_private(p);\n \n \tif (topa_table_full(topa)) {\n \t\ttopa = topa_alloc(cpu, gfp);\n@@ -1296,8 +1295,7 @@ static int pt_buffer_try_single(struct pt_buffer *buf, int nr_pages)\n \tif (!intel_pt_validate_hw_cap(PT_CAP_single_range_output))\n \t\tgoto out;\n \n-\tif (PagePrivate(p))\n-\t\torder = page_private(p);\n+\torder = page_private(p);\n \n \tif (1 \u003c\u003c order != nr_pages)\n \t\tgoto out;\ndiff --git a/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c\nindex b8325cb09a371..0cf14bc1cff32 100644\n--- a/drivers/md/md-bitmap.c\n+++ b/drivers/md/md-bitmap.c\n@@ -516,7 +516,7 @@ static void end_bitmap_write(struct bio *bio)\n \n static void write_file_page(struct bitmap *bitmap, struct page *page, int wait)\n {\n-\tstruct buffer_head *bh = page_buffers(page);\n+\tstruct buffer_head *bh = (struct buffer_head *)page_private(page);\n \n \twhile (bh \u0026\u0026 bh-\u003eb_blocknr) {\n \t\tatomic_inc(\u0026bitmap-\u003epending_writes);\n@@ -535,10 +535,10 @@ static void free_buffers(struct page *page)\n {\n \tstruct buffer_head *bh;\n \n-\tif (!PagePrivate(page))\n+\tif (!page_private(page))\n \t\treturn;\n \n-\tbh = page_buffers(page);\n+\tbh = (struct buffer_head *)page_private(page);\n \twhile (bh) {\n \t\tstruct buffer_head *next = bh-\u003eb_this_page;\n \t\tfree_buffer_head(bh);\ndiff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c\nindex e7f74ea7cd5eb..fdb18348cfdfe 100644\n--- a/drivers/xen/balloon.c\n+++ b/drivers/xen/balloon.c\n@@ -182,6 +182,11 @@ static struct page *balloon_retrieve(bool require_lowmem)\n \n \t__ClearPageOffline(page);\n \tdec_node_page_state(page, NR_BALLOON_PAGES);\n+\t/*\n+\t * clear page-\u003eprivate before giving it out, since it might be used to\n+\t * store xen_page_foreign info.\n+\t */\n+\tset_page_private(page, 0);\n \n \treturn page;\n }\ndiff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c\nindex 69922be28b54c..993f89f048e21 100644\n--- a/drivers/xen/grant-table.c\n+++ b/drivers/xen/grant-table.c\n@@ -863,10 +863,10 @@ EXPORT_SYMBOL_GPL(gnttab_free_auto_xlat_frames);\n \n int gnttab_pages_set_private(int nr_pages, struct page **pages)\n {\n+#if BITS_PER_LONG \u003c 64\n \tint i;\n \n \tfor (i = 0; i \u003c nr_pages; i++) {\n-#if BITS_PER_LONG \u003c 64\n \t\tstruct xen_page_foreign *foreign;\n \n \t\tforeign = kzalloc_obj(*foreign);\n@@ -874,9 +874,9 @@ int gnttab_pages_set_private(int nr_pages, struct page **pages)\n \t\t\treturn -ENOMEM;\n \n \t\tset_page_private(pages[i], (unsigned long)foreign);\n-#endif\n-\t\tSetPagePrivate(pages[i]);\n \t}\n+#endif\n+\t/* Data is stored in page-\u003eprivate on 64-bit */\n \n \treturn 0;\n }\n@@ -1031,12 +1031,11 @@ void gnttab_pages_clear_private(int nr_pages, struct page **pages)\n \tint i;\n \n \tfor (i = 0; i \u003c nr_pages; i++) {\n-\t\tif (PagePrivate(pages[i])) {\n #if BITS_PER_LONG \u003c 64\n+\t\tif (page_private(pages[i]))\n \t\t\tkfree((void *)page_private(pages[i]));\n #endif\n-\t\t\tClearPagePrivate(pages[i]);\n-\t\t}\n+\t\tset_page_private(pages[i], 0);\n \t}\n }\n EXPORT_SYMBOL_GPL(gnttab_pages_clear_private);\ndiff --git a/fs/ceph/addr.c b/fs/ceph/addr.c\nindex 657c2cb0f8811..f9b2ec9550481 100644\n--- a/fs/ceph/addr.c\n+++ b/fs/ceph/addr.c\n@@ -70,9 +70,7 @@ static int ceph_netfs_check_write_begin(struct file *file, loff_t pos, unsigned\n \n static inline struct ceph_snap_context *page_snap_context(struct page *page)\n {\n-\tif (PagePrivate(page))\n-\t\treturn (void *)page-\u003eprivate;\n-\treturn NULL;\n+\treturn (void *)page-\u003eprivate;\n }\n \n /*\n@@ -124,8 +122,8 @@ static bool ceph_dirty_folio(struct address_space *mapping, struct folio *folio)\n \tspin_unlock(\u0026ci-\u003ei_ceph_lock);\n \n \t/*\n-\t * Reference snap context in folio-\u003eprivate. Also set\n-\t * PagePrivate so that we get invalidate_folio callback.\n+\t * Reference snap context in folio-\u003eprivate. Setting folio-\u003eprivate is\n+\t * what gets us the invalidate_folio callback.\n \t */\n \tVM_WARN_ON_FOLIO(folio-\u003eprivate, folio);\n \tfolio_attach_private(folio, snapc);\ndiff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c\nindex 5286a124b0d98..aced5c50a4601 100644\n--- a/fs/crypto/crypto.c\n+++ b/fs/crypto/crypto.c\n@@ -65,7 +65,6 @@ void fscrypt_free_bounce_page(struct page *bounce_page)\n \tif (!bounce_page)\n \t\treturn;\n \tset_page_private(bounce_page, (unsigned long)NULL);\n-\tClearPagePrivate(bounce_page);\n \tmempool_free(bounce_page, fscrypt_bounce_page_pool);\n }\n EXPORT_SYMBOL(fscrypt_free_bounce_page);\n@@ -210,7 +209,6 @@ struct page *fscrypt_encrypt_pagecache_blocks(struct folio *folio,\n \t\t\treturn ERR_PTR(err);\n \t\t}\n \t}\n-\tSetPagePrivate(ciphertext_page);\n \tset_page_private(ciphertext_page, (unsigned long)folio);\n \treturn ciphertext_page;\n }\ndiff --git a/fs/erofs/data.c b/fs/erofs/data.c\nindex 0885b1f2fc925..f71c7b51bb720 100644\n--- a/fs/erofs/data.c\n+++ b/fs/erofs/data.c\n@@ -239,19 +239,23 @@ int erofs_map_dev(struct super_block *sb, struct erofs_map_dev *map)\n /*\n * bit 30: I/O error occurred on this folio\n * bit 29: CPU has dirty data in D-cache (needs aliasing handling);\n- * bit 0 - 29: remaining parts to complete this folio\n+ * bit 0 - 28: remaining parts to complete this folio, biased by 1 so that\n+ *\t -\u003eprivate stays non-NULL while the folio is attached\n */\n #define EROFS_ONLINEFOLIO_EIO\t\t30\n #define EROFS_ONLINEFOLIO_DIRTY\t\t29\n+#define EROFS_ONLINEFOLIO_COUNT_MASK\t(BIT(EROFS_ONLINEFOLIO_DIRTY) - 1)\n+#define EROFS_ONLINEFOLIO_BIAS\t\t1\n \n void erofs_onlinefolio_init(struct folio *folio)\n {\n \tunion {\n \t\tatomic_t o;\n \t\tvoid *v;\n-\t} u = { .o = ATOMIC_INIT(1) };\n+\t} u = { .o = ATOMIC_INIT(1 + EROFS_ONLINEFOLIO_BIAS) };\n \n-\tfolio-\u003eprivate = u.v;\t/* valid only if file-backed folio is locked */\n+\t/* valid only if file-backed folio is locked */\n+\tfolio_attach_private(folio, u.v);\n }\n \n void erofs_onlinefolio_split(struct folio *folio)\n@@ -265,14 +269,14 @@ void erofs_onlinefolio_end(struct folio *folio, int err, bool dirty)\n \n \tdo {\n \t\torig = atomic_read((atomic_t *)\u0026folio-\u003eprivate);\n-\t\tDBG_BUGON(orig \u003c= 0);\n+\t\tDBG_BUGON((orig \u0026 EROFS_ONLINEFOLIO_COUNT_MASK) \u003c= EROFS_ONLINEFOLIO_BIAS);\n \t\tv = dirty \u003c\u003c EROFS_ONLINEFOLIO_DIRTY;\n \t\tv |= (orig - 1) | (!!err \u003c\u003c EROFS_ONLINEFOLIO_EIO);\n \t} while (atomic_cmpxchg((atomic_t *)\u0026folio-\u003eprivate, orig, v) != orig);\n \n-\tif (v \u0026 (BIT(EROFS_ONLINEFOLIO_DIRTY) - 1))\n+\tif ((v \u0026 EROFS_ONLINEFOLIO_COUNT_MASK) != EROFS_ONLINEFOLIO_BIAS)\n \t\treturn;\n-\tfolio-\u003eprivate = 0;\n+\tfolio_detach_private(folio);\n \tif (v \u0026 BIT(EROFS_ONLINEFOLIO_DIRTY))\n \t\tflush_dcache_folio(folio);\n \tfolio_end_read(folio, !(v \u0026 BIT(EROFS_ONLINEFOLIO_EIO)));\ndiff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c\nindex e1e25ca0d1904..78fd7d980e957 100644\n--- a/fs/erofs/zdata.c\n+++ b/fs/erofs/zdata.c\n@@ -1898,21 +1898,14 @@ static void z_erofs_readahead(struct readahead_control *rac)\n \tstruct inode *realinode = erofs_real_inode(sharedinode, \u0026need_iput);\n \tZ_EROFS_DEFINE_FRONTEND(f, realinode, sharedinode, readahead_pos(rac));\n \tunsigned int nrpages = readahead_count(rac);\n-\tstruct folio *head = NULL, *folio;\n+\tstruct folio *folio;\n \tint err;\n \n \ttrace_erofs_readahead(realinode, readahead_index(rac), nrpages, false);\n \tz_erofs_pcluster_readmore(\u0026f, rac, true);\n-\twhile ((folio = readahead_folio(rac))) {\n-\t\tfolio-\u003eprivate = head;\n-\t\thead = folio;\n-\t}\n-\n-\t/* traverse in reverse order for best metadata I/O performance */\n-\twhile (head) {\n-\t\tfolio = head;\n-\t\thead = folio_get_private(folio);\n \n+\t/* traverse from last to first for best metadata I/O performance */\n+\twhile ((folio = readahead_folio_last(rac))) {\n \t\terr = z_erofs_scan_folio(\u0026f, folio, true);\n \t\tif (err \u0026\u0026 err != -EINTR)\n \t\t\terofs_err(realinode-\u003ei_sb, \"readahead error at folio %lu @ nid %llu\",\ndiff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h\nindex 9940a6cecf1a2..2f7ab5888b078 100644\n--- a/fs/f2fs/f2fs.h\n+++ b/fs/f2fs/f2fs.h\n@@ -2691,7 +2691,7 @@ static inline bool folio_test_f2fs_##name(const struct folio *folio)\t\\\n }\t\t\t\t\t\t\t\t\t\\\n static inline bool page_private_##name(struct page *page) \\\n { \\\n-\treturn PagePrivate(page) \u0026\u0026 \\\n+\treturn page_private(page) \u0026\u0026 \\\n \t\ttest_bit(PAGE_PRIVATE_NOT_POINTER, \u0026page_private(page)) \u0026\u0026 \\\n \t\ttest_bit(PAGE_PRIVATE_##flagname, \u0026page_private(page)); \\\n }\n@@ -2710,9 +2710,9 @@ static inline void folio_set_f2fs_##name(struct folio *folio)\t\t\\\n }\t\t\t\t\t\t\t\t\t\\\n static inline void set_page_private_##name(struct page *page) \\\n { \\\n-\tif (!PagePrivate(page)) \\\n-\t\tattach_page_private(page, (void *)0); \\\n-\tset_bit(PAGE_PRIVATE_NOT_POINTER, \u0026page_private(page)); \\\n+\tif (!page_private(page)) \\\n+\t\tattach_page_private(page, \\\n+\t\t\t\t(void *)BIT(PAGE_PRIVATE_NOT_POINTER)); \\\n \tset_bit(PAGE_PRIVATE_##flagname, \u0026page_private(page)); \\\n }\n \ndiff --git a/fs/nfs/file.c b/fs/nfs/file.c\nindex e1bdd10b35f10..38f830a6467c9 100644\n--- a/fs/nfs/file.c\n+++ b/fs/nfs/file.c\n@@ -484,7 +484,7 @@ static int nfs_write_end(const struct kiocb *iocb,\n * Partially or wholly invalidate a page\n * - Release the private state associated with a page if undergoing complete\n * page invalidation\n- * - Called if either PG_private or PG_fscache is set on the page\n+ * - Called if either folio-\u003eprivate or PG_fscache is set on the page\n * - Caller holds page lock\n */\n static void nfs_invalidate_folio(struct folio *folio, size_t offset,\n@@ -555,7 +555,7 @@ static void nfs_check_dirty_writeback(struct folio *folio,\n * Attempt to clear the private state associated with a page when an error\n * occurs that requires the cached contents of an inode to be written back or\n * destroyed\n- * - Called if either PG_private or fscache is set on the page\n+ * - Called if either page-\u003eprivate or fscache is set on the page\n * - Caller holds page lock\n * - Return 0 if successful, -error otherwise\n */\ndiff --git a/fs/nfs/write.c b/fs/nfs/write.c\nindex 623e7ef1f73d5..b6967b5286691 100644\n--- a/fs/nfs/write.c\n+++ b/fs/nfs/write.c\n@@ -717,7 +717,6 @@ static void nfs_inode_add_request(struct nfs_page *req)\n \tnfs_lock_request(req);\n \tspin_lock(\u0026mapping-\u003ei_private_lock);\n \tset_bit(PG_MAPPED, \u0026req-\u003ewb_flags);\n-\tfolio_set_private(folio);\n \tfolio-\u003eprivate = req;\n \tspin_unlock(\u0026mapping-\u003ei_private_lock);\n \tatomic_long_inc(\u0026nfsi-\u003enrequests);\n@@ -745,7 +744,6 @@ static void nfs_inode_remove_request(struct nfs_page *req)\n \n \t\t\tspin_lock(\u0026mapping-\u003ei_private_lock);\n \t\t\tfolio-\u003eprivate = NULL;\n-\t\t\tfolio_clear_private(folio);\n \t\t\tclear_bit(PG_MAPPED, \u0026req-\u003ewb_head-\u003ewb_flags);\n \t\t\tspin_unlock(\u0026mapping-\u003ei_private_lock);\n \ndiff --git a/fs/proc/page.c b/fs/proc/page.c\nindex 260772b20bd99..f90e1030825e9 100644\n--- a/fs/proc/page.c\n+++ b/fs/proc/page.c\n@@ -232,7 +232,6 @@ u64 stable_page_flags(const struct page *page)\n \n \tu |= kpf_copy_bit(k, KPF_RESERVED,\tPG_reserved);\n \tu |= kpf_copy_bit(k, KPF_OWNER_2,\tPG_owner_2);\n-\tu |= kpf_copy_bit(k, KPF_PRIVATE,\tPG_private);\n \tu |= kpf_copy_bit(k, KPF_PRIVATE_2,\tPG_private_2);\n \tu |= kpf_copy_bit(k, KPF_OWNER_PRIVATE,\tPG_owner_priv_1);\n \tu |= kpf_copy_bit(k, KPF_ARCH,\t\tPG_arch_1);\ndiff --git a/fs/ubifs/file.c b/fs/ubifs/file.c\nindex e73c28b12f97f..aa0298ce451ef 100644\n--- a/fs/ubifs/file.c\n+++ b/fs/ubifs/file.c\n@@ -12,14 +12,14 @@\n * This file implements VFS file and inode operations for regular files, device\n * nodes and symlinks as well as address space operations.\n *\n- * UBIFS uses 2 page flags: @PG_private and @PG_checked. @PG_private is set if\n+ * UBIFS uses folio-\u003eprivate and page flag @PG_checked. folio-\u003eprivate is set if\n * the page is dirty and is used for optimization purposes - dirty pages are\n- * not budgeted so the flag shows that 'ubifs_write_end()' should not release\n+ * not budgeted so it shows that 'ubifs_write_end()' should not release\n * the budget for this page. The @PG_checked flag is set if full budgeting is\n * required for the page e.g., when it corresponds to a file hole or it is\n * beyond the file size. The budgeting is done in 'ubifs_write_begin()', because\n * it is OK to fail in this function, and the budget is released in\n- * 'ubifs_write_end()'. So the @PG_private and @PG_checked flags carry\n+ * 'ubifs_write_end()'. So the folio-\u003eprivate and the @PG_checked flag carry\n * information about how the page was budgeted, to make it possible to release\n * the budget properly.\n *\n@@ -1509,7 +1509,7 @@ static vm_fault_t ubifs_vm_page_mkwrite(struct vm_fault *vmf)\n \t *\n \t * At the moment we do not know whether the folio is dirty or not, so we\n \t * assume that it is not and budget for a new folio. We could look at\n-\t * the @PG_private flag and figure this out, but we may race with write\n+\t * folio-\u003eprivate and figure this out, but we may race with write\n \t * back and the folio state may change by the time we lock it, so this\n \t * would need additional care. We do not bother with this at the\n \t * moment, although it might be good idea to do. Instead, we allocate\ndiff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h\nindex fd2c7115c0542..e47fbd0387b69 100644\n--- a/include/linux/buffer_head.h\n+++ b/include/linux/buffer_head.h\n@@ -175,12 +175,6 @@ static inline unsigned long bh_offset(const struct buffer_head *bh)\n \treturn (unsigned long)(bh)-\u003eb_data \u0026 (page_size(bh-\u003eb_page) - 1);\n }\n \n-/* If we *know* page-\u003eprivate refers to buffer_heads */\n-#define page_buffers(page)\t\t\t\t\t\\\n-\t({\t\t\t\t\t\t\t\\\n-\t\tBUG_ON(!PagePrivate(page));\t\t\t\\\n-\t\t((struct buffer_head *)page_private(page));\t\\\n-\t})\n #define folio_buffers(folio)\t\tfolio_get_private(folio)\n \n void buffer_check_dirty_writeback(struct folio *folio,\ndiff --git a/include/linux/kernel-page-flags.h b/include/linux/kernel-page-flags.h\nindex 196778a087c4d..fe5ab6e50bd70 100644\n--- a/include/linux/kernel-page-flags.h\n+++ b/include/linux/kernel-page-flags.h\n@@ -11,7 +11,6 @@\n #define KPF_RESERVED\t\t32\n #define KPF_MLOCKED\t\t33\n #define KPF_OWNER_2\t\t34\n-#define KPF_PRIVATE\t\t35\n #define KPF_PRIVATE_2\t\t36\n #define KPF_OWNER_PRIVATE\t37\n #define KPF_ARCH\t\t38\ndiff --git a/include/linux/mm.h b/include/linux/mm.h\nindex dd09c438fa23e..2855739a0f379 100644\n--- a/include/linux/mm.h\n+++ b/include/linux/mm.h\n@@ -2075,20 +2075,21 @@ vm_fault_t finish_fault(struct vm_fault *vmf);\n *\n * A pagecache page contains an opaque `private' member, which belongs to the\n * page's address_space. Usually, this is the address of a circular list of\n- * the page's disk buffers. PG_private must be set to tell the VM to call\n- * into the filesystem to release these pages.\n+ * the page's disk buffers. It tells the VM to call into the filesystem to\n+ * release these pages.\n *\n * A folio may belong to an inode's memory mapping. In this case,\n * folio-\u003emapping points to the inode, and folio-\u003eindex is the file\n * offset of the folio, in units of PAGE_SIZE.\n *\n- * If pagecache pages are not associated with an inode, they are said to be\n- * anonymous pages. These may become associated with the swapcache, and in that\n- * case PG_swapcache is set, and page-\u003eprivate is an offset into the swapcache.\n+ * If pagecache folios are not associated with an inode, they are said to be\n+ * anonymous folios. These may become associated with the swapcache, and in that\n+ * case PG_swapcache is set, and folio-\u003eprivate is an offset into the swapcache.\n *\n * In either case (swapcache or inode backed), the pagecache itself holds one\n- * reference to the page. Setting PG_private should also increment the\n- * refcount. The each user mapping also has a reference to the page.\n+ * reference to the folio. Attaching filesystem private data via\n+ * folio_attach_private() also increments the refcount. Each user mapping also\n+ * has a reference to the folio.\n *\n * The pagecache pages are stored in a per-mapping radix tree, which is\n * rooted at mapping-\u003ei_pages, and indexed by offset.\n@@ -3022,9 +3023,9 @@ static inline bool folio_maybe_mapped_shared(struct folio *folio)\n * @folio: the folio\n *\n * Calculate the expected folio refcount, taking references from the pagecache,\n- * swapcache, PG_private and page table mappings into account. Useful in\n- * combination with folio_ref_count() to detect unexpected references (e.g.,\n- * GUP or other temporary references).\n+ * swapcache, private data (folio-\u003eprivate != NULL) and page table mappings into\n+ * account. Useful in combination with folio_ref_count() to detect unexpected\n+ * references (e.g., GUP or other temporary references).\n *\n * Does currently not consider references from the LRU cache. If the folio\n * was isolated from the LRU (which is the case during migration or split),\n@@ -3062,10 +3063,16 @@ static inline int folio_expected_ref_count(const struct folio *folio)\n \tref_count += folio_test_swapcache(folio) \u003c\u003c order;\n \n \tif (!folio_test_anon(folio)) {\n-\t\t/* One reference per page from the pagecache. */\n-\t\tref_count += !!folio-\u003emapping \u003c\u003c order;\n-\t\t/* One reference from PG_private. */\n-\t\tref_count += folio_test_private(folio);\n+\t\t/*\n+\t\t * One reference per page from the pagecache.\n+\t\t * Use data_race() since folio might not be locked.\n+\t\t */\n+\t\tref_count += !!data_race(folio-\u003emapping) \u003c\u003c order;\n+\t\t/*\n+\t\t * One reference from filesystem private data.\n+\t\t * Use data_race() since folio might not be locked.\n+\t\t */\n+\t\tref_count += data_race(folio_test_fs_private(folio));\n \t}\n \n \t/* One reference per page table mapping. */\ndiff --git a/include/linux/mm_types.h b/include/linux/mm_types.h\nindex 6d815f6440c94..e35aece38b933 100644\n--- a/include/linux/mm_types.h\n+++ b/include/linux/mm_types.h\n@@ -108,7 +108,7 @@ struct page {\n \t\t\t};\n \t\t\t/**\n \t\t\t * @private: Mapping-private opaque data.\n-\t\t\t * Usually used for buffer_heads if PagePrivate.\n+\t\t\t * Usually used for buffer_heads.\n \t\t\t * Used for swp_entry_t if swapcache flag set.\n \t\t\t * Indicates order in the buddy system if PageBuddy\n \t\t\t * or on pcp_llist.\n@@ -675,7 +675,7 @@ static inline void ptdesc_pmd_pts_init(struct ptdesc *ptdesc)\n #define STRUCT_PAGE_MAX_SHIFT\t(order_base_2(sizeof(struct page)))\n \n /*\n- * page_private can be used on tail pages. However, PagePrivate is only\n+ * page_private can be used on tail pages. However, it is only\n * checked by the VM on the head page. So page_private on the tail pages\n * should be used for data that's ancillary to the head page (eg attaching\n * buffer heads to tail pages after attaching buffer heads to the head page)\ndiff --git a/include/linux/page-flags.h b/include/linux/page-flags.h\nindex 7a863572adce7..eb2961ed61018 100644\n--- a/include/linux/page-flags.h\n+++ b/include/linux/page-flags.h\n@@ -44,10 +44,6 @@\n * Consequently, PG_reserved for a page mapped into user space can indicate\n * the zero page, the vDSO, MMIO pages or device memory.\n *\n- * The PG_private bitflag is set on pagecache pages if they contain filesystem\n- * specific data (which is normally at page-\u003eprivate). It can be used by\n- * private allocations for its own usage.\n- *\n * During initiation of disk I/O, PG_locked is set. This bit is set before I/O\n * and cleared when writeback _starts_ or when read _completes_. PG_writeback\n * is set before writeback starts and cleared when it finishes.\n@@ -105,7 +101,7 @@ enum pageflags {\n \tPG_owner_2,\t\t/* Owner use. If pagecache, fs may use */\n \tPG_arch_1,\n \tPG_reserved,\n-\tPG_private,\t\t/* If pagecache, has fs-private data */\n+\t__PG_folio,\t\t/* Do not use: reserved for folio identification */\n \tPG_private_2,\t\t/* If pagecache, has fs aux data */\n \tPG_reclaim,\t\t/* To be reclaimed asap */\n \tPG_swapbacked,\t\t/* Page is backed by RAM/swap */\n@@ -576,9 +572,14 @@ FOLIO_FLAG(swapbacked, FOLIO_HEAD_PAGE)\n /*\n * Private page markings that may be used by the filesystem that owns the page\n * for its own purposes.\n- * - PG_private and PG_private_2 cause release_folio() and co to be invoked\n+ * - folio-\u003eprivate and PG_private_2 cause release_folio() and co to be invoked\n */\n-PAGEFLAG(Private, private, PF_ANY)\n+\n+static __always_inline bool folio_test_private(const struct folio *folio)\n+{\n+\treturn folio-\u003eprivate;\n+}\n+\n FOLIO_FLAG(private_2, FOLIO_HEAD_PAGE)\n \n /* owner_2 can be set on tail pages for anon memory */\n@@ -1170,7 +1171,7 @@ static __always_inline void __ClearPageAnonExclusive(struct page *page)\n */\n #define PAGE_FLAGS_CHECK_AT_FREE\t\t\t\t\\\n \t(1UL \u003c\u003c PG_lru\t\t| 1UL \u003c\u003c PG_locked\t|\t\\\n-\t 1UL \u003c\u003c PG_private\t| 1UL \u003c\u003c PG_private_2\t|\t\\\n+\t 1UL \u003c\u003c PG_private_2\t|\t\t\t\t\\\n \t 1UL \u003c\u003c PG_writeback\t| 1UL \u003c\u003c PG_reserved\t|\t\\\n \t 1UL \u003c\u003c PG_active \t|\t\t\t\t\\\n \t 1UL \u003c\u003c PG_unevictable\t| __PG_MLOCKED | LRU_GEN_MASK)\n@@ -1194,8 +1195,23 @@ static __always_inline void __ClearPageAnonExclusive(struct page *page)\n \t(0xffUL /* order */\t\t| 1UL \u003c\u003c PG_has_hwpoisoned |\t\\\n \t 1UL \u003c\u003c PG_large_rmappable\t| 1UL \u003c\u003c PG_partially_mapped)\n \n-#define PAGE_FLAGS_PRIVATE\t\t\t\t\\\n-\t(1UL \u003c\u003c PG_private | 1UL \u003c\u003c PG_private_2)\n+/**\n+ * folio_test_fs_private - check if the folio has filesystem private data\n+ * @folio: The folio to check.\n+ *\n+ * Use this in code that may encounter swapcache or hugetlb folios but only\n+ * wants to detect filesystem private data. Swapcache stores swp_entry_t in\n+ * folio-\u003eswap, a union with folio-\u003eprivate, and hugetlb stores its own flags\n+ * in folio-\u003eprivate; both are excluded.\n+ *\n+ * Return: true if folio-\u003eprivate is set and the folio is neither swapcache\n+ * nor hugetlb.\n+ */\n+static inline bool folio_test_fs_private(const struct folio *folio)\n+{\n+\treturn folio_test_private(folio) \u0026\u0026 !folio_test_swapcache(folio) \u0026\u0026\n+\t !folio_test_hugetlb(folio);\n+}\n /**\n * folio_has_private - Determine if folio has private stuff\n * @folio: The folio to be checked\n@@ -1205,7 +1221,7 @@ static __always_inline void __ClearPageAnonExclusive(struct page *page)\n */\n static inline int folio_has_private(const struct folio *folio)\n {\n-\treturn !!(folio-\u003eflags.f \u0026 PAGE_FLAGS_PRIVATE);\n+\treturn folio_test_fs_private(folio) || folio_test_private_2(folio);\n }\n \n #undef PF_ANY\ndiff --git a/include/linux/pagemap.h b/include/linux/pagemap.h\nindex 0adfa6605653d..88b4c92b43575 100644\n--- a/include/linux/pagemap.h\n+++ b/include/linux/pagemap.h\n@@ -594,7 +594,6 @@ static inline void folio_attach_private(struct folio *folio, void *data)\n {\n \tfolio_get(folio);\n \tfolio-\u003eprivate = data;\n-\tfolio_set_private(folio);\n }\n \n /**\n@@ -629,9 +628,8 @@ static inline void *folio_detach_private(struct folio *folio)\n {\n \tvoid *data = folio_get_private(folio);\n \n-\tif (!folio_test_private(folio))\n+\tif (!data)\n \t\treturn NULL;\n-\tfolio_clear_private(folio);\n \tfolio-\u003eprivate = NULL;\n \tfolio_put(folio);\n \n@@ -1416,6 +1414,7 @@ struct readahead_control {\n \tbool dropbehind;\n \tbool _workingset;\n \tunsigned long _pflags;\n+\tbool _forward;\n };\n \n #define DEFINE_READAHEAD(ractl, f, r, m, i)\t\t\t\t\\\n@@ -1480,18 +1479,25 @@ void page_cache_async_readahead(struct address_space *mapping,\n \tpage_cache_async_ra(\u0026ractl, folio, req_count);\n }\n \n+static inline void __readahead_advance(struct readahead_control *rac)\n+{\n+\tif (rac-\u003e_forward)\n+\t\trac-\u003e_index += rac-\u003e_batch_count;\n+\n+\trac-\u003e_nr_pages -= rac-\u003e_batch_count;\n+\trac-\u003e_batch_count = 0;\n+}\n+\n static inline struct folio *__readahead_folio(struct readahead_control *ractl)\n {\n \tstruct folio *folio;\n \n \tBUG_ON(ractl-\u003e_batch_count \u003e ractl-\u003e_nr_pages);\n-\tractl-\u003e_nr_pages -= ractl-\u003e_batch_count;\n-\tractl-\u003e_index += ractl-\u003e_batch_count;\n+\t__readahead_advance(ractl);\n+\tractl-\u003e_forward = true;\n \n-\tif (!ractl-\u003e_nr_pages) {\n-\t\tractl-\u003e_batch_count = 0;\n+\tif (!ractl-\u003e_nr_pages)\n \t\treturn NULL;\n-\t}\n \n \tfolio = xa_load(\u0026ractl-\u003emapping-\u003ei_pages, ractl-\u003e_index);\n \tVM_BUG_ON_FOLIO(!folio_test_locked(folio), folio);\n@@ -1517,6 +1523,39 @@ static inline struct folio *readahead_folio(struct readahead_control *ractl)\n \treturn folio;\n }\n \n+/**\n+ * readahead_folio_last - Get the next folio to read, from the tail.\n+ * @ractl: The current readahead request.\n+ *\n+ * Like readahead_folio(), but walks the range back-to-front. The folio is\n+ * returned locked with its refcount dropped; the caller unlocks it once I/O\n+ * completes. Compound folios are returned once, at their head index.\n+ *\n+ * Context: The folio is locked.\n+ * Return: A pointer to the next folio, or %NULL when done.\n+ */\n+static inline struct folio *readahead_folio_last(struct readahead_control *ractl)\n+{\n+\tstruct folio *folio;\n+\n+\t/* Drop the previously returned batch from the remaining range. */\n+\t__readahead_advance(ractl);\n+\tractl-\u003e_forward = false;\n+\n+\tif (!ractl-\u003e_nr_pages)\n+\t\treturn NULL;\n+\n+\t/* xa_load() follows sibling entries, so a tail index returns the head */\n+\tfolio = xa_load(\u0026ractl-\u003emapping-\u003ei_pages,\n+\t\t\tractl-\u003e_index + ractl-\u003e_nr_pages - 1);\n+\tVM_WARN_ON_ONCE_FOLIO(!folio_test_locked(folio), folio);\n+\n+\tractl-\u003e_batch_count = folio_nr_pages(folio);\n+\n+\tfolio_put(folio);\n+\treturn folio;\n+}\n+\n static inline unsigned int __readahead_batch(struct readahead_control *rac,\n \t\tstruct page **array, unsigned int array_sz)\n {\n@@ -1525,9 +1564,8 @@ static inline unsigned int __readahead_batch(struct readahead_control *rac,\n \tstruct folio *folio;\n \n \tBUG_ON(rac-\u003e_batch_count \u003e rac-\u003e_nr_pages);\n-\trac-\u003e_nr_pages -= rac-\u003e_batch_count;\n-\trac-\u003e_index += rac-\u003e_batch_count;\n-\trac-\u003e_batch_count = 0;\n+\t__readahead_advance(rac);\n+\trac-\u003e_forward = true;\n \n \txas_set(\u0026xas, rac-\u003e_index);\n \trcu_read_lock();\ndiff --git a/include/trace/events/mmflags.h b/include/trace/events/mmflags.h\nindex 935893e5ea53b..caf090cd6f85e 100644\n--- a/include/trace/events/mmflags.h\n+++ b/include/trace/events/mmflags.h\n@@ -144,7 +144,7 @@ TRACE_DEFINE_ENUM(___GFP_LAST_BIT);\n \tDEF_PAGEFLAG_NAME(owner_2),\t\t\t\t\t\\\n \tDEF_PAGEFLAG_NAME(arch_1),\t\t\t\t\t\\\n \tDEF_PAGEFLAG_NAME(reserved),\t\t\t\t\t\\\n-\tDEF_PAGEFLAG_NAME(private),\t\t\t\t\t\\\n+\t{ 1UL \u003c\u003c __PG_folio, \"folio\" },\t\t\t\t\t\\\n \tDEF_PAGEFLAG_NAME(private_2),\t\t\t\t\t\\\n \tDEF_PAGEFLAG_NAME(writeback),\t\t\t\t\t\\\n \tDEF_PAGEFLAG_NAME(head),\t\t\t\t\t\\\ndiff --git a/include/trace/events/pagemap.h b/include/trace/events/pagemap.h\nindex 36c3a90f0acca..5425ef7bbae6e 100644\n--- a/include/trace/events/pagemap.h\n+++ b/include/trace/events/pagemap.h\n@@ -22,7 +22,7 @@\n \t(folio_test_swapcache(folio)\t? PAGEMAP_SWAPCACHE : 0) | \\\n \t(folio_test_swapbacked(folio)\t? PAGEMAP_SWAPBACKED : 0) | \\\n \t(folio_test_mappedtodisk(folio)\t? PAGEMAP_MAPPEDDISK : 0) | \\\n-\t(folio_test_private(folio)\t? PAGEMAP_BUFFERS : 0) \\\n+\t(folio_test_fs_private(folio)\t? PAGEMAP_BUFFERS : 0) \\\n \t)\n \n TRACE_EVENT(mm_lru_insertion,\ndiff --git a/kernel/events/ring_buffer.c b/kernel/events/ring_buffer.c\nindex 9fe92161715e0..061b5cb222266 100644\n--- a/kernel/events/ring_buffer.c\n+++ b/kernel/events/ring_buffer.c\n@@ -630,11 +630,10 @@ static struct page *rb_alloc_aux_page(int node, int order)\n \t\t/*\n \t\t * Communicate the allocation size to the driver:\n \t\t * if we managed to secure a high-order allocation,\n-\t\t * set its first page's private to this order;\n-\t\t * !PagePrivate(page) means it's just a normal page.\n+\t\t * set its first page's private to this order, otherwise page's\n+\t\t * private remains zero.\n \t\t */\n \t\tsplit_page(page, order);\n-\t\tSetPagePrivate(page);\n \t\tset_page_private(page, order);\n \t}\n \n@@ -645,7 +644,7 @@ static void rb_free_aux_page(struct perf_buffer *rb, int idx)\n {\n \tstruct page *page = virt_to_page(rb-\u003eaux_pages[idx]);\n \n-\tClearPagePrivate(page);\n+\tset_page_private(page, 0);\n \t__free_page(page);\n }\n \ndiff --git a/kernel/vmcore_info.c b/kernel/vmcore_info.c\nindex 8614430ca212a..5a417f8a922ab 100644\n--- a/kernel/vmcore_info.c\n+++ b/kernel/vmcore_info.c\n@@ -216,7 +216,6 @@ static int __init crash_save_vmcoreinfo_init(void)\n \tVMCOREINFO_LENGTH(free_area.free_list, MIGRATE_TYPES);\n \tVMCOREINFO_NUMBER(NR_FREE_PAGES);\n \tVMCOREINFO_NUMBER(PG_lru);\n-\tVMCOREINFO_NUMBER(PG_private);\n \tVMCOREINFO_NUMBER(PG_swapcache);\n \tVMCOREINFO_NUMBER(PG_swapbacked);\n #define PAGE_SLAB_MAPCOUNT_VALUE\t(PGTY_slab \u003c\u003c 24)\ndiff --git a/mm/huge_memory.c b/mm/huge_memory.c\nindex ced400f72d43a..d085fd09466ef 100644\n--- a/mm/huge_memory.c\n+++ b/mm/huge_memory.c\n@@ -4810,7 +4810,7 @@ static int split_huge_pages_pid(int pid, unsigned long vaddr_start,\n \t\t * will try to drop it before split and then check if the folio\n \t\t * can be split or not. So skip the check here.\n \t\t */\n-\t\tif (!folio_test_private(folio) \u0026\u0026\n+\t\tif (!folio_test_fs_private(folio) \u0026\u0026\n \t\t folio_expected_ref_count(folio) != folio_ref_count(folio))\n \t\t\tgoto next;\n \ndiff --git a/mm/hugetlb.c b/mm/hugetlb.c\nindex 7857728457952..4b6753b87162d 100644\n--- a/mm/hugetlb.c\n+++ b/mm/hugetlb.c\n@@ -1433,10 +1433,10 @@ void add_hugetlb_folio(struct hstate *h, struct folio *folio,\n \t}\n \n \t__folio_set_hugetlb(folio);\n-\tfolio_change_private(folio, NULL);\n+\tfolio-\u003eprivate = NULL;\n \t/*\n-\t * We have to set hugetlb_vmemmap_optimized again as above\n-\t * folio_change_private(folio, NULL) cleared it.\n+\t * The hugetlb flags live in folio-\u003eprivate and are cleared by the above\n+\t * assignment. Restore the hugetlb_vmemmap_optimized flag.\n \t */\n \tfolio_set_hugetlb_vmemmap_optimized(folio);\n \ndiff --git a/mm/migrate.c b/mm/migrate.c\nindex 15b45832bcfa7..5ca1548ca6d61 100644\n--- a/mm/migrate.c\n+++ b/mm/migrate.c\n@@ -835,7 +835,6 @@ void folio_migrate_flags(struct folio *newfolio, struct folio *folio)\n \t */\n \tif (folio_test_swapcache(folio))\n \t\tfolio_clear_swapcache(folio);\n-\tfolio_clear_private(folio);\n \n \t/* page-\u003eprivate contains hugetlb specific flags */\n \tif (!folio_test_hugetlb(folio))\n@@ -1327,7 +1326,7 @@ static int migrate_folio_unmap(new_folio_t get_new_folio,\n \t * free the metadata, so the page can be freed.\n \t */\n \tif (!src-\u003emapping) {\n-\t\tif (folio_test_private(src)) {\n+\t\tif (folio_test_fs_private(src)) {\n \t\t\ttry_to_free_buffers(src);\n \t\t\tgoto out;\n \t\t}\ndiff --git a/mm/page-writeback.c b/mm/page-writeback.c\nindex eeab25d6ce364..e03a1c46bce01 100644\n--- a/mm/page-writeback.c\n+++ b/mm/page-writeback.c\n@@ -2705,7 +2705,7 @@ bool filemap_dirty_folio(struct address_space *mapping, struct folio *folio)\n \tif (folio_test_set_dirty(folio))\n \t\treturn false;\n \n-\t__folio_mark_dirty(folio, mapping, !folio_test_private(folio));\n+\t__folio_mark_dirty(folio, mapping, !folio_test_fs_private(folio));\n \n \tif (mapping-\u003ehost) {\n \t\t/* !PageAnon \u0026\u0026 !swapper_space */\ndiff --git a/mm/vmscan.c b/mm/vmscan.c\nindex f11491ee9ed5c..29051c0f89881 100644\n--- a/mm/vmscan.c\n+++ b/mm/vmscan.c\n@@ -955,7 +955,7 @@ static void folio_check_dirty_writeback(struct folio *folio,\n \t*writeback = folio_test_writeback(folio);\n \n \t/* Verify dirty/writeback state if the filesystem supports it */\n-\tif (!folio_test_private(folio))\n+\tif (!folio_test_fs_private(folio))\n \t\treturn;\n \n \tmapping = folio_mapping(folio);\ndiff --git a/mm/zpdesc.h b/mm/zpdesc.h\nindex b8258dc78548d..4fd81c2e80769 100644\n--- a/mm/zpdesc.h\n+++ b/mm/zpdesc.h\n@@ -26,8 +26,8 @@\n * with memcg_data.\n *\n * Page flags used:\n- * * PG_private identifies the first component page.\n * * PG_locked is used by page migration code.\n+ * The first component page has zpdesc-\u003ezspage-\u003efirst_zpdesc == zpdesc\n */\n struct zpdesc {\n \tunsigned long flags;\ndiff --git a/mm/zsmalloc.c b/mm/zsmalloc.c\nindex 825022a7a328f..24526185fd31f 100644\n--- a/mm/zsmalloc.c\n+++ b/mm/zsmalloc.c\n@@ -290,11 +290,6 @@ struct zs_pool {\n \tatomic_t compaction_in_progress;\n };\n \n-static inline void zpdesc_set_first(struct zpdesc *zpdesc)\n-{\n-\tSetPagePrivate(zpdesc_page(zpdesc));\n-}\n-\n static inline void zpdesc_inc_zone_page_state(struct zpdesc *zpdesc)\n {\n \tinc_zone_page_state(zpdesc_page(zpdesc), NR_ZSPAGES);\n@@ -476,11 +471,6 @@ static void record_obj(unsigned long handle, unsigned long obj)\n \tWRITE_ONCE(*(unsigned long *)handle, obj);\n }\n \n-static inline bool __maybe_unused is_first_zpdesc(struct zpdesc *zpdesc)\n-{\n-\treturn PagePrivate(zpdesc_page(zpdesc));\n-}\n-\n /* Protected by class-\u003elock */\n static inline int get_zspage_inuse(struct zspage *zspage)\n {\n@@ -496,7 +486,8 @@ static struct zpdesc *get_first_zpdesc(struct zspage *zspage)\n {\n \tstruct zpdesc *first_zpdesc = zspage-\u003efirst_zpdesc;\n \n-\tVM_BUG_ON_PAGE(!is_first_zpdesc(first_zpdesc), zpdesc_page(first_zpdesc));\n+\t/* the first zpdesc must point back to this zspage */\n+\tVM_WARN_ON_ONCE_PAGE(first_zpdesc-\u003ezspage != zspage, zpdesc_page(first_zpdesc));\n \treturn first_zpdesc;\n }\n \n@@ -838,7 +829,8 @@ static inline bool obj_allocated(struct zpdesc *zpdesc, void *obj,\n \tstruct zspage *zspage = get_zspage(zpdesc);\n \n \tif (unlikely(ZsHugePage(zspage))) {\n-\t\tVM_BUG_ON_PAGE(!is_first_zpdesc(zpdesc), zpdesc_page(zpdesc));\n+\t\t/* only first zpdesc holds the handle */\n+\t\tVM_WARN_ON_ONCE_PAGE(zspage-\u003efirst_zpdesc != zpdesc, zpdesc_page(zpdesc));\n \t\thandle = zpdesc-\u003ehandle;\n \t} else\n \t\thandle = *(unsigned long *)obj;\n@@ -853,9 +845,6 @@ static inline bool obj_allocated(struct zpdesc *zpdesc, void *obj,\n \n static void reset_zpdesc(struct zpdesc *zpdesc)\n {\n-\tstruct page *page = zpdesc_page(zpdesc);\n-\n-\tClearPagePrivate(page);\n \tzpdesc-\u003ezspage = NULL;\n \tzpdesc-\u003enext = NULL;\n \t/* PageZsmalloc is sticky until the page is freed to the buddy. */\n@@ -1006,8 +995,8 @@ static void create_page_chain(struct size_class *class, struct zspage *zspage,\n \t * 1. all pages are linked together using zpdesc-\u003enext\n \t * 2. each sub-page point to zspage using zpdesc-\u003ezspage\n \t *\n-\t * we set PG_private to identify the first zpdesc (i.e. no other zpdesc\n-\t * has this flag set).\n+\t * The first zpdesc has its zspage-\u003efirst_zpdesc set to itself, no\n+\t * other zpdesc has this set.\n \t */\n \tfor (i = 0; i \u003c nr_zpdescs; i++) {\n \t\tzpdesc = zpdescs[i];\n@@ -1015,7 +1004,6 @@ static void create_page_chain(struct size_class *class, struct zspage *zspage,\n \t\tzpdesc-\u003enext = NULL;\n \t\tif (i == 0) {\n \t\t\tzspage-\u003efirst_zpdesc = zpdesc;\n-\t\t\tzpdesc_set_first(zpdesc);\n \t\t\tif (unlikely(class-\u003eobjs_per_zspage == 1 \u0026\u0026\n \t\t\t\t\tclass-\u003epages_per_zspage == 1))\n \t\t\t\tSetZsHugePage(zspage);\ndiff --git a/tools/mm/page-types.c b/tools/mm/page-types.c\nindex 7fc5a8be5997f..47e4781c5fc38 100644\n--- a/tools/mm/page-types.c\n+++ b/tools/mm/page-types.c\n@@ -73,7 +73,6 @@\n #define KPF_RESERVED\t\t32\n #define KPF_MLOCKED\t\t33\n #define KPF_OWNER_2\t\t34\n-#define KPF_PRIVATE\t\t35\n #define KPF_PRIVATE_2\t\t36\n #define KPF_OWNER_PRIVATE\t37\n #define KPF_ARCH\t\t38\n@@ -131,7 +130,6 @@ static const char * const page_flag_names[] = {\n \t[KPF_RESERVED]\t\t= \"r:reserved\",\n \t[KPF_MLOCKED]\t\t= \"m:mlocked\",\n \t[KPF_OWNER_2]\t\t= \"d:owner_2\",\n-\t[KPF_PRIVATE]\t\t= \"P:private\",\n \t[KPF_PRIVATE_2]\t\t= \"p:private_2\",\n \t[KPF_OWNER_PRIVATE]\t= \"O:owner_private\",\n \t[KPF_ARCH]\t\t= \"h:arch\",\n"
} |
| 2/1 | 2026/09/01 03:41 | agent | patch-evaluator |
2mModel:core Args: null Results: {
"EnableConfigs": [
"EROFS_FS",
"EROFS_FS_ZIP",
"FS_ENCRYPTION",
"HUGETLBFS",
"TRANSPARENT_HUGEPAGE",
"ZSMALLOC"
],
"FocusSymbols": [
"erofs_onlinefolio_init",
"erofs_onlinefolio_end",
"fscrypt_encrypt_pagecache_blocks",
"fscrypt_free_bounce_page",
"add_hugetlb_folio",
"folio_migrate_flags",
"stable_page_flags"
],
"Reasoning": "The patch removes the PG_private page flag across the kernel in favor of direct folio-\u003eprivate and page_private checks, implements a reverse readahead iterator (readahead_folio_last) for pagemaps, updates online folio handling in EROFS, updates ciphertext bounce page handling in fscrypt, and adjusts HugeTLB/migration/zsmalloc metadata tracking. These are reachable, functional changes in core memory management and filesystems that should be fuzzed.",
"WorthFuzzing": true
}Instruction: You are an expert Linux kernel maintainer. Your job is to review a provided patch series and determine if it makes functional changes to the kernel that should be fuzzed. IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in your workspace. Do NOT rely on your internal knowledge of the kernel. You must actively use your code access tools to examine the actual source code and confirm any assumptions. Return WorthFuzzing=false if the patch only contains: - Modifications to Documentation/, Kconfig files, or code comments. - Purely decorative changes, such as logging (e.g., pr_err, printk) or tracepoints. - Changes to numeric constants or macros that do not functionally alter execution flow. - Code paths that are impossible to reach in virtualized environments like GCE or QEMU, even when utilizing software-emulated hardware (e.g., usb gadget, mac80211_hwsim). - Code in vendor-specific PCIe switch, SmartNIC, or GPU drivers (e.g., mlxsw, pds_core, qed, ionic, amdgpu) that require physical PCIe hardware cards not emulated in standard QEMU. - Driver .remove, .shutdown, or pci_unregister_driver teardown callbacks (e.g., igb_remove) that are executed only during PCI hot-unplug or sysfs driver unbind operations. If it modifies reachable core kernel logic, drivers, or architectures, use your code search tools to verify the code can be executed, then return WorthFuzzing=true. When returning WorthFuzzing=true, you MUST ALSO: 1. Extract any specific kernel functions that should be heavily fuzzed into FocusSymbols. Avoid listing generic hot-path functions to prevent skewed test distributions. Prefer non-static, non-inlined API entrypoint functions over internal static helper functions (which are inlined by the compiler and do not have distinct symbol addresses). 2. Identify any specific CONFIG_ options required to properly test this new/modified feature. Go and look into the Kconfig files and check for ifdefs around the code, do not make assumptions. Also check "depends on" lines in Kconfig to include any non-standard parent subsystem configs needed for Kbuild to compile the code statically into vmlinux. List them in the EnableConfigs output array, and DO NOT add a 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4"). Prefer calling several tools at the same time to save round-trips. Use set-results tool to provide results of the analysis. It must be called exactly once before the final reply. Ignore results of this tool. Prompt: For your convenience, here is the diff of the changes:
commit 421bcb73cd4f011e8a27d95d741dbb1eb94e34c6
Author: syz-cluster <triage@syzkaller.com>
Date: Tue Sep 1 03:41:49 2026 +0000
syz-cluster: applied patch under review
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 d3a93eec3945f..dec7816303c6a 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/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 5754cd4055628..49349afee6119 100644
--- a/arch/x86/events/intel/pt.c
+++ b/arch/x86/events/intel/pt.c
@@ -781,8 +781,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);
@@ -1296,8 +1295,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/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c
index b8325cb09a371..0cf14bc1cff32 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/drivers/xen/balloon.c b/drivers/xen/balloon.c
index e7f74ea7cd5eb..fdb18348cfdfe 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 69922be28b54c..993f89f048e21 100644
--- a/drivers/xen/grant-table.c
+++ b/drivers/xen/grant-table.c
@@ -863,10 +863,10 @@ EXPORT_SYMBOL_GPL(gnttab_free_auto_xlat_frames);
int gnttab_pages_set_private(int nr_pages, struct page **pages)
{
+#if BITS_PER_LONG < 64
int i;
for (i = 0; i < nr_pages; i++) {
-#if BITS_PER_LONG < 64
struct xen_page_foreign *foreign;
foreign = kzalloc_obj(*foreign);
@@ -874,9 +874,9 @@ int gnttab_pages_set_private(int nr_pages, struct page **pages)
return -ENOMEM;
set_page_private(pages[i], (unsigned long)foreign);
-#endif
- SetPagePrivate(pages[i]);
}
+#endif
+ /* 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);
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c
index 657c2cb0f8811..f9b2ec9550481 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;
}
/*
@@ -124,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. Setting folio->private is
+ * what gets us the invalidate_folio callback.
*/
VM_WARN_ON_FOLIO(folio->private, folio);
folio_attach_private(folio, snapc);
diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c
index 5286a124b0d98..aced5c50a4601 100644
--- a/fs/crypto/crypto.c
+++ b/fs/crypto/crypto.c
@@ -65,7 +65,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);
@@ -210,7 +209,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;
}
diff --git a/fs/erofs/data.c b/fs/erofs/data.c
index 0885b1f2fc925..f71c7b51bb720 100644
--- a/fs/erofs/data.c
+++ b/fs/erofs/data.c
@@ -239,19 +239,23 @@ int erofs_map_dev(struct super_block *sb, struct erofs_map_dev *map)
/*
* bit 30: I/O error occurred on this folio
* bit 29: CPU has dirty data in D-cache (needs aliasing handling);
- * bit 0 - 29: remaining parts to complete this folio
+ * bit 0 - 28: remaining parts to complete this folio, biased by 1 so that
+ * ->private stays non-NULL while the folio is attached
*/
#define EROFS_ONLINEFOLIO_EIO 30
#define EROFS_ONLINEFOLIO_DIRTY 29
+#define EROFS_ONLINEFOLIO_COUNT_MASK (BIT(EROFS_ONLINEFOLIO_DIRTY) - 1)
+#define EROFS_ONLINEFOLIO_BIAS 1
void erofs_onlinefolio_init(struct folio *folio)
{
union {
atomic_t o;
void *v;
- } u = { .o = ATOMIC_INIT(1) };
+ } u = { .o = ATOMIC_INIT(1 + EROFS_ONLINEFOLIO_BIAS) };
- 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)
@@ -265,14 +269,14 @@ void erofs_onlinefolio_end(struct folio *folio, int err, bool dirty)
do {
orig = atomic_read((atomic_t *)&folio->private);
- DBG_BUGON(orig <= 0);
+ DBG_BUGON((orig & EROFS_ONLINEFOLIO_COUNT_MASK) <= EROFS_ONLINEFOLIO_BIAS);
v = dirty << EROFS_ONLINEFOLIO_DIRTY;
v |= (orig - 1) | (!!err << EROFS_ONLINEFOLIO_EIO);
} while (atomic_cmpxchg((atomic_t *)&folio->private, orig, v) != orig);
- if (v & (BIT(EROFS_ONLINEFOLIO_DIRTY) - 1))
+ if ((v & EROFS_ONLINEFOLIO_COUNT_MASK) != EROFS_ONLINEFOLIO_BIAS)
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)));
diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c
index e1e25ca0d1904..78fd7d980e957 100644
--- a/fs/erofs/zdata.c
+++ b/fs/erofs/zdata.c
@@ -1898,21 +1898,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);
+ /* traverse from last to first for best metadata I/O performance */
+ while ((folio = readahead_folio_last(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/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 9940a6cecf1a2..2f7ab5888b078 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -2691,7 +2691,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)); \
}
@@ -2710,9 +2710,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)); \
}
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index e1bdd10b35f10..38f830a6467c9 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -484,7 +484,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,
@@ -555,7 +555,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/nfs/write.c b/fs/nfs/write.c
index 623e7ef1f73d5..b6967b5286691 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);
@@ -745,7 +744,6 @@ static void nfs_inode_remove_request(struct nfs_page *req)
spin_lock(&mapping->i_private_lock);
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/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/fs/ubifs/file.c b/fs/ubifs/file.c
index e73c28b12f97f..aa0298ce451ef 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
+ * not budgeted so it 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 the @PG_checked flag 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/buffer_head.h b/include/linux/buffer_head.h
index fd2c7115c0542..e47fbd0387b69 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,
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 dd09c438fa23e..2855739a0f379 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -2075,20 +2075,21 @@ 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
* offset of the folio, in units of PAGE_SIZE.
*
- * If pagecache pages are not associated with an inode, they are said to be
- * anonymous pages. These may become associated with the swapcache, and in that
- * case PG_swapcache is set, and page->private is an offset into the swapcache.
+ * If pagecache folios are not associated with an inode, they are said to be
+ * anonymous folios. These may become associated with the swapcache, and in that
+ * case PG_swapcache is set, and folio->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
- * refcount. The each user mapping also has a reference to the page.
+ * reference to the folio. Attaching filesystem private data via
+ * folio_attach_private() also increments the refcount. Each user mapping also
+ * has a reference to the folio.
*
* The pagecache pages are stored in a per-mapping radix tree, which is
* rooted at mapping->i_pages, and indexed by offset.
@@ -3022,9 +3023,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),
@@ -3062,10 +3063,16 @@ 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.
+ * Use data_race() since folio might not be locked.
+ */
+ ref_count += data_race(folio_test_fs_private(folio));
}
/* One reference per page table mapping. */
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index 6d815f6440c94..e35aece38b933 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)
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
index 7a863572adce7..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,9 +572,14 @@ 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)
+{
+ return folio->private;
+}
+
FOLIO_FLAG(private_2, FOLIO_HEAD_PAGE)
/* owner_2 can be set on tail pages for anon memory */
@@ -1170,7 +1171,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 +1195,23 @@ 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_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
@@ -1205,7 +1221,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_test_fs_private(folio) || folio_test_private_2(folio);
}
#undef PF_ANY
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index 0adfa6605653d..88b4c92b43575 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);
@@ -1416,6 +1414,7 @@ struct readahead_control {
bool dropbehind;
bool _workingset;
unsigned long _pflags;
+ bool _forward;
};
#define DEFINE_READAHEAD(ractl, f, r, m, i) \
@@ -1480,18 +1479,25 @@ void page_cache_async_readahead(struct address_space *mapping,
page_cache_async_ra(&ractl, folio, req_count);
}
+static inline void __readahead_advance(struct readahead_control *rac)
+{
+ if (rac->_forward)
+ rac->_index += rac->_batch_count;
+
+ rac->_nr_pages -= rac->_batch_count;
+ rac->_batch_count = 0;
+}
+
static inline struct folio *__readahead_folio(struct readahead_control *ractl)
{
struct folio *folio;
BUG_ON(ractl->_batch_count > ractl->_nr_pages);
- ractl->_nr_pages -= ractl->_batch_count;
- ractl->_index += ractl->_batch_count;
+ __readahead_advance(ractl);
+ ractl->_forward = true;
- if (!ractl->_nr_pages) {
- ractl->_batch_count = 0;
+ if (!ractl->_nr_pages)
return NULL;
- }
folio = xa_load(&ractl->mapping->i_pages, ractl->_index);
VM_BUG_ON_FOLIO(!folio_test_locked(folio), folio);
@@ -1517,6 +1523,39 @@ static inline struct folio *readahead_folio(struct readahead_control *ractl)
return folio;
}
+/**
+ * readahead_folio_last - 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_last(struct readahead_control *ractl)
+{
+ struct folio *folio;
+
+ /* Drop the previously returned batch from the remaining range. */
+ __readahead_advance(ractl);
+ ractl->_forward = false;
+
+ 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);
+
+ ractl->_batch_count = folio_nr_pages(folio);
+
+ folio_put(folio);
+ return folio;
+}
+
static inline unsigned int __readahead_batch(struct readahead_control *rac,
struct page **array, unsigned int array_sz)
{
@@ -1525,9 +1564,8 @@ static inline unsigned int __readahead_batch(struct readahead_control *rac,
struct folio *folio;
BUG_ON(rac->_batch_count > rac->_nr_pages);
- rac->_nr_pages -= rac->_batch_count;
- rac->_index += rac->_batch_count;
- rac->_batch_count = 0;
+ __readahead_advance(rac);
+ rac->_forward = true;
xas_set(&xas, rac->_index);
rcu_read_lock();
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/include/trace/events/pagemap.h b/include/trace/events/pagemap.h
index 36c3a90f0acca..5425ef7bbae6e 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_test_fs_private(folio) ? PAGEMAP_BUFFERS : 0) \
)
TRACE_EVENT(mm_lru_insertion,
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);
}
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)
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index ced400f72d43a..d085fd09466ef 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -4810,7 +4810,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_test_fs_private(folio) &&
folio_expected_ref_count(folio) != folio_ref_count(folio))
goto next;
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 7857728457952..4b6753b87162d 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.
+ * The hugetlb flags live in folio->private and are cleared by the above
+ * assignment. Restore the hugetlb_vmemmap_optimized flag.
*/
folio_set_hugetlb_vmemmap_optimized(folio);
diff --git a/mm/migrate.c b/mm/migrate.c
index 15b45832bcfa7..5ca1548ca6d61 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -835,7 +835,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))
@@ -1327,7 +1326,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_test_fs_private(src)) {
try_to_free_buffers(src);
goto out;
}
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index eeab25d6ce364..e03a1c46bce01 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_test_fs_private(folio));
if (mapping->host) {
/* !PageAnon && !swapper_space */
diff --git a/mm/vmscan.c b/mm/vmscan.c
index f11491ee9ed5c..29051c0f89881 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -955,7 +955,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_test_fs_private(folio))
return;
mapping = folio_mapping(folio);
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 825022a7a328f..24526185fd31f 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);
@@ -476,11 +471,6 @@ static void record_obj(unsigned long handle, unsigned long obj)
WRITE_ONCE(*(unsigned long *)handle, obj);
}
-static inline bool __maybe_unused is_first_zpdesc(struct zpdesc *zpdesc)
-{
- return PagePrivate(zpdesc_page(zpdesc));
-}
-
/* Protected by class->lock */
static inline int get_zspage_inuse(struct zspage *zspage)
{
@@ -496,7 +486,8 @@ static struct zpdesc *get_first_zpdesc(struct zspage *zspage)
{
struct zpdesc *first_zpdesc = zspage->first_zpdesc;
- VM_BUG_ON_PAGE(!is_first_zpdesc(first_zpdesc), zpdesc_page(first_zpdesc));
+ /* the first zpdesc must point back to this zspage */
+ VM_WARN_ON_ONCE_PAGE(first_zpdesc->zspage != zspage, zpdesc_page(first_zpdesc));
return first_zpdesc;
}
@@ -838,7 +829,8 @@ static inline bool obj_allocated(struct zpdesc *zpdesc, void *obj,
struct zspage *zspage = get_zspage(zpdesc);
if (unlikely(ZsHugePage(zspage))) {
- VM_BUG_ON_PAGE(!is_first_zpdesc(zpdesc), zpdesc_page(zpdesc));
+ /* only first zpdesc holds the handle */
+ VM_WARN_ON_ONCE_PAGE(zspage->first_zpdesc != zpdesc, zpdesc_page(zpdesc));
handle = zpdesc->handle;
} else
handle = *(unsigned long *)obj;
@@ -853,9 +845,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. */
@@ -1006,8 +995,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];
@@ -1015,7 +1004,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);
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",
|
| 3/2 | 2026/09/01 03:41 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 16076 output: 20 thoughts: 906 Thoughts: **Analyzing a Core Memory Management Refactoring** Alright, let's dive into this patch series. My initial impression is that it's a significant refactor, specifically targeting how the kernel handles page flags and private data associated with pages and folios. It seems `PG_private` is being deprecated and replaced with a more granular approach using `page_private()`, `folio->private`, and related folio-based functions. Thatās a fundamental shift in how memory metadata is managed, and it touches a vast number of subsystems. I see a substantial list of modified files, which confirms my initial assessment. Itās hitting Documentation, core MM components, filesystems (Ceph, EROFS, F2FS, NFS, UBIFS), drivers (Xen, MD, Xen, etc.), and tracing facilities. The implications are wide-ranging, potentially affecting everything from filesystem I/O to memory management in various architectures. We're talking about changes to `readahead_folio_last`, EROFS readahead, zsmalloc, huge memory, and more. This is definitely a candidate for fuzzing. Now, let's apply the fuzzing criteria. This clearly isn't just documentation or logging; it's a core modification of reachable kernel logic across MM, filesystems, and drivers. The changes are deeply integrated into the kernel's memory management and I/O paths, and this isn't specific to any impossible-to-reach hardware configuration. No dice, this is *definitely* worth fuzzing. My next step is to nail down the `FocusSymbols` and `EnableConfigs`. This refactor is complex and impacts many core data paths, so I need to carefully analyze the changes in detail to identify which specific functions and configurations are most relevant. I'll be using `grepper` or `read-file` to zero in on the modified functions and how the change has impacted them. Time to get to work! |
| 4/2 | 2026/09/01 03:41 | tool | grepper |
0mArgs:{
"Expression": "readahead_folio_last"
}Results: {
"Output": "fs/erofs/zdata.c=1894=static void z_erofs_readahead(struct readahead_control *rac)\n--\nfs/erofs/zdata.c-1907-\t/* traverse from last to first for best metadata I/O performance */\nfs/erofs/zdata.c:1908:\twhile ((folio = readahead_folio_last(rac))) {\nfs/erofs/zdata.c-1909-\t\terr = z_erofs_scan_folio(\u0026f, folio, true);\n--\ninclude/linux/pagemap.h=1517=static inline struct folio *readahead_folio(struct readahead_control *ractl)\n--\ninclude/linux/pagemap.h-1526-/**\ninclude/linux/pagemap.h:1527: * readahead_folio_last - Get the next folio to read, from the tail.\ninclude/linux/pagemap.h-1528- * @ractl: The current readahead request.\n--\ninclude/linux/pagemap.h-1536- */\ninclude/linux/pagemap.h:1537:static inline struct folio *readahead_folio_last(struct readahead_control *ractl)\ninclude/linux/pagemap.h-1538-{\n"
} |
| 5/2 | 2026/09/01 03:42 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 17751 output: 31 thoughts: 668 Thoughts: **My Analysis of the Code Changes** Okay, let's dive into this patch. My initial focus is always on understanding the core logic alterations and potential performance implications. I'm going to start by scrutinizing the functions that were modified, particularly those that aren't static or are considered entry points, or where the core logic was likely changed. So, I'm going to start with the files that have been flagged as modified: `arch/x86/events/intel/bts.c`, `arch/x86/events/intel/pt.c`, `drivers/md/md-bitmap.c`, `drivers/xen/balloon.c`, `drivers/xen/grant-table.c`, `fs/ceph/addr.c`, `fs/crypto/crypto.c`, `fs/erofs/data.c`, `fs/erofs/zdata.c`, `fs/f2fs/f2fs.h`, `fs/nfs/write.c`, `fs/proc/page.c`, `kernel/events/ring_buffer.c`, `mm/huge_memory.c`, `mm/hugetlb.c`, `mm/migrate.c`, `mm/page-writeback.c`, `mm/vmscan.c`, and `mm/zsmalloc.c`. I'll be looking closely at `buf_nr_pages`, `topa_insert_pages`, `pt_buffer_try_single`, `write_file_page`, `free_buffers`, `balloon_retrieve`, `gnttab_pages_set_private`, `gnttab_pages_clear_private`, `page_snap_context`, `ceph_dirty_folio`, `fscrypt_free_bounce_page`, `fscrypt_encrypt_pagecache_blocks`, `erofs_onlinefolio_init`, `erofs_onlinefolio_end`, `z_erofs_readahead`, the various `page_private_##name` and `set_page_private_##name` macros in `f2fs.h`, `nfs_inode_add_request`, `nfs_inode_remove_request`, `stable_page_flags`, `rb_alloc_aux_page`, `rb_free_aux_page`, `split_huge_pages_pid`, `add_hugetlb_folio`, `folio_migrate_flags`, `migrate_folio_unmap`, `filemap_dirty_folio`, `folio_check_dirty_writeback`, `get_first_zpdesc`, `obj_allocated`, `reset_zpdesc`, and `create_page_chain`. Now, I'm going to specifically single out non-static functions and those with distinct symbols within the modules `fs/erofs/data.c`, `fs/erofs/zdata.c`, `mm/huge_memory.c`, `mm/hugetlb.c`, `mm/migrate.c`, `mm/page-writeback.c`, `mm/vmscan.c`, and `fs/crypto/crypto.c` (and the rest of the list, of course) as a starting point to assess their impact on the overall system behavior. From there, I'll be able to get a better handle on the implications. |
| 6/2 | 2026/09/01 03:42 | tool | grepper |
0mArgs:{
"Expression": "void erofs_onlinefolio_",
"PathPrefix": "fs/erofs"
}Results: {
"Output": "fs/erofs/data.c=197=int erofs_map_dev(struct super_block *sb, struct erofs_map_dev *map)\n--\nfs/erofs/data.c-249-\nfs/erofs/data.c:250:void erofs_onlinefolio_init(struct folio *folio)\nfs/erofs/data.c-251-{\n--\nfs/erofs/data.c-260-\nfs/erofs/data.c:261:void erofs_onlinefolio_split(struct folio *folio)\nfs/erofs/data.c-262-{\n--\nfs/erofs/data.c-265-\nfs/erofs/data.c:266:void erofs_onlinefolio_end(struct folio *folio, int err, bool dirty)\nfs/erofs/data.c-267-{\n--\nfs/erofs/internal.h=419=int erofs_map_blocks(struct inode *inode, struct erofs_map_blocks *map);\nfs/erofs/internal.h:420:void erofs_onlinefolio_init(struct folio *folio);\nfs/erofs/internal.h:421:void erofs_onlinefolio_split(struct folio *folio);\nfs/erofs/internal.h:422:void erofs_onlinefolio_end(struct folio *folio, int err, bool dirty);\nfs/erofs/internal.h-423-struct inode *erofs_iget(struct super_block *sb, erofs_nid_t nid);\n"
} |
| 7/2 | 2026/09/01 03:42 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 19562 output: 31 thoughts: 59 Thoughts: Here's my take on those thoughts: **Analyzing `z_erofs_readahead` in the EROFS Filesystem** Okay, so I need to understand how the EROFS filesystem handles readahead. The place to start is likely `fs/erofs/zdata.c`. Let's confirm: is `z_erofs_readahead` an implementation of an `address_space_operations` callback? I'm pretty sure it is, but it's always best to double-check the source code. Let me open that file and verify the function's usage within the `address_space_operations` structure. This will provide context for how EROFS optimizes I/O performance. I suspect this function plays a crucial role in prefetching data and minimizing latency. |
| 8/2 | 2026/09/01 03:42 | tool | grepper |
0mArgs:{
"Expression": "z_erofs_readahead",
"PathPrefix": "fs/erofs"
}Results: {
"Output": "fs/erofs/zdata.c=1866=static int z_erofs_read_folio(struct file *file, struct folio *folio)\n--\nfs/erofs/zdata.c-1893-\nfs/erofs/zdata.c:1894:static void z_erofs_readahead(struct readahead_control *rac)\nfs/erofs/zdata.c-1895-{\n--\nfs/erofs/zdata.c=1925=const struct address_space_operations z_erofs_aops = {\nfs/erofs/zdata.c-1926-\t.read_folio = z_erofs_read_folio,\nfs/erofs/zdata.c:1927:\t.readahead = z_erofs_readahead,\nfs/erofs/zdata.c-1928-};\n"
} |
| 9/2 | 2026/09/01 03:42 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 20051 output: 43 thoughts: 36 Thoughts: Okay, let's dive in. **Flipping Through Crypto.c for the Kernel's Block Encryption** Alright, I need to jog my memory on the pagecache encryption routines. Where are we handling block-level encryption within the filesystem, again? Right, `fs/crypto/crypto.c` is the likely spot. Let's see... yep, it looks like `fscrypt_encrypt_pagecache_blocks` is what I'm after, that's where the actual encryption process likely happens on the data read from or written to the page cache. I need to be sure to check how it interfaces with the lower layers and how it handles the details. And I should probably check the decryption function while I am there. And of course, I need to see how the kernel handles releasing bounce pages. So, `fscrypt_free_bounce_page` is going to be relevant to my query, because these pages are created to deal with the encryption/decryption process. Need to understand how that memory is managed. |
| 10/2 | 2026/09/01 03:42 | tool | grepper |
0mArgs:{
"Expression": "fscrypt_encrypt_pagecache_blocks|fscrypt_free_bounce_page",
"PathPrefix": "fs/crypto"
}Results: {
"Output": "fs/crypto/crypto.c=45=static struct page *fscrypt_alloc_bounce_page(gfp_t gfp_flags)\n--\nfs/crypto/crypto.c-57-/**\nfs/crypto/crypto.c:58: * fscrypt_free_bounce_page() - free a ciphertext bounce page\nfs/crypto/crypto.c-59- * @bounce_page: the bounce page to free, or NULL\nfs/crypto/crypto.c-60- *\nfs/crypto/crypto.c:61: * Free a bounce page that was allocated by fscrypt_encrypt_pagecache_blocks().\nfs/crypto/crypto.c-62- */\nfs/crypto/crypto.c:63:void fscrypt_free_bounce_page(struct page *bounce_page)\nfs/crypto/crypto.c-64-{\n--\nfs/crypto/crypto.c-69-}\nfs/crypto/crypto.c:70:EXPORT_SYMBOL(fscrypt_free_bounce_page);\nfs/crypto/crypto.c-71-\n--\nfs/crypto/crypto.c=101=static int fscrypt_crypt_data_unit(const struct fscrypt_inode_info *ci,\n--\nfs/crypto/crypto.c-148-/**\nfs/crypto/crypto.c:149: * fscrypt_encrypt_pagecache_blocks() - Encrypt data from a pagecache folio\nfs/crypto/crypto.c-150- * @folio: the locked pagecache folio containing the data to encrypt\n--\nfs/crypto/crypto.c-172- */\nfs/crypto/crypto.c:173:struct page *fscrypt_encrypt_pagecache_blocks(struct folio *folio,\nfs/crypto/crypto.c-174-\t\tsize_t len, size_t offs, gfp_t gfp_flags)\n--\nfs/crypto/crypto.c-207-\t\tif (err) {\nfs/crypto/crypto.c:208:\t\t\tfscrypt_free_bounce_page(ciphertext_page);\nfs/crypto/crypto.c-209-\t\t\treturn ERR_PTR(err);\n--\nfs/crypto/crypto.c-214-}\nfs/crypto/crypto.c:215:EXPORT_SYMBOL(fscrypt_encrypt_pagecache_blocks);\nfs/crypto/crypto.c-216-\n"
} |
| 11/2 | 2026/09/01 03:42 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 20941 output: 28 thoughts: 40 Thoughts: Okay, here's my interpretation of that thought process, summarized as if it were my own: **Diving into Huge Page Management** Right, time to dig into this huge page issue. My initial thought is to go straight to `mm/huge_memory.c`. I know that's where the core functions related to managing huge pages reside. Specifically, I'm interested in understanding how processes interact with the splitting of huge pages. So, I need to investigate `split_huge_pages_pid`. My instinct tells me that function is going to be central to this. I want to see exactly what that function *does*. But beyond that, I also need to understand its context. I need to figure out which other functions are calling `split_huge_pages_pid`, and what else is happening within `mm/huge_memory.c` that might be relevant. It's about building a solid understanding of the ecosystem surrounding the process of splitting a huge page. Context is everything when dealing with memory management at this level. Let's see what the code reveals. |
| 12/2 | 2026/09/01 03:42 | tool | grepper |
0mArgs:{
"Expression": "split_huge_pages_pid",
"PathPrefix": "mm"
}Results: {
"Output": "mm/huge_memory.c=4725=static inline bool vma_not_suitable_for_thp_split(struct vm_area_struct *vma)\n--\nmm/huge_memory.c-4738-\nmm/huge_memory.c:4739:static int split_huge_pages_pid(int pid, unsigned long vaddr_start,\nmm/huge_memory.c-4740-\t\t\t\tunsigned long vaddr_end, unsigned int new_order,\n--\nmm/huge_memory.c=4926=static ssize_t split_huge_pages_write(struct file *file, const char __user *buf,\n--\nmm/huge_memory.c-4992-\nmm/huge_memory.c:4993:\tret = split_huge_pages_pid(pid, vaddr_start, vaddr_end, new_order,\nmm/huge_memory.c-4994-\t\t\tin_folio_offset);\n"
} |
| 13/2 | 2026/09/01 03:42 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 21483 output: 27 thoughts: 22 Thoughts: Here's my summary, as if I were thinking these thoughts: **Diving into the Dirty Folio Logic** Okay, so I need to understand how dirty folios are handled. The place to start, naturally, is `mm/page-writeback.c`. Let's see what's going on within `filemap_dirty_folio`. This is where the core logic for marking a folio as dirty resides, I suspect. I need to refresh my memory on the interactions here, especially around the page cache and writeback processes. It's crucial to understand how that 'dirty' state propagates, how it triggers writeback, and what conditions need to be met. I'll focus on the data structures and locking involved too, of course, the interplay is a subtle and complex area. |
| 14/2 | 2026/09/01 03:42 | tool | grepper |
0mArgs:{
"Expression": "filemap_dirty_folio",
"PathPrefix": "mm"
}Results: {
"Output": "mm/page-writeback.c=2663=void __folio_mark_dirty(struct folio *folio, struct address_space *mapping,\n--\nmm/page-writeback.c-2684-/**\nmm/page-writeback.c:2685: * filemap_dirty_folio - Mark a folio dirty for filesystems which do not use buffer_heads.\nmm/page-writeback.c-2686- * @mapping: Address space this folio belongs to.\n--\nmm/page-writeback.c-2702- */\nmm/page-writeback.c:2703:bool filemap_dirty_folio(struct address_space *mapping, struct folio *folio)\nmm/page-writeback.c-2704-{\n--\nmm/page-writeback.c-2715-}\nmm/page-writeback.c:2716:EXPORT_SYMBOL(filemap_dirty_folio);\nmm/page-writeback.c-2717-\n--\nmm/page-writeback.c=2730=bool folio_redirty_for_writepage(struct writeback_control *wbc,\n--\nmm/page-writeback.c-2737-\twbc-\u003epages_skipped += nr;\nmm/page-writeback.c:2738:\tret = filemap_dirty_folio(mapping, folio);\nmm/page-writeback.c-2739-\tif (mapping \u0026\u0026 mapping_can_writeback(mapping)) {\n"
} |
| 15/2 | 2026/09/01 03:42 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 22078 output: 26 thoughts: 44 Thoughts: Okay, let's dive into this. I need to refresh my memory on the folio migration process. First, I'm going to pull up `mm/migrate.c`. I need to check out the details surrounding `folio_migrate_flags`, and `migrate_folio_unmap`, specifically. I'll need to jog my memory on the context these functions exist within, so I can understand the whole picture. I'll go through the functions within that file, just to be sure I'm up to speed on the related code. That'll get me oriented on how folio migration is handled, and the key components involved. |
| 16/2 | 2026/09/01 03:42 | tool | grepper |
0mArgs:{
"Expression": "folio_migrate_flags",
"PathPrefix": "mm"
}Results: {
"Output": "mm/migrate.c=739=int migrate_huge_page_move_mapping(struct address_space *mapping,\n--\nmm/migrate.c-774- */\nmm/migrate.c:775:void folio_migrate_flags(struct folio *newfolio, struct folio *folio)\nmm/migrate.c-776-{\n--\nmm/migrate.c-862-}\nmm/migrate.c:863:EXPORT_SYMBOL(folio_migrate_flags);\nmm/migrate.c-864-\n--\nmm/migrate.c=869=static int __migrate_folio(struct address_space *mapping, struct folio *dst,\n--\nmm/migrate.c-889-\nmm/migrate.c:890:\tfolio_migrate_flags(dst, src);\nmm/migrate.c-891-\treturn 0;\n--\nmm/migrate_device.c=1109=static void __migrate_device_pages(unsigned long *src_pfns,\n--\nmm/migrate_device.c-1251-\t\t\telse\nmm/migrate_device.c:1252:\t\t\t\tfolio_migrate_flags(newfolio, folio);\nmm/migrate_device.c-1253-\t\t}\n"
} |
| 17/2 | 2026/09/01 03:42 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 22597 output: 28 thoughts: 22 Thoughts: Here's my summary, as though I'm thinking through this process: **Diving into the HugeTLB Implementation** Okay, I need to understand how huge pages are being added to the system. The logical starting point is `mm/hugetlb.c`, specifically the `add_hugetlb_folio` function. I know this function is crucial for, well, adding a folio, which represents a chunk of huge page memory, to the huge page management structures. I need to understand the control flow here - who's calling it, and what's it doing with that folio after it's added. I need to understand memory reservation, and how the physical page is being mapped. Is it being mapped immediately or deferred? And how does it relate to the page table entries for the processes that have access to those pages? Understanding that is the key to understanding how a process will ultimately access huge pages. I'll need to figure out what data structures are being updated here. I'll be looking for references to the `hugetlb_cgroup` and `hugetlb_inode` structures. Are there any locks involved, and if so, what are their implications for concurrency and performance? This is fundamental, I need to know how it works from the inside out to best assess the system as a whole. |
| 18/2 | 2026/09/01 03:42 | tool | grepper |
0mArgs:{
"Expression": "add_hugetlb_folio",
"PathPrefix": "mm"
}Results: {
"Output": "mm/hugetlb.c=1381=void remove_hugetlb_folio(struct hstate *h, struct folio *folio,\n--\nmm/hugetlb.c-1416-\nmm/hugetlb.c:1417:void add_hugetlb_folio(struct hstate *h, struct folio *folio,\nmm/hugetlb.c-1418-\t\t bool adjust_surplus)\n--\nmm/hugetlb.c=1447=static void __update_and_free_hugetlb_folio(struct hstate *h,\n--\nmm/hugetlb.c-1473-\t\t */\nmm/hugetlb.c:1474:\t\tadd_hugetlb_folio(h, folio, true);\nmm/hugetlb.c-1475-\t\tspin_unlock_irq(\u0026hugetlb_lock);\n--\nmm/hugetlb.c=1570=static void bulk_vmemmap_restore_error(struct hstate *h,\n--\nmm/hugetlb.c-1606-\t\t\t\tspin_lock_irq(\u0026hugetlb_lock);\nmm/hugetlb.c:1607:\t\t\t\tadd_hugetlb_folio(h, folio, true);\nmm/hugetlb.c-1608-\t\t\t\tspin_unlock_irq(\u0026hugetlb_lock);\n--\nmm/hugetlb.c=1951=int dissolve_free_hugetlb_folio(struct folio *folio)\n--\nmm/hugetlb.c-2013-\t\t\t\tspin_lock_irq(\u0026hugetlb_lock);\nmm/hugetlb.c:2014:\t\t\t\tadd_hugetlb_folio(h, folio, adjust_surplus);\nmm/hugetlb.c-2015-\t\t\t\th-\u003emax_huge_pages++;\n--\nmm/hugetlb.c=4005=long demote_pool_huge_page(struct hstate *src, nodemask_t *nodes_allowed,\n--\nmm/hugetlb.c-4045-\t\t\tlist_del(\u0026folio-\u003elru);\nmm/hugetlb.c:4046:\t\t\tadd_hugetlb_folio(src, folio, false);\nmm/hugetlb.c-4047-\n--\nmm/hugetlb_internal.h=95=extern void remove_hugetlb_folio(struct hstate *h, struct folio *folio,\nmm/hugetlb_internal.h-96-\t\t\t\t bool adjust_surplus);\nmm/hugetlb_internal.h:97:extern void add_hugetlb_folio(struct hstate *h, struct folio *folio,\nmm/hugetlb_internal.h-98-\t\t\t bool adjust_surplus);\n"
} |
| 19/2 | 2026/09/01 03:42 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 23618 output: 28 thoughts: 20 Thoughts: Here's my summary, as though I'm thinking through this process: **Diving into Page Flag Stability** Okay, so I need to understand how page flags are managed and whether they're, well, stable over time. That suggests I should start by digging into the kernel code that manages these flags. The obvious place to begin is with the core page management in the `fs/proc` filesystem, specifically the `page.c` file. It's a key source for process-related memory information. Let me take a look for the `stable_page_flags` function, and see what the code has to tell me about how these flags are handled, their definition, and any protections applied to them. My focus is the `stable_page_flags` function as a jumping-off point. Hopefully, it will yield important insights into the mechanics of their behaviour. |
| 20/2 | 2026/09/01 03:42 | tool | grepper |
0mArgs:{
"Expression": "stable_page_flags",
"PathPrefix": "fs/proc"
}Results: {
"Output": "fs/proc/page.c=61=static ssize_t kpage_read(struct file *file, char __user *buf,\n--\nfs/proc/page.c-89-\t\t\tcase KPAGE_FLAGS:\nfs/proc/page.c:90:\t\t\t\tinfo = stable_page_flags(page);\nfs/proc/page.c-91-\t\t\t\tbreak;\n--\nfs/proc/page.c=141=static inline u64 kpf_copy_bit(u64 kflags, int ubit, int kbit)\n--\nfs/proc/page.c-145-\nfs/proc/page.c:146:u64 stable_page_flags(const struct page *page)\nfs/proc/page.c-147-{\n--\nfs/proc/page.c-246-}\nfs/proc/page.c:247:EXPORT_SYMBOL_GPL(stable_page_flags);\nfs/proc/page.c-248-\n"
} |
| 21/2 | 2026/09/01 03:42 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 24104 output: 30 thoughts: 302 Thoughts: **My Initial Assessment of Potential Kernel Module Interface Issues** Okay, so I'm diving into this code, trying to get a handle on potential issues around module interfaces. My first thought is to check some well-known areas for potential vulnerabilities or problems related to exported symbols or internal functions that are being used improperly. First, I'm taking a look at `drivers/xen/grant-table.c`. Specifically, I'm checking `gnttab_pages_set_private` and `gnttab_pages_clear_private` to see if they're exported. Yup, there's `EXPORT_SYMBOL_GPL(gnttab_pages_clear_private)` in the diff. Good. It's explicitly exported under the GPL. That's one. Next, I'm going to look at `fs/ceph/addr.c` and specifically at `ceph_dirty_folio`. I need to figure out if it's exported for use elsewhere or if it's declared `static`. Looks like it's a `static bool ceph_dirty_folio(struct address_space *mapping, struct folio *folio)`. Alright, that's not exported, so it should be fine. It is supposed to be internal. Moving on to `drivers/md/md-bitmap.c`, I'm glancing at `static void write_file_page(...)` and `static void free_buffers(...)`. These are `static`, therefore internal, which is good. Finally, I'm turning my attention to `fs/erofs/`. I want to investigate the usage of `erofs_onlinefolio_*` functions. I'm focusing on `erofs_onlinefolio_init`, `erofs_onlinefolio_split`, `erofs_onlinefolio_end`, and `z_erofs_readahead`. I can see that `erofs_onlinefolio_init` is declared in `fs/erofs/internal.h` and used by multiple files, like `fs/erofs/zdata.c` and `fs/erofs/data.c`. It's clearly intended as an internal interface, but I need to dive deeper into how those `erofs_onlinefolio_*` functions are being *used* within the EROFS code to confirm if there are any questionable uses. |
| 22/2 | 2026/09/01 03:42 | tool | grepper |
0mArgs:{
"Expression": "erofs_onlinefolio_",
"PathPrefix": "fs/erofs"
}Results: {
"Output": "fs/erofs/data.c=197=int erofs_map_dev(struct super_block *sb, struct erofs_map_dev *map)\n--\nfs/erofs/data.c-249-\nfs/erofs/data.c:250:void erofs_onlinefolio_init(struct folio *folio)\nfs/erofs/data.c-251-{\n--\nfs/erofs/data.c-260-\nfs/erofs/data.c:261:void erofs_onlinefolio_split(struct folio *folio)\nfs/erofs/data.c-262-{\n--\nfs/erofs/data.c-265-\nfs/erofs/data.c:266:void erofs_onlinefolio_end(struct folio *folio, int err, bool dirty)\nfs/erofs/data.c-267-{\n--\nfs/erofs/fileio.c=22=static void erofs_fileio_ki_complete(struct kiocb *iocb, long ret)\n--\nfs/erofs/fileio.c-32-\t\t\tDBG_BUGON(folio_test_uptodate(fi.folio));\nfs/erofs/fileio.c:33:\t\t\terofs_onlinefolio_end(fi.folio, ret \u003c 0, false);\nfs/erofs/fileio.c-34-\t\t}\n--\nfs/erofs/fileio.c=89=static int erofs_fileio_scan_folio(struct erofs_fileio *io,\n--\nfs/erofs/fileio.c-96-\nfs/erofs/fileio.c:97:\terofs_onlinefolio_init(folio);\nfs/erofs/fileio.c-98-\twhile (cur \u003c end) {\n--\nfs/erofs/fileio.c-147-\t\t\tif (!attached++)\nfs/erofs/fileio.c:148:\t\t\t\terofs_onlinefolio_split(folio);\nfs/erofs/fileio.c-149-\t\t\tio-\u003edev.m_pa += len;\n--\nfs/erofs/fileio.c-152-\t}\nfs/erofs/fileio.c:153:\terofs_onlinefolio_end(folio, err, false);\nfs/erofs/fileio.c-154-\treturn err;\n--\nfs/erofs/fileio.c=198=int erofs_read_meta_folio(struct file *file, struct folio *folio)\n--\nfs/erofs/fileio.c-212-\t\t(io.dev.m_dif-\u003efsoff + io.dev.m_pa) \u003e\u003e 9;\nfs/erofs/fileio.c:213:\terofs_onlinefolio_init(folio);\nfs/erofs/fileio.c-214-\tbio_add_folio_nofail(\u0026io.rq-\u003ebio, folio, folio_size(folio), 0);\n--\nfs/erofs/internal.h=419=int erofs_map_blocks(struct inode *inode, struct erofs_map_blocks *map);\nfs/erofs/internal.h:420:void erofs_onlinefolio_init(struct folio *folio);\nfs/erofs/internal.h:421:void erofs_onlinefolio_split(struct folio *folio);\nfs/erofs/internal.h:422:void erofs_onlinefolio_end(struct folio *folio, int err, bool dirty);\nfs/erofs/internal.h-423-struct inode *erofs_iget(struct super_block *sb, erofs_nid_t nid);\n--\nfs/erofs/zdata.c=1010=static int z_erofs_scan_folio(struct z_erofs_frontend *f,\n--\nfs/erofs/zdata.c-1021-\ttight = (bs == PAGE_SIZE);\nfs/erofs/zdata.c:1022:\terofs_onlinefolio_init(folio);\nfs/erofs/zdata.c-1023-\tdo {\n--\nfs/erofs/zdata.c-1080-\nfs/erofs/zdata.c:1081:\t\t\terofs_onlinefolio_split(folio);\nfs/erofs/zdata.c-1082-\t\t\tif (f-\u003epcl-\u003elength \u003c offset + end - map-\u003em_la) {\n--\nfs/erofs/zdata.c-1097-\t} while ((end = cur) \u003e 0);\nfs/erofs/zdata.c:1098:\terofs_onlinefolio_end(folio, err, false);\nfs/erofs/zdata.c-1099-\treturn err;\n--\nfs/erofs/zdata.c=1153=static void z_erofs_fill_other_copies(struct z_erofs_backend *be, int err)\n--\nfs/erofs/zdata.c-1187-\t\tkunmap_local(dst);\nfs/erofs/zdata.c:1188:\t\terofs_onlinefolio_end(page_folio(bvi-\u003ebvec.page), err, true);\nfs/erofs/zdata.c-1189-\t\tlist_del(p);\n--\nfs/erofs/zdata.c=1254=static int z_erofs_decompress_pcluster(struct z_erofs_backend *be, bool eio)\n--\nfs/erofs/zdata.c-1359-\t\tif (!z_erofs_is_shortlived_page(page)) {\nfs/erofs/zdata.c:1360:\t\t\terofs_onlinefolio_end(page_folio(page), err, true);\nfs/erofs/zdata.c-1361-\t\t\tcontinue;\n"
} |
| 23/2 | 2026/09/01 03:42 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 26386 output: 30 thoughts: 107 Thoughts: **Analyzing Recent Changes in `zsmalloc.c`** Okay, let's dive into this. First, I need to see what's actually been modified within `mm/zsmalloc.c`. The diff mentions these functions: `get_first_zpdesc`, `obj_allocated`, `reset_zpdesc`, and `create_page_chain`. All of them are static, so the change is likely internal to the `zsmalloc` module itself. Interesting that we're seeing internal changes. Also, the removal of `zpdesc_set_first` and `is_first_zpdesc` is curious, especially since they're part of the core data structures' management. This hints at a possible restructuring of how zero-page descriptors are managed or accessed. Now, with this understanding of the *internal* modifications, I need to understand whether these changes have propagated to the *external* interface. Let me now scrutinize the exported functions to see if the removal of internal functions led to any modification of API functions. I need to understand how this internal refactoring impacts the bigger picture. |
| 24/2 | 2026/09/01 03:42 | tool | grepper |
0mArgs:{
"Expression": "EXPORT_SYMBOL",
"PathPrefix": "mm/zsmalloc.c"
}Results: {
"Output": "mm/zsmalloc.c=1109=unsigned int zs_lookup_class_index(struct zs_pool *pool, unsigned int size)\n--\nmm/zsmalloc.c-1116-}\nmm/zsmalloc.c:1117:EXPORT_SYMBOL_GPL(zs_lookup_class_index);\nmm/zsmalloc.c-1118-\nmm/zsmalloc.c=1119=unsigned long zs_get_total_pages(struct zs_pool *pool)\n--\nmm/zsmalloc.c-1122-}\nmm/zsmalloc.c:1123:EXPORT_SYMBOL_GPL(zs_get_total_pages);\nmm/zsmalloc.c-1124-\nmm/zsmalloc.c=1125=void *zs_obj_read_begin(struct zs_pool *pool, unsigned long handle,\n--\nmm/zsmalloc.c-1172-}\nmm/zsmalloc.c:1173:EXPORT_SYMBOL_GPL(zs_obj_read_begin);\nmm/zsmalloc.c-1174-\nmm/zsmalloc.c=1175=void zs_obj_read_end(struct zs_pool *pool, unsigned long handle,\n--\nmm/zsmalloc.c-1199-}\nmm/zsmalloc.c:1200:EXPORT_SYMBOL_GPL(zs_obj_read_end);\nmm/zsmalloc.c-1201-\nmm/zsmalloc.c=1202=void zs_obj_read_sg_begin(struct zs_pool *pool, unsigned long handle,\n--\nmm/zsmalloc.c-1246-}\nmm/zsmalloc.c:1247:EXPORT_SYMBOL_GPL(zs_obj_read_sg_begin);\nmm/zsmalloc.c-1248-\nmm/zsmalloc.c=1249=void zs_obj_read_sg_end(struct zs_pool *pool, unsigned long handle)\n--\nmm/zsmalloc.c-1261-}\nmm/zsmalloc.c:1262:EXPORT_SYMBOL_GPL(zs_obj_read_sg_end);\nmm/zsmalloc.c-1263-\nmm/zsmalloc.c=1264=void zs_obj_write(struct zs_pool *pool, unsigned long handle,\n--\nmm/zsmalloc.c-1310-}\nmm/zsmalloc.c:1311:EXPORT_SYMBOL_GPL(zs_obj_write);\nmm/zsmalloc.c-1312-\n--\nmm/zsmalloc.c=1326=size_t zs_huge_class_size(struct zs_pool *pool)\n--\nmm/zsmalloc.c-1329-}\nmm/zsmalloc.c:1330:EXPORT_SYMBOL_GPL(zs_huge_class_size);\nmm/zsmalloc.c-1331-\n--\nmm/zsmalloc.c=1385=unsigned long zs_malloc(struct zs_pool *pool, size_t size, gfp_t gfp,\n--\nmm/zsmalloc.c-1439-}\nmm/zsmalloc.c:1440:EXPORT_SYMBOL_GPL(zs_malloc);\nmm/zsmalloc.c-1441-\n--\nmm/zsmalloc.c=1527=void zs_free(struct zs_pool *pool, unsigned long handle)\n--\nmm/zsmalloc.c-1562-}\nmm/zsmalloc.c:1563:EXPORT_SYMBOL_GPL(zs_free);\nmm/zsmalloc.c-1564-\n--\nmm/zsmalloc.c=2096=unsigned long zs_compact(struct zs_pool *pool)\n--\nmm/zsmalloc.c-2121-}\nmm/zsmalloc.c:2122:EXPORT_SYMBOL_GPL(zs_compact);\nmm/zsmalloc.c-2123-\nmm/zsmalloc.c=2124=void zs_pool_stats(struct zs_pool *pool, struct zs_pool_stats *stats)\n--\nmm/zsmalloc.c-2127-}\nmm/zsmalloc.c:2128:EXPORT_SYMBOL_GPL(zs_pool_stats);\nmm/zsmalloc.c-2129-\n--\nmm/zsmalloc.c=2217=struct zs_pool *zs_create_pool(const char *name)\n--\nmm/zsmalloc.c-2325-}\nmm/zsmalloc.c:2326:EXPORT_SYMBOL_GPL(zs_create_pool);\nmm/zsmalloc.c-2327-\nmm/zsmalloc.c=2328=void zs_destroy_pool(struct zs_pool *pool)\n--\nmm/zsmalloc.c-2358-}\nmm/zsmalloc.c:2359:EXPORT_SYMBOL_GPL(zs_destroy_pool);\nmm/zsmalloc.c-2360-\n"
} |
| 25/2 | 2026/09/01 03:42 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 28050 output: 30 thoughts: 496 Thoughts: **My Analysis of Potential Focus Symbols for Fuzzing**
Okay, let's get down to brass tacks. I need to figure out which functions are prime candidates for fuzzing, given the rules for FocusSymbols. The goal is to identify kernel functions that will benefit the most from focused fuzzing efforts. I need to avoid generic hot-path functions, as that would skew the test distributions. Instead, I should be looking for non-static, non-inlined API entrypoints. Those are the functions with distinct symbol addresses that are likely to expose interesting edge cases.
First, I'll go through the functions that have been modified or directly impacted. Here's what I've got:
* In `fs/erofs/data.c`, I see `erofs_onlinefolio_init`, `erofs_onlinefolio_end`, and `erofs_onlinefolio_split`. They've been touched and look like good candidates because they are non-static.
* `fscrypt_free_bounce_page` and `fscrypt_encrypt_pagecache_blocks` are in `fs/crypto/crypto.c`. Hmm, those might be interesting.
* `add_hugetlb_folio` in `mm/hugetlb.c`. Worth considering.
* `folio_migrate_flags` in `mm/migrate.c`. Added to the list.
* `filemap_dirty_folio` in `mm/page-writeback.c`. Wait... this one is called constantly during folio dirtying. That *could* be a hot path. I'll need to check the call frequency.
* `gnttab_pages_set_private` and `gnttab_pages_clear_private` in `drivers/xen/grant-table.c`. Need to be looked at.
* `stable_page_flags` in `fs/proc/page.c`.
* And finally, there's `zs_malloc`, `zs_free`, and `zs_compact` in `mm/zsmalloc.c`, since related functions were also updated.
Now, let's critically evaluate those based on the rules. `filemap_dirty_folio` is concerning because it *might* be too hot. Should I include it, or remove it? The `erofs_*` functions seem solid since they're non-static. But what about `add_hugetlb_folio`, `folio_migrate_flags`, `fscrypt_encrypt_pagecache_blocks`, and `fscrypt_free_bounce_page`? They might be good targets.
Next, I need to check the configuration requirements for the modified files. Let's see what Kconfig files govern these components.
* `fs/erofs/` has `EROFS_FS`
I need to check the Kconfig for EROFS...
|
| 26/2 | 2026/09/01 03:42 | tool | grepper |
0mArgs:{
"Expression": "config EROFS_FS",
"PathPrefix": "fs/erofs"
}Results: {
"Output": "fs/erofs/Kconfig-2-\nfs/erofs/Kconfig:3:config EROFS_FS\nfs/erofs/Kconfig-4-\ttristate \"EROFS filesystem support\"\n--\nfs/erofs/Kconfig-49-\nfs/erofs/Kconfig:50:config EROFS_FS_DEBUG\nfs/erofs/Kconfig-51-\tbool \"EROFS debugging feature\"\n--\nfs/erofs/Kconfig-59-\nfs/erofs/Kconfig:60:config EROFS_FS_XATTR\nfs/erofs/Kconfig-61-\tbool \"EROFS extended attributes\"\n--\nfs/erofs/Kconfig-70-\nfs/erofs/Kconfig:71:config EROFS_FS_POSIX_ACL\nfs/erofs/Kconfig-72-\tbool \"EROFS Access Control Lists\"\n--\nfs/erofs/Kconfig-84-\nfs/erofs/Kconfig:85:config EROFS_FS_SECURITY\nfs/erofs/Kconfig-86-\tbool \"EROFS Security Labels\"\n--\nfs/erofs/Kconfig-97-\nfs/erofs/Kconfig:98:config EROFS_FS_BACKED_BY_FILE\nfs/erofs/Kconfig-99-\tbool \"File-backed EROFS filesystem support\"\n--\nfs/erofs/Kconfig-111-\nfs/erofs/Kconfig:112:config EROFS_FS_ZIP\nfs/erofs/Kconfig-113-\tbool \"EROFS Data Compression Support\"\n--\nfs/erofs/Kconfig-121-\nfs/erofs/Kconfig:122:config EROFS_FS_ZIP_LZMA\nfs/erofs/Kconfig-123-\tbool \"EROFS LZMA compressed data support\"\n--\nfs/erofs/Kconfig-133-\nfs/erofs/Kconfig:134:config EROFS_FS_ZIP_LZMA_DEFAULT_MAX_STREAMS\nfs/erofs/Kconfig-135-\tint \"EROFS LZMA default maximum decompression streams\" if SMP\n--\nfs/erofs/Kconfig-150-\nfs/erofs/Kconfig:151:config EROFS_FS_ZIP_DEFLATE\nfs/erofs/Kconfig-152-\tbool \"EROFS DEFLATE compressed data support\"\n--\nfs/erofs/Kconfig-161-\nfs/erofs/Kconfig:162:config EROFS_FS_ZIP_ZSTD\nfs/erofs/Kconfig-163-\tbool \"EROFS Zstandard compressed data support\"\n--\nfs/erofs/Kconfig-172-\nfs/erofs/Kconfig:173:config EROFS_FS_ZIP_ACCEL\nfs/erofs/Kconfig-174-\tbool \"EROFS hardware decompression support\"\n--\nfs/erofs/Kconfig-186-\nfs/erofs/Kconfig:187:config EROFS_FS_PCPU_KTHREAD\nfs/erofs/Kconfig-188-\tbool \"EROFS per-cpu decompression kthread workers\"\n--\nfs/erofs/Kconfig-195-\nfs/erofs/Kconfig:196:config EROFS_FS_PCPU_KTHREAD_HIPRI\nfs/erofs/Kconfig-197-\tbool \"EROFS high priority per-CPU kthread workers\"\n--\nfs/erofs/Kconfig-205-\nfs/erofs/Kconfig:206:config EROFS_FS_PAGE_CACHE_SHARE\nfs/erofs/Kconfig-207-\tbool \"EROFS page cache share support (experimental)\"\n"
} |
| 27/2 | 2026/09/01 03:42 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 30131 output: 32 thoughts: 27 Thoughts: Here's my take on the thought process, as if it were my own: **Investigating the EROFS Build Process** Okay, so I need to figure out which configurations are responsible for compiling `zdata.c` and `data.c` within the EROFS filesystem. My immediate instinct is to dive into the `fs/erofs/Makefile`. That's where all the build magic for that component lives. Hopefully, it's straightforward, and I can quickly identify the dependencies and conditional logic that determine when these specific source files get built. It's usually pretty clear in Makefilesāhopefully this one isn't too convoluted with macros and nested conditionals! Let's see what we find. |
| 28/2 | 2026/09/01 03:43 | tool | read-file |
0mArgs:{
"File": "fs/erofs/Makefile",
"FirstLine": 1,
"LineCount": 20
}Results: {
"Contents": " 1:\t# SPDX-License-Identifier: GPL-2.0-only\n 2:\t\n 3:\tobj-$(CONFIG_EROFS_FS) += erofs.o\n 4:\terofs-objs := super.o inode.o data.o namei.o dir.o sysfs.o\n 5:\terofs-$(CONFIG_EROFS_FS_XATTR) += xattr.o\n 6:\terofs-$(CONFIG_EROFS_FS_ZIP) += decompressor.o zmap.o zdata.o zutil.o\n 7:\terofs-$(CONFIG_EROFS_FS_ZIP_LZMA) += decompressor_lzma.o\n 8:\terofs-$(CONFIG_EROFS_FS_ZIP_DEFLATE) += decompressor_deflate.o\n 9:\terofs-$(CONFIG_EROFS_FS_ZIP_ZSTD) += decompressor_zstd.o\n 10:\terofs-$(CONFIG_EROFS_FS_ZIP_ACCEL) += decompressor_crypto.o\n 11:\terofs-$(CONFIG_EROFS_FS_BACKED_BY_FILE) += fileio.o\n 12:\terofs-$(CONFIG_EROFS_FS_PAGE_CACHE_SHARE) += ishare.o\n"
} |
| 29/2 | 2026/09/01 03:43 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 30666 output: 28 thoughts: 53 Thoughts: **My Initial Thoughts on EROFS and Compression** Okay, so `zdata.c` in this context is being compiled with `CONFIG_EROFS_FS_ZIP` enabled. Interesting, and not unexpected given the context, as the use of compression is fairly specific. Given the configuration, I also know that `CONFIG_EROFS_FS_ZIP` *has* to depend on `EROFS_FS` being enabled, because it's the base filesystem. Now, the next logical step, from an analysis and debugging perspective, or from a development perspective, is to cross reference the Makefile and the Kconfig files. Time to check the crypto directory specifically; let's see what we can find regarding those configuration options and the build process. |
| 30/2 | 2026/09/01 03:43 | tool | grepper |
0mArgs:{
"Expression": "FS_ENCRYPTION",
"PathPrefix": "fs/crypto"
}Results: {
"Output": "fs/crypto/Kconfig-1-# SPDX-License-Identifier: GPL-2.0-only\nfs/crypto/Kconfig:2:config FS_ENCRYPTION\nfs/crypto/Kconfig-3-\tbool \"FS Encryption (Per-file encryption)\"\n--\nfs/crypto/Kconfig-18-\nfs/crypto/Kconfig:19:# Filesystems supporting encryption must select this if FS_ENCRYPTION. This\nfs/crypto/Kconfig-20-# allows the algorithms to be built as modules when all the filesystems are,\nfs/crypto/Kconfig:21:# whereas selecting them from FS_ENCRYPTION would force them to be built-in.\nfs/crypto/Kconfig-22-#\n--\nfs/crypto/Kconfig-30-# strongly recommended to enable optimized implementations too.\nfs/crypto/Kconfig:31:config FS_ENCRYPTION_ALGS\nfs/crypto/Kconfig-32-\ttristate\n--\nfs/crypto/Kconfig-37-\nfs/crypto/Kconfig:38:config FS_ENCRYPTION_INLINE_CRYPT\nfs/crypto/Kconfig-39-\tbool\nfs/crypto/Kconfig:40:\tdefault y if FS_ENCRYPTION \u0026\u0026 BLOCK\n--\nfs/crypto/Makefile-1-# SPDX-License-Identifier: GPL-2.0-only\nfs/crypto/Makefile:2:obj-$(CONFIG_FS_ENCRYPTION)\t+= fscrypto.o\nfs/crypto/Makefile-3-\n--\nfs/crypto/fscrypt_private.h=238=struct fscrypt_prepared_key {\nfs/crypto/fscrypt_private.h-239-\tstruct crypto_sync_skcipher *tfm;\nfs/crypto/fscrypt_private.h:240:#ifdef CONFIG_FS_ENCRYPTION_INLINE_CRYPT\nfs/crypto/fscrypt_private.h-241-\tstruct blk_crypto_key *blk_key;\n--\nfs/crypto/fscrypt_private.h=394=void fscrypt_hkdf_expand(const struct hmac_sha512_key *hkdf, u8 context,\n--\nfs/crypto/fscrypt_private.h-398-/* block.c */\nfs/crypto/fscrypt_private.h:399:#ifdef CONFIG_FS_ENCRYPTION_INLINE_CRYPT\nfs/crypto/fscrypt_private.h-400-static inline bool\n--\nfs/crypto/fscrypt_private.h=425=fscrypt_is_key_prepared(const struct fscrypt_prepared_key *prep_key,\n--\nfs/crypto/fscrypt_private.h-432-\nfs/crypto/fscrypt_private.h:433:#else /* CONFIG_FS_ENCRYPTION_INLINE_CRYPT */\nfs/crypto/fscrypt_private.h-434-\n--\nfs/crypto/fscrypt_private.h=467=fscrypt_is_key_prepared(const struct fscrypt_prepared_key *prep_key,\n--\nfs/crypto/fscrypt_private.h-471-}\nfs/crypto/fscrypt_private.h:472:#endif /* !CONFIG_FS_ENCRYPTION_INLINE_CRYPT */\nfs/crypto/fscrypt_private.h-473-\n"
} |
| 31/2 | 2026/09/01 03:43 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 31729 output: 37 thoughts: 66 Thoughts: **Investigating Zsmalloc Configuration** Okay, let's dive in. I need to understand the configuration behind `zsmalloc`, so the logical first step is to check out `mm/zsmalloc.c`. That's where the magic likely happens. I'm assuming there's a Kconfig option that enables it. It's usually pretty obvious ā let's see if the code itself makes that clear. Right, so to trace that back, I'll need to look through the `Kconfig` files. I know this from experience, as that's where all the build-time configuration settings live. Specifically, I'll need to check `mm/Kconfig`. I'll be looking for the `ZSMALLOC` symbol, and likely checking how it interacts with other related features like `TRANSPARENT_HUGEPAGE`, `MIGRATION` and `HUGETLB_PAGE`, and any dependencies or relationships between them. These things are often intertwined, and understanding the interplay is key. I'll need to quickly understand if `zsmalloc` is a stand-alone feature, or if it is dependent on these or other configurations. |
| 32/2 | 2026/09/01 03:43 | tool | grepper |
0mArgs:{
"Expression": "config ZSMALLOC|config HUGETLB_PAGE|config MIGRATION",
"PathPrefix": "mm"
}Results: {
"Output": "mm/Kconfig=114=config ZSWAP_COMPRESSOR_DEFAULT\n--\nmm/Kconfig-124-\nmm/Kconfig:125:config ZSMALLOC\nmm/Kconfig-126-\ttristate\n--\nmm/Kconfig=131=comment \"Zsmalloc is a common backend allocator for zswap \u0026 zram\"\nmm/Kconfig-132-\nmm/Kconfig:133:config ZSMALLOC_STAT\nmm/Kconfig-134-\tbool \"Export zsmalloc statistics\"\n--\nmm/Kconfig-141-\nmm/Kconfig:142:config ZSMALLOC_CHAIN_SIZE\nmm/Kconfig-143-\tint \"Maximum number of physical pages per-zspage\"\n--\nmm/Kconfig=673=config NUMA_MIGRATION\n--\nmm/Kconfig-683-\nmm/Kconfig:684:config MIGRATION\nmm/Kconfig-685-\tbool\n--\nmm/Kconfig=694=config ARCH_HAS_PMD_SOFTLEAVES\n--\nmm/Kconfig-696-\nmm/Kconfig:697:config HUGETLB_PAGE_SIZE_VARIABLE\nmm/Kconfig-698-\tdef_bool n\n"
} |
| 33/2 | 2026/09/01 03:43 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 32407 output: 27 thoughts: 25 Thoughts: Okay, here's my interpretation of that thought process, assuming I'm deep in the weeds of kernel development and specifically working with huge pages: **Hunting Down the HUGETLB_PAGE Configuration** Alright, time to get to the bottom of this. I need to figure out exactly where the `HUGETLB_PAGE` configuration option is defined. This is a crucial setting, and I need to know precisely where the kernel is pulling its information from. My first instinct, based on experience, is to dig into the `Kconfig` files. That's where all the configuration options are declared and their dependencies are laid out. I have a hunch it's either going to be in `mm/Kconfig` (related to memory management, which makes perfect sense for huge pages) or possibly tucked away in `fs/Kconfig` (file systems, as huge pages *can* have implications there, but it's less likely in my experience). I'll start by checking those two locations. Time to get my hands dirty and find that configuration! |
| 34/2 | 2026/09/01 03:43 | tool | grepper |
0mArgs:{
"Expression": "config HUGETLB_PAGE",
"PathPrefix": "fs"
}Results: {
"Output": "fs/Kconfig=262=if HUGETLBFS\nfs/Kconfig:263:config HUGETLB_PAGE_OPTIMIZE_VMEMMAP_DEFAULT_ON\nfs/Kconfig-264-\tbool \"HugeTLB Vmemmap Optimization (HVO) defaults to on\"\n--\nfs/Kconfig=271=endif # HUGETLBFS\nfs/Kconfig-272-\nfs/Kconfig:273:config HUGETLB_PAGE\nfs/Kconfig-274-\tdef_bool HUGETLBFS\n--\nfs/Kconfig-276-\nfs/Kconfig:277:config HUGETLB_PAGE_OPTIMIZE_VMEMMAP\nfs/Kconfig-278-\tdef_bool HUGETLB_PAGE\n"
} |
| 35/2 | 2026/09/01 03:43 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 32877 output: 18 thoughts: 54 Thoughts: Okay, here's my take on those thoughts, framed as my own: **Investigating Memory Management Options** Alright, so `HUGETLBFS` is naturally tied to `HUGETLB_PAGE`, that's a given. But, I'm starting to think about more holistic memory management, especially within the context of something like `ZSMALLOC`. I'm wondering if using `ZRAM` or potentially even `ZSWAP` could be beneficial alongside it. These compression methods could really amplify the impact, depending on the workload and the types of data that are being handled. So, the next logical step is to dive into the kernel configuration files. I need to poke around the `drivers/block/zram/Kconfig` and `mm/Kconfig` files. I'm looking for clues about how these features interact, dependencies, and if there are any specific configurations that might make this combination optimal, or even supported. I need to understand the relationship between these different memory management tools to assess the impact of this arrangement. |
| 36/2 | 2026/09/01 03:43 | tool | grepper |
0mArgs:{
"Expression": "select ZSMALLOC"
}Results: {
"Output": "drivers/block/zram/Kconfig=2=config ZRAM\n--\ndrivers/block/zram/Kconfig-4-\tdepends on BLOCK \u0026\u0026 SYSFS \u0026\u0026 MMU\ndrivers/block/zram/Kconfig:5:\tselect ZSMALLOC\ndrivers/block/zram/Kconfig-6-\thelp\n--\nmm/Kconfig=22=config ZSWAP\n--\nmm/Kconfig-25-\tselect CRYPTO\nmm/Kconfig:26:\tselect ZSMALLOC\nmm/Kconfig-27-\thelp\n"
} |
| 37/2 | 2026/09/01 03:43 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 33309 output: 29 thoughts: 92 Thoughts: Okay, here's my summary, tailored for an expert audience, presented as my own thought process: **Diving into Memory and Filesystem Optimizations** Right, let's start the deep dive. My initial focus is on memory management, specifically looking at how we're dealing with memory compression and swapping. I'm thinking, "Let's check `ZRAM`, `ZSWAP`, and `ZSMALLOC`." These are the usual suspects when optimizing memory usage in constrained environments, and I want to refresh my understanding of their current configuration and interactions. Then, moving on to the filesystem layer, I want to assess the impact of read-only filesystems. I'll need to check `EROFS_FS` and `EROFS_FS_ZIP`. These are critical for embedded systems. Read-only filesystems can have a significant impact on speed and power consumption. I also want to consider security implications at the file system level. Let's make sure we are not missing anything with `FS_ENCRYPTION`. Now, onto hugetlbfs. I need to refresh my understanding here. I want to check `HUGETLBFS` to see how it is being used. And, I will need to check `TRANSPARENT_HUGEPAGE` for the overall configuration. Finally, I'm going to take a peek at the source. Let's check `mm/huge_memory.c`. I'll be digging into the underlying memory management code for a holistic view of the current configuration. I need to cross-reference my high-level overview with the low-level implementation. |
| 38/2 | 2026/09/01 03:43 | tool | grepper |
0mArgs:{
"Expression": "TRANSPARENT_HUGEPAGE",
"PathPrefix": "mm"
}Results: {
"Output": "\nFull output is too long, showing 500 out of 866 lines.\nUse more precise expression if possible.\n\nmm/Kconfig=816=config PERSISTENT_HUGE_ZERO_FOLIO\nmm/Kconfig-817-\tbool \"Allocate a PMD sized folio for zeroing\"\nmm/Kconfig:818:\tdepends on TRANSPARENT_HUGEPAGE\nmm/Kconfig-819-\thelp\n--\nmm/Kconfig=832=config MM_ID\n--\nmm/Kconfig-834-\nmm/Kconfig:835:menuconfig TRANSPARENT_HUGEPAGE\nmm/Kconfig-836-\tbool \"Transparent Hugepage Support\"\nmm/Kconfig:837:\tdepends on HAVE_ARCH_TRANSPARENT_HUGEPAGE \u0026\u0026 !PREEMPT_RT\nmm/Kconfig-838-\tselect COMPACTION\n--\nmm/Kconfig-850-\nmm/Kconfig:851:if TRANSPARENT_HUGEPAGE\nmm/Kconfig-852-\nmm/Kconfig=853=choice\nmm/Kconfig-854-\tprompt \"Transparent Hugepage Support sysfs defaults\"\nmm/Kconfig:855:\tdefault TRANSPARENT_HUGEPAGE_ALWAYS\nmm/Kconfig-856-\thelp\n--\nmm/Kconfig-858-\nmm/Kconfig:859:\tconfig TRANSPARENT_HUGEPAGE_ALWAYS\nmm/Kconfig-860-\t\tbool \"always\"\n--\nmm/Kconfig-865-\nmm/Kconfig:866:\tconfig TRANSPARENT_HUGEPAGE_MADVISE\nmm/Kconfig-867-\t\tbool \"madvise\"\n--\nmm/Kconfig-874-\nmm/Kconfig:875:\tconfig TRANSPARENT_HUGEPAGE_NEVER\nmm/Kconfig-876-\t\tbool \"never\"\n--\nmm/Kconfig=882=choice\nmm/Kconfig-883-\tprompt \"Shmem hugepage allocation defaults\"\nmm/Kconfig:884:\tdefault TRANSPARENT_HUGEPAGE_SHMEM_HUGE_NEVER\nmm/Kconfig-885-\thelp\n--\nmm/Kconfig-891-\nmm/Kconfig:892:\tconfig TRANSPARENT_HUGEPAGE_SHMEM_HUGE_NEVER\nmm/Kconfig-893-\t\tbool \"never\"\n--\nmm/Kconfig-901-\nmm/Kconfig:902:\tconfig TRANSPARENT_HUGEPAGE_SHMEM_HUGE_ALWAYS\nmm/Kconfig-903-\t\tbool \"always\"\n--\nmm/Kconfig-909-\nmm/Kconfig:910:\tconfig TRANSPARENT_HUGEPAGE_SHMEM_HUGE_WITHIN_SIZE\nmm/Kconfig-911-\t\tbool \"within_size\"\n--\nmm/Kconfig-917-\nmm/Kconfig:918:\tconfig TRANSPARENT_HUGEPAGE_SHMEM_HUGE_ADVISE\nmm/Kconfig-919-\t\tbool \"advise\"\n--\nmm/Kconfig=927=choice\nmm/Kconfig-928-\tprompt \"Tmpfs hugepage allocation defaults\"\nmm/Kconfig:929:\tdefault TRANSPARENT_HUGEPAGE_TMPFS_HUGE_NEVER\nmm/Kconfig-930-\thelp\n--\nmm/Kconfig-936-\nmm/Kconfig:937:\tconfig TRANSPARENT_HUGEPAGE_TMPFS_HUGE_NEVER\nmm/Kconfig-938-\t\tbool \"never\"\n--\nmm/Kconfig-945-\nmm/Kconfig:946:\tconfig TRANSPARENT_HUGEPAGE_TMPFS_HUGE_ALWAYS\nmm/Kconfig-947-\t\tbool \"always\"\n--\nmm/Kconfig-953-\nmm/Kconfig:954:\tconfig TRANSPARENT_HUGEPAGE_TMPFS_HUGE_WITHIN_SIZE\nmm/Kconfig-955-\t\tbool \"within_size\"\n--\nmm/Kconfig-961-\nmm/Kconfig:962:\tconfig TRANSPARENT_HUGEPAGE_TMPFS_HUGE_ADVISE\nmm/Kconfig-963-\t\tbool \"advise\"\n--\nmm/Kconfig=981=config NO_PAGE_MAPCOUNT\n--\nmm/Kconfig-993-\nmm/Kconfig:994:endif # TRANSPARENT_HUGEPAGE\nmm/Kconfig-995-\n--\nmm/Kconfig=1003=config PGTABLE_HAS_HUGE_LEAVES\nmm/Kconfig:1004:\tdef_bool TRANSPARENT_HUGEPAGE || HUGETLB_PAGE\nmm/Kconfig-1005-\n--\nmm/Kconfig=1009=config HAVE_GIGANTIC_FOLIOS\nmm/Kconfig-1010-\tdef_bool (HUGETLB_PAGE \u0026\u0026 ARCH_HAS_GIGANTIC_PAGE) || \\\nmm/Kconfig:1011:\t\t (ZONE_DEVICE \u0026\u0026 HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD)\nmm/Kconfig-1012-\n--\nmm/Kconfig=1017=config ARCH_SUPPORTS_HUGE_PFNMAP\nmm/Kconfig-1018-\tdef_bool n\nmm/Kconfig:1019:\tdepends on TRANSPARENT_HUGEPAGE\nmm/Kconfig-1020-\nmm/Kconfig=1021=config ARCH_SUPPORTS_PMD_PFNMAP\nmm/Kconfig-1022-\tdef_bool y\nmm/Kconfig:1023:\tdepends on ARCH_SUPPORTS_HUGE_PFNMAP \u0026\u0026 HAVE_ARCH_TRANSPARENT_HUGEPAGE\nmm/Kconfig-1024-\nmm/Kconfig=1025=config ARCH_SUPPORTS_PUD_PFNMAP\nmm/Kconfig-1026-\tdef_bool y\nmm/Kconfig:1027:\tdepends on ARCH_SUPPORTS_HUGE_PFNMAP \u0026\u0026 HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD\nmm/Kconfig-1028-\n--\nmm/Makefile=100=obj-$(CONFIG_DEVICE_MIGRATION) += migrate_device.o\nmm/Makefile:101:obj-$(CONFIG_TRANSPARENT_HUGEPAGE) += huge_memory.o khugepaged.o\nmm/Makefile-102-obj-$(CONFIG_PAGE_COUNTER) += page_counter.o\n--\nmm/compaction.c=60=static inline bool is_via_compact_memory(int order) { return false; }\n--\nmm/compaction.c-75- */\nmm/compaction.c:76:#if defined CONFIG_TRANSPARENT_HUGEPAGE\nmm/compaction.c-77-#define COMPACTION_HPAGE_ORDER\tHPAGE_PMD_ORDER\n--\nmm/damon/ops-common.c=73=void damon_pmdp_mkold(pmd_t *pmd, struct vm_area_struct *vma, unsigned long addr)\nmm/damon/ops-common.c-74-{\nmm/damon/ops-common.c:75:#ifdef CONFIG_TRANSPARENT_HUGEPAGE\nmm/damon/ops-common.c-76-\tpmd_t pmdval = pmdp_get(pmd);\n--\nmm/damon/ops-common.c-97-\tfolio_put(folio);\nmm/damon/ops-common.c:98:#endif /* CONFIG_TRANSPARENT_HUGEPAGE */\nmm/damon/ops-common.c-99-}\n--\nmm/damon/ops-common.c=194=static bool damon_folio_young_one(struct folio *folio,\n--\nmm/damon/ops-common.c-215-\t\t} else {\nmm/damon/ops-common.c:216:#ifdef CONFIG_TRANSPARENT_HUGEPAGE\nmm/damon/ops-common.c-217-\t\t\tpmd_t pmd = pmdp_get(pvmw.pmd);\n--\nmm/damon/ops-common.c-223-\t\t\tWARN_ON_ONCE(1);\nmm/damon/ops-common.c:224:#endif\t/* CONFIG_TRANSPARENT_HUGEPAGE */\nmm/damon/ops-common.c-225-\t\t}\n--\nmm/damon/vaddr.c=389=static int damon_young_pmd_entry(pmd_t *pmd, unsigned long addr,\n--\nmm/damon/vaddr.c-397-\nmm/damon/vaddr.c:398:#ifdef CONFIG_TRANSPARENT_HUGEPAGE\nmm/damon/vaddr.c-399-\tptl = pmd_trans_huge_lock(pmd, walk-\u003evma);\n--\nmm/damon/vaddr.c-415-\t}\nmm/damon/vaddr.c:416:#endif\t/* CONFIG_TRANSPARENT_HUGEPAGE */\nmm/damon/vaddr.c-417-\n--\nmm/damon/vaddr.c=635=static int damos_va_migrate_pmd_entry(pmd_t *pmd, unsigned long addr,\n--\nmm/damon/vaddr.c-646-\nmm/damon/vaddr.c:647:#ifdef CONFIG_TRANSPARENT_HUGEPAGE\nmm/damon/vaddr.c-648-\tptl = pmd_trans_huge_lock(pmd, walk-\u003evma);\n--\nmm/damon/vaddr.c-664-\t}\nmm/damon/vaddr.c:665:#endif\t/* CONFIG_TRANSPARENT_HUGEPAGE */\nmm/damon/vaddr.c-666-\n--\nmm/damon/vaddr.c=795=static int damos_va_stat_pmd_entry(pmd_t *pmd, unsigned long addr,\n--\nmm/damon/vaddr.c-806-\nmm/damon/vaddr.c:807:#ifdef CONFIG_TRANSPARENT_HUGEPAGE\nmm/damon/vaddr.c-808-\tptl = pmd_trans_huge_lock(pmd, vma);\n--\nmm/debug_vm_pgtable.c=114=static void __init pte_advanced_tests(struct pgtable_debug_args *args)\n--\nmm/debug_vm_pgtable.c-172-\nmm/debug_vm_pgtable.c:173:#ifdef CONFIG_TRANSPARENT_HUGEPAGE\nmm/debug_vm_pgtable.c-174-static void __init pmd_basic_tests(struct pgtable_debug_args *args, int idx)\n--\nmm/debug_vm_pgtable.c=282=static void __init pmd_leaf_tests(struct pgtable_debug_args *args)\n--\nmm/debug_vm_pgtable.c-298-\nmm/debug_vm_pgtable.c:299:#ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD\nmm/debug_vm_pgtable.c-300-static void __init pud_basic_tests(struct pgtable_debug_args *args, int idx)\n--\nmm/debug_vm_pgtable.c=405=static void __init pud_leaf_tests(struct pgtable_debug_args *args)\n--\nmm/debug_vm_pgtable.c-419-}\nmm/debug_vm_pgtable.c:420:#else /* !CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD */\nmm/debug_vm_pgtable.c-421-static void __init pud_basic_tests(struct pgtable_debug_args *args, int idx) { }\n--\nmm/debug_vm_pgtable.c=423=static void __init pud_leaf_tests(struct pgtable_debug_args *args) { }\nmm/debug_vm_pgtable.c:424:#endif /* CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD */\nmm/debug_vm_pgtable.c:425:#else /* !CONFIG_TRANSPARENT_HUGEPAGE */\nmm/debug_vm_pgtable.c-426-static void __init pmd_basic_tests(struct pgtable_debug_args *args, int idx) { }\n--\nmm/debug_vm_pgtable.c=431=static void __init pud_leaf_tests(struct pgtable_debug_args *args) { }\nmm/debug_vm_pgtable.c:432:#endif /* CONFIG_TRANSPARENT_HUGEPAGE */\nmm/debug_vm_pgtable.c-433-\n--\nmm/debug_vm_pgtable.c=671=static void __init pte_protnone_tests(struct pgtable_debug_args *args)\n--\nmm/debug_vm_pgtable.c-682-\nmm/debug_vm_pgtable.c:683:#ifdef CONFIG_TRANSPARENT_HUGEPAGE\nmm/debug_vm_pgtable.c-684-static void __init pmd_protnone_tests(struct pgtable_debug_args *args)\n--\nmm/debug_vm_pgtable.c-698-}\nmm/debug_vm_pgtable.c:699:#else /* !CONFIG_TRANSPARENT_HUGEPAGE */\nmm/debug_vm_pgtable.c-700-static void __init pmd_protnone_tests(struct pgtable_debug_args *args) { }\nmm/debug_vm_pgtable.c:701:#endif /* CONFIG_TRANSPARENT_HUGEPAGE */\nmm/debug_vm_pgtable.c-702-\n--\nmm/debug_vm_pgtable.c=715=static void __init pte_swap_soft_dirty_tests(struct pgtable_debug_args *args)\n--\nmm/debug_vm_pgtable.c-731-\nmm/debug_vm_pgtable.c:732:#ifdef CONFIG_TRANSPARENT_HUGEPAGE\nmm/debug_vm_pgtable.c-733-static void __init pmd_soft_dirty_tests(struct pgtable_debug_args *args)\n--\nmm/debug_vm_pgtable.c=749=static void __init pmd_leaf_soft_dirty_tests(struct pgtable_debug_args *args)\n--\nmm/debug_vm_pgtable.c-767-}\nmm/debug_vm_pgtable.c:768:#else /* !CONFIG_TRANSPARENT_HUGEPAGE */\nmm/debug_vm_pgtable.c-769-static void __init pmd_soft_dirty_tests(struct pgtable_debug_args *args) { }\nmm/debug_vm_pgtable.c=770=static void __init pmd_leaf_soft_dirty_tests(struct pgtable_debug_args *args) { }\nmm/debug_vm_pgtable.c:771:#endif /* CONFIG_TRANSPARENT_HUGEPAGE */\nmm/debug_vm_pgtable.c-772-\n--\nmm/debug_vm_pgtable.c=901=static void __init hugetlb_basic_tests(struct pgtable_debug_args *args) { }\n--\nmm/debug_vm_pgtable.c-903-\nmm/debug_vm_pgtable.c:904:#ifdef CONFIG_TRANSPARENT_HUGEPAGE\nmm/debug_vm_pgtable.c-905-static void __init pmd_thp_tests(struct pgtable_debug_args *args)\n--\nmm/debug_vm_pgtable.c-933-\nmm/debug_vm_pgtable.c:934:#ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD\nmm/debug_vm_pgtable.c-935-static void __init pud_thp_tests(struct pgtable_debug_args *args)\n--\nmm/debug_vm_pgtable.c-953-}\nmm/debug_vm_pgtable.c:954:#else /* !CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD */\nmm/debug_vm_pgtable.c-955-static void __init pud_thp_tests(struct pgtable_debug_args *args) { }\nmm/debug_vm_pgtable.c:956:#endif /* CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD */\nmm/debug_vm_pgtable.c:957:#else /* !CONFIG_TRANSPARENT_HUGEPAGE */\nmm/debug_vm_pgtable.c-958-static void __init pmd_thp_tests(struct pgtable_debug_args *args) { }\nmm/debug_vm_pgtable.c=959=static void __init pud_thp_tests(struct pgtable_debug_args *args) { }\nmm/debug_vm_pgtable.c:960:#endif /* CONFIG_TRANSPARENT_HUGEPAGE */\nmm/debug_vm_pgtable.c-961-\n--\nmm/debug_vm_pgtable.c=987=static void __init destroy_args(struct pgtable_debug_args *args)\n--\nmm/debug_vm_pgtable.c-989-\t/* Free (huge) page */\nmm/debug_vm_pgtable.c:990:\tif (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) \u0026\u0026\nmm/debug_vm_pgtable.c-991-\t has_transparent_pud_hugepage() \u0026\u0026\n--\nmm/debug_vm_pgtable.c-998-\nmm/debug_vm_pgtable.c:999:\tif (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) \u0026\u0026\nmm/debug_vm_pgtable.c-1000-\t has_transparent_hugepage() \u0026\u0026\n--\nmm/debug_vm_pgtable.c=1143=static int __init init_args(struct pgtable_debug_args *args)\n--\nmm/debug_vm_pgtable.c-1239-\t */\nmm/debug_vm_pgtable.c:1240:\tif (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) \u0026\u0026\nmm/debug_vm_pgtable.c-1241-\t has_transparent_pud_hugepage()) {\n--\nmm/debug_vm_pgtable.c-1250-\nmm/debug_vm_pgtable.c:1251:\tif (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) \u0026\u0026\nmm/debug_vm_pgtable.c-1252-\t has_transparent_hugepage()) {\n--\nmm/filemap.c=3329=static struct file *do_sync_mmap_readahead(struct vm_fault *vmf)\n--\nmm/filemap.c-3341-\t/* Use the readahead code, even if readahead is disabled */\nmm/filemap.c:3342:\tif (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) \u0026\u0026 (vm_flags \u0026 VM_HUGEPAGE)) {\nmm/filemap.c-3343-\t\t/*\n--\nmm/gup.c=701=static struct page *follow_huge_pmd(struct vm_area_struct *vma,\n--\nmm/gup.c-734-\nmm/gup.c:735:#ifdef CONFIG_TRANSPARENT_HUGEPAGE\nmm/gup.c-736-\tif (pmd_trans_huge(pmdval) \u0026\u0026 (flags \u0026 FOLL_TOUCH))\nmm/gup.c-737-\t\ttouch_pmd(vma, addr, pmd, flags \u0026 FOLL_WRITE);\nmm/gup.c:738:#endif\t/* CONFIG_TRANSPARENT_HUGEPAGE */\nmm/gup.c-739-\n--\nmm/hmm.c=188=static inline unsigned long hmm_pfn_flags_order(unsigned long order)\n--\nmm/hmm.c-192-\nmm/hmm.c:193:#ifdef CONFIG_TRANSPARENT_HUGEPAGE\nmm/hmm.c-194-static inline unsigned long pmd_to_hmm_pfn_flags(struct hmm_range *range,\n--\nmm/hmm.c=204=static int hmm_vma_handle_pmd(struct mm_walk *walk, unsigned long addr,\n--\nmm/hmm.c-227-}\nmm/hmm.c:228:#else /* CONFIG_TRANSPARENT_HUGEPAGE */\nmm/hmm.c-229-/* stub to allow the code below to compile */\nmm/hmm.c=230=int hmm_vma_handle_pmd(struct mm_walk *walk, unsigned long addr,\nmm/hmm.c-231-\t\tunsigned long end, unsigned long hmm_pfns[], pmd_t pmd);\nmm/hmm.c:232:#endif /* CONFIG_TRANSPARENT_HUGEPAGE */\nmm/hmm.c-233-\n--\nmm/hmm.c=403=static int hmm_vma_walk_pmd(pmd_t *pmdp,\n--\nmm/hmm.c-479-\nmm/hmm.c:480:#if defined(CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD)\nmm/hmm.c-481-static inline unsigned long pud_to_hmm_pfn_flags(struct hmm_range *range,\n--\nmm/huge_memory.c=61=unsigned long transparent_hugepage_flags __read_mostly =\nmm/huge_memory.c:62:#ifdef CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS\nmm/huge_memory.c:63:\t(1\u003c\u003cTRANSPARENT_HUGEPAGE_FLAG)|\nmm/huge_memory.c-64-#endif\nmm/huge_memory.c:65:#ifdef CONFIG_TRANSPARENT_HUGEPAGE_MADVISE\nmm/huge_memory.c:66:\t(1\u003c\u003cTRANSPARENT_HUGEPAGE_REQ_MADV_FLAG)|\nmm/huge_memory.c-67-#endif\nmm/huge_memory.c:68:\t(1\u003c\u003cTRANSPARENT_HUGEPAGE_DEFRAG_REQ_MADV_FLAG)|\nmm/huge_memory.c:69:\t(1\u003c\u003cTRANSPARENT_HUGEPAGE_DEFRAG_KHUGEPAGED_FLAG)|\nmm/huge_memory.c:70:\t(1\u003c\u003cTRANSPARENT_HUGEPAGE_USE_ZERO_PAGE_FLAG);\nmm/huge_memory.c-71-\n--\nmm/huge_memory.c=382=static ssize_t enabled_show(struct kobject *kobj,\n--\nmm/huge_memory.c-386-\nmm/huge_memory.c:387:\tif (test_bit(TRANSPARENT_HUGEPAGE_FLAG, \u0026transparent_hugepage_flags))\nmm/huge_memory.c-388-\t\toutput = \"[always] madvise never\";\nmm/huge_memory.c:389:\telse if (test_bit(TRANSPARENT_HUGEPAGE_REQ_MADV_FLAG,\nmm/huge_memory.c-390-\t\t\t \u0026transparent_hugepage_flags))\n--\nmm/huge_memory.c=424=static bool set_global_enabled_mode(enum global_enabled_mode mode)\n--\nmm/huge_memory.c-426-\tstatic const unsigned long thp_flags[] = {\nmm/huge_memory.c:427:\t\tTRANSPARENT_HUGEPAGE_FLAG,\nmm/huge_memory.c:428:\t\tTRANSPARENT_HUGEPAGE_REQ_MADV_FLAG,\nmm/huge_memory.c-429-\t};\n--\nmm/huge_memory.c=519=static const enum transparent_hugepage_flag defrag_flags[] = {\nmm/huge_memory.c:520:\t[DEFRAG_ALWAYS]\t\t= TRANSPARENT_HUGEPAGE_DEFRAG_DIRECT_FLAG,\nmm/huge_memory.c:521:\t[DEFRAG_DEFER]\t\t= TRANSPARENT_HUGEPAGE_DEFRAG_KSWAPD_FLAG,\nmm/huge_memory.c:522:\t[DEFRAG_DEFER_MADVISE]\t= TRANSPARENT_HUGEPAGE_DEFRAG_KSWAPD_OR_MADV_FLAG,\nmm/huge_memory.c:523:\t[DEFRAG_MADVISE]\t= TRANSPARENT_HUGEPAGE_DEFRAG_REQ_MADV_FLAG,\nmm/huge_memory.c-524-};\n--\nmm/huge_memory.c=576=static ssize_t use_zero_page_show(struct kobject *kobj,\n--\nmm/huge_memory.c-579-\treturn single_hugepage_flag_show(kobj, attr, buf,\nmm/huge_memory.c:580:\t\t\t\t\t TRANSPARENT_HUGEPAGE_USE_ZERO_PAGE_FLAG);\nmm/huge_memory.c-581-}\nmm/huge_memory.c=582=static ssize_t use_zero_page_store(struct kobject *kobj,\n--\nmm/huge_memory.c-585-\treturn single_hugepage_flag_store(kobj, attr, buf, count,\nmm/huge_memory.c:586:\t\t\t\t TRANSPARENT_HUGEPAGE_USE_ZERO_PAGE_FLAG);\nmm/huge_memory.c-587-}\n--\nmm/huge_memory.c=1051=static int __init hugepage_init(void)\n--\nmm/huge_memory.c-1056-\tif (!has_transparent_hugepage()) {\nmm/huge_memory.c:1057:\t\ttransparent_hugepage_flags = 1 \u003c\u003c TRANSPARENT_HUGEPAGE_UNSUPPORTED;\nmm/huge_memory.c-1058-\t\treturn -EINVAL;\n--\nmm/huge_memory.c=1104=static int __init setup_transparent_hugepage(char *str)\n--\nmm/huge_memory.c-1109-\tif (!strcmp(str, \"always\")) {\nmm/huge_memory.c:1110:\t\tset_bit(TRANSPARENT_HUGEPAGE_FLAG,\nmm/huge_memory.c-1111-\t\t\t\u0026transparent_hugepage_flags);\nmm/huge_memory.c:1112:\t\tclear_bit(TRANSPARENT_HUGEPAGE_REQ_MADV_FLAG,\nmm/huge_memory.c-1113-\t\t\t \u0026transparent_hugepage_flags);\n--\nmm/huge_memory.c-1115-\t} else if (!strcmp(str, \"madvise\")) {\nmm/huge_memory.c:1116:\t\tclear_bit(TRANSPARENT_HUGEPAGE_FLAG,\nmm/huge_memory.c-1117-\t\t\t \u0026transparent_hugepage_flags);\nmm/huge_memory.c:1118:\t\tset_bit(TRANSPARENT_HUGEPAGE_REQ_MADV_FLAG,\nmm/huge_memory.c-1119-\t\t\t\u0026transparent_hugepage_flags);\n--\nmm/huge_memory.c-1121-\t} else if (!strcmp(str, \"never\")) {\nmm/huge_memory.c:1122:\t\tclear_bit(TRANSPARENT_HUGEPAGE_FLAG,\nmm/huge_memory.c-1123-\t\t\t \u0026transparent_hugepage_flags);\nmm/huge_memory.c:1124:\t\tclear_bit(TRANSPARENT_HUGEPAGE_REQ_MADV_FLAG,\nmm/huge_memory.c-1125-\t\t\t \u0026transparent_hugepage_flags);\n--\nmm/huge_memory.c=1481=gfp_t vma_thp_gfp_mask(struct vm_area_struct *vma)\n--\nmm/huge_memory.c-1485-\t/* Always do synchronous compaction */\nmm/huge_memory.c:1486:\tif (test_bit(TRANSPARENT_HUGEPAGE_DEFRAG_DIRECT_FLAG, \u0026transparent_hugepage_flags))\nmm/huge_memory.c-1487-\t\treturn GFP_TRANSHUGE | (vma_madvised ? 0 : __GFP_NORETRY);\n--\nmm/huge_memory.c-1489-\t/* Kick kcompactd and fail quickly */\nmm/huge_memory.c:1490:\tif (test_bit(TRANSPARENT_HUGEPAGE_DEFRAG_KSWAPD_FLAG, \u0026transparent_hugepage_flags))\nmm/huge_memory.c-1491-\t\treturn GFP_TRANSHUGE_LIGHT | __GFP_KSWAPD_RECLAIM;\n--\nmm/huge_memory.c-1493-\t/* Synchronous compaction if madvised, otherwise kick kcompactd */\nmm/huge_memory.c:1494:\tif (test_bit(TRANSPARENT_HUGEPAGE_DEFRAG_KSWAPD_OR_MADV_FLAG, \u0026transparent_hugepage_flags))\nmm/huge_memory.c-1495-\t\treturn GFP_TRANSHUGE_LIGHT |\n--\nmm/huge_memory.c-1499-\t/* Only do synchronous compaction if madvised */\nmm/huge_memory.c:1500:\tif (test_bit(TRANSPARENT_HUGEPAGE_DEFRAG_REQ_MADV_FLAG, \u0026transparent_hugepage_flags))\nmm/huge_memory.c-1501-\t\treturn GFP_TRANSHUGE_LIGHT |\n--\nmm/huge_memory.c=1707=EXPORT_SYMBOL_GPL(vmf_insert_folio_pmd);\nmm/huge_memory.c-1708-\nmm/huge_memory.c:1709:#ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD\nmm/huge_memory.c-1710-static pud_t maybe_pud_mkwrite(pud_t pud, struct vm_area_struct *vma)\n--\nmm/huge_memory.c=1823=EXPORT_SYMBOL_GPL(vmf_insert_folio_pud);\nmm/huge_memory.c:1824:#endif /* CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD */\nmm/huge_memory.c-1825-\n--\nmm/huge_memory.c=1908=int copy_huge_pmd(struct mm_struct *dst_mm, struct mm_struct *src_mm,\n--\nmm/huge_memory.c-2019-\nmm/huge_memory.c:2020:#ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD\nmm/huge_memory.c-2021-void touch_pud(struct vm_area_struct *vma, unsigned long addr,\n--\nmm/huge_memory.c=2069=void huge_pud_set_accessed(struct vm_fault *vmf, pud_t orig_pud)\n--\nmm/huge_memory.c-2080-}\nmm/huge_memory.c:2081:#endif /* CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD */\nmm/huge_memory.c-2082-\n--\nmm/huge_memory.c=2690=int change_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma,\n--\nmm/huge_memory.c-2797- */\nmm/huge_memory.c:2798:#ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD\nmm/huge_memory.c-2799-int change_huge_pud(struct mmu_gather *tlb, struct vm_area_struct *vma,\n--\nmm/huge_memory.c=2989=spinlock_t *__pud_trans_huge_lock(pud_t *pud, struct vm_area_struct *vma)\n--\nmm/huge_memory.c-2999-\nmm/huge_memory.c:3000:#ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD\nmm/huge_memory.c-3001-int zap_huge_pud(struct mmu_gather *tlb, struct vm_area_struct *vma,\n--\nmm/huge_memory.c=3088=void __split_huge_pud(struct vm_area_struct *vma, pud_t *pud,\n--\nmm/huge_memory.c-3091-}\nmm/huge_memory.c:3092:#endif /* CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD */\nmm/huge_memory.c-3093-\n--\nmm/khugepaged.c=232=static ssize_t defrag_show(struct kobject *kobj,\n--\nmm/khugepaged.c-235-\treturn single_hugepage_flag_show(kobj, attr, buf,\nmm/khugepaged.c:236:\t\t\t\t\t TRANSPARENT_HUGEPAGE_DEFRAG_KHUGEPAGED_FLAG);\nmm/khugepaged.c-237-}\nmm/khugepaged.c=238=static ssize_t defrag_store(struct kobject *kobj,\n--\nmm/khugepaged.c-242-\treturn single_hugepage_flag_store(kobj, attr, buf, count,\nmm/khugepaged.c:243:\t\t\t\t TRANSPARENT_HUGEPAGE_DEFRAG_KHUGEPAGED_FLAG);\nmm/khugepaged.c-244-}\n--\nmm/khugepaged.c=1004=static bool collapse_scan_abort(int nid, struct collapse_control *cc)\n--\nmm/khugepaged.c-1029-\t(transparent_hugepage_flags \u0026\t\t\t\t\\\nmm/khugepaged.c:1030:\t (1\u003c\u003cTRANSPARENT_HUGEPAGE_DEFRAG_KHUGEPAGED_FLAG))\nmm/khugepaged.c-1031-\n--\nmm/ksm.c=2527=static int ksm_next_page_pmd_entry(pmd_t *pmdp, unsigned long addr, unsigned long end,\n--\nmm/ksm.c-2547-\nmm/ksm.c:2548:\tif (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) \u0026\u0026 pmd_leaf(pmd)) {\nmm/ksm.c-2549-\t\tptl = pmd_lock(mm, pmdp);\n--\nmm/madvise.c=354=static int madvise_cold_or_pageout_pte_range(pmd_t *pmd,\n--\nmm/madvise.c-376-\nmm/madvise.c:377:#ifdef CONFIG_TRANSPARENT_HUGEPAGE\nmm/madvise.c-378-\tif (pmd_trans_huge(*pmd)) {\n--\nmm/madvise.c=1519=madvise_behavior_valid(int behavior)\n--\nmm/madvise.c-1539-#endif\nmm/madvise.c:1540:#ifdef CONFIG_TRANSPARENT_HUGEPAGE\nmm/madvise.c-1541-\tcase MADV_HUGEPAGE:\n--\nmm/mapping_dirty_helpers.c=148=static int wp_clean_pud_entry(pud_t *pud, unsigned long addr, unsigned long end,\n--\nmm/mapping_dirty_helpers.c-150-{\nmm/mapping_dirty_helpers.c:151:#ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD\nmm/mapping_dirty_helpers.c-152-\tpud_t pudval = pudp_get(pud);\n--\nmm/memcontrol-v1.c=2165=static const unsigned int memcg1_stats[] = {\n--\nmm/memcontrol-v1.c-2167-\tNR_ANON_MAPPED,\nmm/memcontrol-v1.c:2168:#ifdef CONFIG_TRANSPARENT_HUGEPAGE\nmm/memcontrol-v1.c-2169-\tNR_ANON_THPS,\n--\nmm/memcontrol-v1.c=2183=static const char *const memcg1_stat_names[] = {\n--\nmm/memcontrol-v1.c-2185-\t\"rss\",\nmm/memcontrol-v1.c:2186:#ifdef CONFIG_TRANSPARENT_HUGEPAGE\nmm/memcontrol-v1.c-2187-\t\"rss_huge\",\n--\nmm/memcontrol.c=598=static const unsigned int memcg_vm_event_stat[] = {\n--\nmm/memcontrol.c-619-#endif\nmm/memcontrol.c:620:#ifdef CONFIG_TRANSPARENT_HUGEPAGE\nmm/memcontrol.c-621-\tTHP_FAULT_ALLOC,\n--\nmm/memcontrol.c=1591=static const struct memory_stat memory_stats[] = {\n--\nmm/memcontrol.c-1612-#endif\nmm/memcontrol.c:1613:#ifdef CONFIG_TRANSPARENT_HUGEPAGE\nmm/memcontrol.c-1614-\t{ \"anon_thp\",\t\t\tNR_ANON_THPS\t\t\t},\n--\nmm/memory-failure.c=689=static int check_hwpoisoned_entry(pte_t pte, unsigned long addr, short shift,\n--\nmm/memory-failure.c-713-\nmm/memory-failure.c:714:#ifdef CONFIG_TRANSPARENT_HUGEPAGE\nmm/memory-failure.c-715-static int check_hwpoisoned_pmd_entry(pmd_t *pmdp, unsigned long addr,\n--\nmm/memory.c=4199=static vm_fault_t wp_page_shared(struct vm_fault *vmf, struct folio *folio)\n--\nmm/memory.c-4238-\nmm/memory.c:4239:#ifdef CONFIG_TRANSPARENT_HUGEPAGE\nmm/memory.c-4240-static bool __wp_can_reuse_large_anon_folio(struct folio *folio,\n--\nmm/memory.c-4304-}\nmm/memory.c:4305:#else /* !CONFIG_TRANSPARENT_HUGEPAGE */\nmm/memory.c-4306-static bool __wp_can_reuse_large_anon_folio(struct folio *folio,\n--\nmm/memory.c-4310-}\nmm/memory.c:4311:#endif /* CONFIG_TRANSPARENT_HUGEPAGE */\n\n"
} |
| 39/2 | 2026/09/01 03:43 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 43640 output: 28 thoughts: 47 Thoughts: **Investigating Xen Grant Table Allocation** Okay, let's dive in. My immediate focus is on the Xen grant table, specifically the allocation mechanism. I need to understand how these DMA allocations are handled. My initial target is `drivers/xen/grant-table.c`, where I expect to find the core logic tied to `XEN_GRANT_DMA_ALLOC` or any relevant `XEN` symbols. I need to be sure I understand the calls within. After that, I also need to verify that `drivers/xen/Makefile` and `Kconfig` contain everything needed to make sure it compiles with the correct parameters, and that no features are disabled that I might need. |
| 40/2 | 2026/09/01 03:43 | tool | grepper |
0mArgs:{
"Expression": "grant-table.o",
"PathPrefix": "drivers/xen"
}Results: {
"Output": "drivers/xen/Makefile=2=obj-$(CONFIG_HOTPLUG_CPU)\t\t+= cpu_hotplug.o\ndrivers/xen/Makefile:3:obj-y\t+= grant-table.o features.o balloon.o manage.o time.o\ndrivers/xen/Makefile-4-obj-y\t+= mem-reservation.o\n"
} |
| 41/2 | 2026/09/01 03:43 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 43949 output: 24 thoughts: 22 Thoughts: Okay, here's my summary, framed as my thought process: **Investigating the Xen Driver Build Configuration** Alright, I need to figure out the build conditions for the Xen drivers within this system. My immediate hunch is that the key to this lies within the Kconfig and Makefile files within the `drivers/xen` directory. However, a more likely location for the master configuration options would be in the `drivers/xen/Kconfig` file or at the top level in the `drivers/Makefile`. It's a standard pattern, and those files are usually the first place to look when trying to understand conditional compilation. Let's start digging there and see what we can find. I expect to see dependencies on other kernel features or specific hardware, or perhaps a configuration option that's explicitly enabling or disabling these drivers. It's a fairly standard approach to kernel module builds, so hopefully, the configuration is clear enough. Let's get to it. |
| 42/2 | 2026/09/01 03:43 | tool | grepper |
0mArgs:{
"Expression": "xen",
"PathPrefix": "drivers/Makefile"
}Results: {
"Output": "drivers/Makefile=50=obj-$(CONFIG_VDPA)\t\t+= vdpa/\ndrivers/Makefile:51:obj-$(CONFIG_XEN)\t\t+= xen/\ndrivers/Makefile-52-\n"
} |
| 43/2 | 2026/09/01 03:43 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 44255 output: 26 thoughts: 49 Thoughts: Okay, here's my thought process as I'd approach this, considering I'm knee-deep in this kind of kernel work: **Investigating the `md-bitmap.c` Driver** Alright, the first thing I want to do is see where this is all going, so let's start with `XEN`. I figure I should start by getting a handle on whether `XEN` is running, since this sounds like a potential disk-related issue. That'll give me context to dive deeper. Next, I need to understand how the `md-bitmap.c` driver is being used. Specifically, I need to understand what configuration options enable it. So, Iāll head straight for `drivers/md/md-bitmap.c`. Gotta find the configuration directives. Okay, let's look at the `Makefile` in the `drivers/md/` directory. That's usually where the dependencies and build rules are defined, which should show me the Kconfig option that pulls in `md-bitmap.c`. From here, I can get a better sense of how it's used and build a plan to troubleshoot. |
| 44/2 | 2026/09/01 03:43 | tool | grepper |
0mArgs:{
"Expression": "md-bitmap",
"PathPrefix": "drivers/md"
}Results: {
"Output": "drivers/md/Makefile=30=md-mod-y\t+= md.o\ndrivers/md/Makefile:31:md-mod-$(CONFIG_MD_BITMAP)\t+= md-bitmap.o\ndrivers/md/Makefile-32-md-mod-$(CONFIG_MD_LLBITMAP)\t+= md-llbitmap.o\n--\ndrivers/md/dm-raid.c-15-#include \"raid10.h\"\ndrivers/md/dm-raid.c:16:#include \"md-bitmap.h\"\ndrivers/md/dm-raid.c-17-\n--\ndrivers/md/md-bitmap.c-33-#include \"md.h\"\ndrivers/md/md-bitmap.c:34:#include \"md-bitmap.h\"\ndrivers/md/md-bitmap.c-35-#include \"md-cluster.h\"\n--\ndrivers/md/md-cluster.c-12-#include \"md.h\"\ndrivers/md/md-cluster.c:13:#include \"md-bitmap.h\"\ndrivers/md/md-cluster.c-14-#include \"md-cluster.h\"\n--\ndrivers/md/md-llbitmap.c-16-#include \"md.h\"\ndrivers/md/md-llbitmap.c:17:#include \"md-bitmap.h\"\ndrivers/md/md-llbitmap.c-18-\n--\ndrivers/md/md.c-68-#include \"md.h\"\ndrivers/md/md.c:69:#include \"md-bitmap.h\"\ndrivers/md/md.c-70-#include \"md-cluster.h\"\n--\ndrivers/md/raid1.c-37-#include \"raid1.h\"\ndrivers/md/raid1.c:38:#include \"md-bitmap.h\"\ndrivers/md/raid1.c-39-#include \"md-cluster.h\"\n--\ndrivers/md/raid10.c-25-#include \"raid0.h\"\ndrivers/md/raid10.c:26:#include \"md-bitmap.h\"\ndrivers/md/raid10.c-27-#include \"md-cluster.h\"\n--\ndrivers/md/raid5-cache.c-16-#include \"raid5.h\"\ndrivers/md/raid5-cache.c:17:#include \"md-bitmap.h\"\ndrivers/md/raid5-cache.c-18-#include \"raid5-log.h\"\n--\ndrivers/md/raid5.c-55-#include \"raid0.h\"\ndrivers/md/raid5.c:56:#include \"md-bitmap.h\"\ndrivers/md/raid5.c-57-#include \"raid5-log.h\"\n"
} |
| 45/2 | 2026/09/01 03:43 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 45245 output: 27 thoughts: 21 Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience: **Investigating the RAID Configuration Options** Alright, let's dive in. When I see something like this, my immediate thought process is: I need to quickly establish *exactly* how the RAID implementation is configured. The phrase "Let's check" is a trigger for me to get into the weeds. I'm thinking about the low-level stuff. Specifically, my mind jumps right to the kernel configuration options that govern the software RAID functionality. We're talking about options like `CONFIG_MD_BITMAP` and `CONFIG_BLK_DEV_MD`. My objective is clear: to determine the enabled features related to metadata and the core block device management for RAID. I want to know which RAID levels are supported, if bitmap logging is enabled (critical for fast recovery), and how the underlying block device interaction is structured. I'm mentally parsing the configuration options to get a complete picture of the RAID setup. This information will inform any subsequent analysis or troubleshooting. |
| 46/2 | 2026/09/01 03:43 | tool | grepper |
0mArgs:{
"Expression": "config MD_BITMAP",
"PathPrefix": "drivers/md"
}Results: {
"Output": "drivers/md/Kconfig=15=config BLK_DEV_MD\n--\ndrivers/md/Kconfig-39-\ndrivers/md/Kconfig:40:config MD_BITMAP\ndrivers/md/Kconfig-41-\tbool \"MD RAID bitmap support\"\n--\ndrivers/md/Kconfig=66=config MD_AUTODETECT\n--\ndrivers/md/Kconfig-79-\ndrivers/md/Kconfig:80:config MD_BITMAP_FILE\ndrivers/md/Kconfig-81-\tbool \"MD bitmap file support (deprecated)\"\n"
} |
| 47/2 | 2026/09/01 03:43 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 45658 output: 33 thoughts: 191 Thoughts: **Kernel Configuration Hunt** Okay, time to dig into this kernel configuration puzzle. First, I'll start by checking a few likely suspects related to bitmap metadata and RAID configurations. I need to make sure `CONFIG_MD_BITMAP` and `CONFIG_BLK_DEV_MD` are enabled. I'll take a look at `drivers/md/md-bitmap.c` and specifically key functions like `write_file_page` and `free_buffers` there. That should provide some insight. Next, I'll broaden the scope to include specific file systems. I'll need to confirm support for various filesystems, so I will start by examining their headers. Let's see... `fs/f2fs/f2fs.h` should be the entrypoint for F2FS configurations, so I will look for `F2FS_FS` there. Then, let's move onto `fs/ubifs/file.c` to confirm `UBIFS_FS`. After that, I will also check `fs/ceph/addr.c` to see `CEPH_FS`, and `fs/nfs/` for `NFS_FS`. This is all to confirm the expected filesystem configurations are enabled. Finally, just to make sure I don't miss anything that has changed, I'll need to check the Intel Processor Trace and Branch Trace Store configurations. Let's examine `arch/x86/events/intel/pt.c` and `bts.c`. I need to ensure that `PERF_EVENTS_INTEL_PT` and `PERF_EVENTS_INTEL_BTS` are properly configured. With that, it's time to check the Kconfig files themselves. Let's see what they have to say! |
| 48/2 | 2026/09/01 03:43 | tool | grepper |
0mArgs:{
"Expression": "PERF_EVENTS_INTEL_",
"PathPrefix": "arch/x86"
}Results: {
"Output": "arch/x86/events/Kconfig=2=menu \"Performance monitoring\"\narch/x86/events/Kconfig-3-\narch/x86/events/Kconfig:4:config PERF_EVENTS_INTEL_UNCORE\narch/x86/events/Kconfig-5-\ttristate \"Intel uncore performance events\"\n--\narch/x86/events/Kconfig-11-\narch/x86/events/Kconfig:12:config PERF_EVENTS_INTEL_RAPL\narch/x86/events/Kconfig-13-\ttristate \"Intel/AMD rapl performance events\"\n--\narch/x86/events/Kconfig-19-\narch/x86/events/Kconfig:20:config PERF_EVENTS_INTEL_CSTATE\narch/x86/events/Kconfig-21-\ttristate \"Intel cstate performance events\"\n--\narch/x86/events/Makefile=2=obj-y\t\t\t\t\t+= core.o probe.o utils.o\narch/x86/events/Makefile:3:obj-$(CONFIG_PERF_EVENTS_INTEL_RAPL)\t+= rapl.o\narch/x86/events/Makefile-4-obj-y\t\t\t\t\t+= amd/\n--\narch/x86/events/intel/Makefile=4=obj-$(CONFIG_CPU_SUP_INTEL)\t\t+= lbr.o p4.o p6.o pt.o\narch/x86/events/intel/Makefile:5:obj-$(CONFIG_PERF_EVENTS_INTEL_UNCORE)\t+= intel-uncore.o\narch/x86/events/intel/Makefile-6-intel-uncore-objs\t\t\t:= uncore.o uncore_nhmex.o uncore_snb.o uncore_snbep.o uncore_discovery.o\narch/x86/events/intel/Makefile:7:obj-$(CONFIG_PERF_EVENTS_INTEL_CSTATE)\t+= intel-cstate.o\narch/x86/events/intel/Makefile-8-intel-cstate-objs\t\t\t:= cstate.o\n"
} |
| 49/2 | 2026/09/01 03:43 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 46785 output: 28 thoughts: 47 Thoughts: Here's my summary, as though I'm thinking through this process: **Diving into the Intel Performance Monitoring Unit (PMU) Code** Okay, so I'm looking at the `arch/x86/events/intel/Makefile` file. My goal here is to understand the build process and how the various performance monitoring features are enabled, specifically for Intel CPUs. Right off the bat, I see the line `obj-$(CONFIG_CPU_SUP_INTEL) += ... pt.o bts.o`. That's the key. This line tells the build system that if the `CONFIG_CPU_SUP_INTEL` configuration option is set (meaning we're building for a supported Intel CPU), then a few object files are included in the build. I'm already pretty familiar with things like `pt.o` (Performance Trace), but the one that jumps out to me now is `bts.o`. Let's dig into `bts.o` specifically and see what it is all about. Probably Branch Trace Store. |
| 50/2 | 2026/09/01 03:43 | tool | grepper |
0mArgs:{
"Expression": "bts\\.o",
"PathPrefix": "arch/x86"
}Results: {
"Output": "arch/x86/events/intel/Makefile-1-# SPDX-License-Identifier: GPL-2.0\narch/x86/events/intel/Makefile:2:obj-$(CONFIG_CPU_SUP_INTEL)\t\t+= core.o bts.o\narch/x86/events/intel/Makefile-3-obj-$(CONFIG_CPU_SUP_INTEL)\t\t+= ds.o knc.o\n"
} |
| 51/2 | 2026/09/01 03:43 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 47193 output: 32 thoughts: 1652 Thoughts: **Focusing on Key Kernel Functionality for Fuzzing** Right, `CPU_SUP_INTEL` is our standard x86 configuration, so let's move on. My immediate focus is on identifying key kernel functions that are relevant and likely entry points for fuzzing, given these changes. First, I need to remind myself of the relevant configurations involved. I'm seeing changes related to these filesystems and memory management: `EROFS_FS`, `EROFS_FS_ZIP`, `FS_ENCRYPTION`, `TRANSPARENT_HUGEPAGE`, `HUGETLBFS`, `ZSMALLOC`, `ZRAM`, `ZSWAP`, `F2FS_FS`, `UBIFS_FS`, `NFS_FS`, `CEPH_FS`, and `MD_BITMAP`. Now, according to the guidance, I need to carefully select "FocusSymbols." We want to avoid generic, hot-path functions. The goal is to identify non-static, non-inlined API entrypoints ā the functions that are good targets for fuzzing because they are externally visible and have their own symbol addresses. Therefore, let's carefully review the modified files and, after a closer inspection, I'm identifying the following candidates: 1. `fs/erofs/data.c`: I see three non-static functions here: `erofs_onlinefolio_init`, `erofs_onlinefolio_split`, and `erofs_onlinefolio_end`. These `erofs_onlinefolio_*` functions seem promising as potential targets, since they are used in other files. 2. `fs/crypto/crypto.c`: `fscrypt_encrypt_pagecache_blocks` and `fscrypt_free_bounce_page` look to be relevant too. 3. `mm/hugetlb.c`: The function `add_hugetlb_folio` looks like it fits the criteria. 4. `mm/migrate.c`: The function `folio_migrate_flags` also seems to be a good focus. 5. `fs/proc/page.c`: `stable_page_flags` is a good focus. 6. `drivers/xen/grant-table.c`: `gnttab_pages_set_private` and `gnttab_pages_clear_private` also seem promising. 7. `mm/zsmalloc.c`: `zs_malloc` and `zs_free` and `zs_compact` seem important too. Now, let's take a comprehensive look at *all* functions modified in the diff, static or otherwise, to avoid missing any potential candidates. This allows us to exclude those functions which may not be worth fuzzing, based on the information we are given. This is a manual, but thorough, process. After a comprehensive review, I've confirmed my initial selection. The other modified functions, such as those related to tracing, documentation, or static inline helpers, are not critical for us right now. I will double-check that `erofs_onlinefolio_init`, `erofs_onlinefolio_end`, `fscrypt_encrypt_pagecache_blocks`, `fscrypt_free_bounce_page`, `add_hugetlb_folio`, `folio_migrate_flags`, `stable_page_flags`, `gnttab_pages_set_private`, and `gnttab_pages_clear_private` are still the best candidates. Finally, I need to verify any configuration dependencies for the filesystems to ensure nothing is missed or incorrectly assigned. I'm focusing on the configurations: `EROFS_FS`, `EROFS_FS_ZIP`, `FS_ENCRYPTION`, `HUGETLBFS`, `TRANSPARENT_HUGEPAGE`, `ZSMALLOC`, and `F2FS_FS`. I'll start by checking if there's anything unusual for `EROFS_FS`, but the Kconfig looks fine, so I will move on to the rest. |
| 52/2 | 2026/09/01 03:44 | tool | grepper |
0mArgs:{
"Expression": "config EROFS_FS\\b",
"PathPrefix": "fs/erofs"
}Results: {
"Output": "fs/erofs/Kconfig-2-\nfs/erofs/Kconfig:3:config EROFS_FS\nfs/erofs/Kconfig-4-\ttristate \"EROFS filesystem support\"\n"
} |
| 53/2 | 2026/09/01 03:44 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 49804 output: 33 thoughts: 20 Thoughts: Here's my take on those lines from `fs/erofs/Kconfig`. **ERofs Kconfig Review: Initial Scan** Okay, first things first, let's dive into the initial lines of this `Kconfig` file for EROFS. Lines 1 through 25, got it. This gives me the broad strokes of the module's configuration options. I'm expecting to see the dependencies, maybe some default values, and the top-level menu entries that would guide a user through its various settings. I'm looking for the structure and hierarchy - are we dealing with a simple yes/no feature, or something with sub-options and complexities? Does this configuration build upon existing features, or does it try to do something new? Any obvious interactions with other file systems or kernel subsystems will jump out at me as potentially interesting. Iām thinking about possible conflicts or areas where it might need special handling. Let's see if there are any immediate red flags, or any pleasant surprises like good documentation in the comments. I'm particularly interested in seeing how they're handling the licensing and any versioning information in the Kconfig file. I'm expecting a pretty standard structure, given it's a kernel module, but there might be some EROFS-specific idiosyncrasies that are worth noting. Let's see. |
| 54/2 | 2026/09/01 03:44 | tool | read-file |
0mArgs:{
"File": "fs/erofs/Kconfig",
"FirstLine": 1,
"LineCount": 25
}Results: {
"Contents": " 1:\t# SPDX-License-Identifier: GPL-2.0-only\n 2:\t\n 3:\tconfig EROFS_FS\n 4:\t\ttristate \"EROFS filesystem support\"\n 5:\t\tdepends on BLOCK\n 6:\t\tselect CRC32\n 7:\t\tselect CRYPTO if EROFS_FS_ZIP_ACCEL\n 8:\t\tselect CRYPTO_DEFLATE if EROFS_FS_ZIP_ACCEL\n 9:\t\tselect FS_IOMAP\n 10:\t\tselect LZ4_DECOMPRESS if EROFS_FS_ZIP\n 11:\t\tselect XXHASH if EROFS_FS_XATTR\n 12:\t\tselect XZ_DEC if EROFS_FS_ZIP_LZMA\n 13:\t\tselect XZ_DEC_MICROLZMA if EROFS_FS_ZIP_LZMA\n 14:\t\tselect ZLIB_INFLATE if EROFS_FS_ZIP_DEFLATE\n 15:\t\tselect ZSTD_DECOMPRESS if EROFS_FS_ZIP_ZSTD\n 16:\t\thelp\n 17:\t\t EROFS (Enhanced Read-Only File System) is a modern, lightweight,\n 18:\t\t secure read-only filesystem for various use cases, such as immutable\n 19:\t\t system images, container images, application sandboxes, and datasets.\n 20:\t\n 21:\t\t EROFS uses a flexible, hierarchical on-disk design so that features\n 22:\t\t can be enabled on demand: the core on-disk format is block-aligned in\n 23:\t\t order to perform optimally on all kinds of devices, including block\n 24:\t\t and memory-backed devices; the format is easy to parse and has zero\n 25:\t\t metadata redundancy, unlike generic filesystems, making it ideal for\n"
} |
| 55/2 | 2026/09/01 03:44 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 50590 output: 32 thoughts: 14 Thoughts: Here's my take on those thoughts, tailored for an expert audience: **Kconfig Dependency Deep Dive** Okay, so I'm looking at `fs/crypto/Kconfig` right now. My immediate concern is, what are the upstream dependencies? I need to understand the full scope of what activating or deactivating these filesystem encryption options might pull in, and more importantly, what might be *blocked* if I disable things. This isn't just about the direct `depends on` statements; I need to think about transitive dependencies, potential conflicts with other features, and how these choices ripple through the entire kernel build. I also need to be mindful of architectural considerations here. Are we talking about performance impacts from enabling specific crypto algorithms or are there other issues? Time to start drilling into those Kconfig files and tracing those dependencies. |
| 56/2 | 2026/09/01 03:44 | tool | read-file |
0mArgs:{
"File": "fs/crypto/Kconfig",
"FirstLine": 1,
"LineCount": 25
}Results: {
"Contents": " 1:\t# SPDX-License-Identifier: GPL-2.0-only\n 2:\tconfig FS_ENCRYPTION\n 3:\t\tbool \"FS Encryption (Per-file encryption)\"\n 4:\t\tselect BLK_INLINE_ENCRYPTION if BLOCK\n 5:\t\tselect BLK_INLINE_ENCRYPTION_FALLBACK if BLOCK\n 6:\t\tselect CRYPTO\n 7:\t\tselect CRYPTO_SKCIPHER\n 8:\t\tselect CRYPTO_LIB_AES\n 9:\t\tselect CRYPTO_LIB_SHA256\n 10:\t\tselect CRYPTO_LIB_SHA512\n 11:\t\tselect KEYS\n 12:\t\thelp\n 13:\t\t Enable encryption of files and directories. This\n 14:\t\t feature is similar to ecryptfs, but it is more memory\n 15:\t\t efficient since it avoids caching the encrypted and\n 16:\t\t decrypted pages in the page cache. Currently Ext4,\n 17:\t\t F2FS, UBIFS, and CephFS make use of this feature.\n 18:\t\n 19:\t# Filesystems supporting encryption must select this if FS_ENCRYPTION. This\n 20:\t# allows the algorithms to be built as modules when all the filesystems are,\n 21:\t# whereas selecting them from FS_ENCRYPTION would force them to be built-in.\n 22:\t#\n 23:\t# Note: this option only pulls in the algorithms that filesystem encryption\n 24:\t# needs \"by default\". If userspace will use \"non-default\" encryption modes such\n 25:\t# as Adiantum encryption, then those other modes need to be explicitly enabled\n"
} |
| 57/2 | 2026/09/01 03:44 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 51226 output: 246 thoughts: 289 Thoughts: **Fuzzing Target Decision** Okay, this looks good. Everything seems very straightforward and well-defined. My analysis tells me we've got a prime candidate for fuzzing here. I'm going to prepare the `set-results` parameters. First, `WorthFuzzing` is definitely `true`. This patch is touching core memory management ā removing the `PG_private` flag and introducing folio-related checks, changes to readahead iterators with `readehead_folio_last`, and alterations in filesystem private folio handling, specifically in EROFS and fscrypt. It also impacts page flag reporting and zsmalloc / hugetlb / migration accounting. These are fundamental changes in kernel memory management and filesystem interaction, making them highly susceptible to edge cases and errors that fuzzing could uncover. We know fuzzing is the right thing to do! Next, for `Reasoning`, I'll concisely capture that the patch modifies core memory management, readahead iterators, filesystem private folio handling, page flags reporting, and zsmalloc/hugetlb/migration accounting ā all worthwhile targets. These are all functional changes. For `FocusSymbols`, I'll include the following functions, as they seem to be the most critical points of interaction with the new or modified logic: `erofs_onlinefolio_init`, `erofs_onlinefolio_end`, `fscrypt_encrypt_pagecache_blocks`, `fscrypt_free_bounce_page`, `add_hugetlb_folio`, `folio_migrate_flags`, and `stable_page_flags`. These should give us good coverage of the changes. Finally, for `EnableConfigs`, I'll need to enable a few kernel configs to ensure that we can actually exercise the code paths. I'll include `EROFS_FS`, `EROFS_FS_ZIP`, `FS_ENCRYPTION`, `HUGETLBFS`, `TRANSPARENT_HUGEPAGE`, and `ZSMALLOC`. Now, that's done, I'll call `set-results` and get this fuzzing run started! |
| 58/2 | 2026/09/01 03:44 | tool | set-results |
0mArgs:{
"EnableConfigs": [
"EROFS_FS",
"EROFS_FS_ZIP",
"FS_ENCRYPTION",
"HUGETLBFS",
"TRANSPARENT_HUGEPAGE",
"ZSMALLOC"
],
"FocusSymbols": [
"erofs_onlinefolio_init",
"erofs_onlinefolio_end",
"fscrypt_encrypt_pagecache_blocks",
"fscrypt_free_bounce_page",
"add_hugetlb_folio",
"folio_migrate_flags",
"stable_page_flags"
],
"Reasoning": "The patch removes the PG_private page flag across the kernel in favor of direct folio-\u003eprivate and page_private checks, implements a reverse readahead iterator (readahead_folio_last) for pagemaps, updates online folio handling in EROFS, updates ciphertext bounce page handling in fscrypt, and adjusts HugeTLB/migration/zsmalloc metadata tracking. These are reachable, functional changes in core memory management and filesystems that should be fuzzed.",
"WorthFuzzing": true
}Results: {
"EnableConfigs": [
"EROFS_FS",
"EROFS_FS_ZIP",
"FS_ENCRYPTION",
"HUGETLBFS",
"TRANSPARENT_HUGEPAGE",
"ZSMALLOC"
],
"FocusSymbols": [
"erofs_onlinefolio_init",
"erofs_onlinefolio_end",
"fscrypt_encrypt_pagecache_blocks",
"fscrypt_free_bounce_page",
"add_hugetlb_folio",
"folio_migrate_flags",
"stable_page_flags"
],
"Reasoning": "The patch removes the PG_private page flag across the kernel in favor of direct folio-\u003eprivate and page_private checks, implements a reverse readahead iterator (readahead_folio_last) for pagemaps, updates online folio handling in EROFS, updates ciphertext bounce page handling in fscrypt, and adjusts HugeTLB/migration/zsmalloc metadata tracking. These are reachable, functional changes in core memory management and filesystems that should be fuzzed.",
"WorthFuzzing": true
} |
| 59/1 | 2026/09/01 03:44 | action | If |
0mArgs:{
"WorthFuzzing": true
}Results: null |
| 60/2 | 2026/09/01 03:44 | agent | kmsan-evaluator |
0mModel:core Args: null Results: {
"KMSANReasoning": "The patch eliminates the PG_private page flag in favor of directly using folio-\u003eprivate (and folio_test_fs_private()), adjusting the mm subsystem, filesystems (Ceph, EROFS, F2FS, NFS, UBIFS), drivers, and tracing infrastructure accordingly.\n\nThese changes refactor internal kernel page/folio metadata management and page cache readahead iteration. They do not introduce or modify any user-space copy paths (no risk of uninitialized struct/padding info-leaks), do not introduce uninitialized stack or heap allocations, and do not introduce conditional branching on uninitialized data. Any potential regressions (such as refcount imbalances, page cache state inconsistencies, or NULL pointer dereferences) are covered by KASAN, LOCKDEP, and internal MM assertions. Therefore, a dedicated KMSAN fuzzing session is not warranted.",
"NeedsKMSAN": false
}Instruction: You are an expert Linux kernel security engineer specializing in kernel memory
error detectors (KASAN and KMSAN). Your job is to review the provided patch series and
determine if the code changes justify spawning a dedicated KMSAN (KernelMemorySanitizer)
fuzzing session in addition to standard KASAN fuzzing.
CRITICAL DISTINCTION BETWEEN KASAN AND KMSAN:
- Standard KASAN kernel builds (upstream-apparmor-kasan.config) already enable
a comprehensive suite of debugging tools and sanitizers, including KASAN
(out-of-bounds accesses, use-after-free, double free, invalid free), LOCKDEP
(locking bugs and deadlocks), UB-sanitizers, and memory corruption checks.
- KMSAN (KernelMemorySanitizer) detects reads of UNINITIALIZED memory (stack, heap,
or page allocations) and kernel-to-user memory info-leaks.
Rule: THERE IS NO SENSE IN RUNNING A KMSAN SESSION IF A BUG CAN BE CAUGHT BY KASAN,
LOCKDEP, OR OTHER STANDARD BUG DETECTORS.
A dedicated KMSAN fuzzing session incurs significant resource costs. You must ONLY
set NeedsKMSAN=true if the code changes introduce or expose UNINITIALIZED MEMORY risks
that are detected ONLY by KMSAN.
Look holistically at the patch series and surrounding code. Even if no direct
uninitialized field accesses or new buffer allocations are added in the diff itself,
a patch may alter control flow, bounds checking, or data length calculations in ways
that change how the rest of the code operates on existing buffers (e.g. allowing
uninitialized stack/heap memory to be read, copied to user space, or used in control
flow). Do not hesitate to use your code access tools to inspect the surrounding code,
called functions, and callers.
Set NeedsKMSAN=true ONLY IF the patch introduces or modifies:
1. Kernel structures sent to user space (via copy_to_user, put_user, netlink skb
attributes, ioctl output arguments, socket options, or BPF buffers) where fields
or structure padding might not be fully initialized/zeroed.
2. Conditional logic or branching that depends on potentially uninitialized variables
or struct fields.
3. Allocation or initialization of complex data structures where uninitialized fields
could be read later in reachable code paths.
4. Bounds checks, lengths, or logic in a way that allows surrounding code to access
uninitialized bytes of existing buffers.
Set NeedsKMSAN=false IF:
- The code changes primarily risk out-of-bounds access, array overflows, NULL pointer
dereferences, locking deadlocks, or use-after-free bugs (these are already caught
by KASAN, LOCKDEP, or standard bug detectors).
- All stack/heap structures touched or introduced by the patch are fully zeroed
or initialized (e.g. using = {0}, memset, kzalloc) before being read or copied.
- The patch does not introduce any risk of uninitialized memory usage or info-leaks.
Use your code access tools to inspect the surrounding code if necessary, then provide
detailed KMSANReasoning contrasting KASAN vs KMSAN applicability for this patch.
Prefer calling several tools at the same time to save round-trips.
Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.
Prompt: For your convenience, here is the diff of the changes:
commit 421bcb73cd4f011e8a27d95d741dbb1eb94e34c6
Author: syz-cluster <triage@syzkaller.com>
Date: Tue Sep 1 03:41:49 2026 +0000
syz-cluster: applied patch under review
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 d3a93eec3945f..dec7816303c6a 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/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 5754cd4055628..49349afee6119 100644
--- a/arch/x86/events/intel/pt.c
+++ b/arch/x86/events/intel/pt.c
@@ -781,8 +781,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);
@@ -1296,8 +1295,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/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c
index b8325cb09a371..0cf14bc1cff32 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/drivers/xen/balloon.c b/drivers/xen/balloon.c
index e7f74ea7cd5eb..fdb18348cfdfe 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 69922be28b54c..993f89f048e21 100644
--- a/drivers/xen/grant-table.c
+++ b/drivers/xen/grant-table.c
@@ -863,10 +863,10 @@ EXPORT_SYMBOL_GPL(gnttab_free_auto_xlat_frames);
int gnttab_pages_set_private(int nr_pages, struct page **pages)
{
+#if BITS_PER_LONG < 64
int i;
for (i = 0; i < nr_pages; i++) {
-#if BITS_PER_LONG < 64
struct xen_page_foreign *foreign;
foreign = kzalloc_obj(*foreign);
@@ -874,9 +874,9 @@ int gnttab_pages_set_private(int nr_pages, struct page **pages)
return -ENOMEM;
set_page_private(pages[i], (unsigned long)foreign);
-#endif
- SetPagePrivate(pages[i]);
}
+#endif
+ /* 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);
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c
index 657c2cb0f8811..f9b2ec9550481 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;
}
/*
@@ -124,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. Setting folio->private is
+ * what gets us the invalidate_folio callback.
*/
VM_WARN_ON_FOLIO(folio->private, folio);
folio_attach_private(folio, snapc);
diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c
index 5286a124b0d98..aced5c50a4601 100644
--- a/fs/crypto/crypto.c
+++ b/fs/crypto/crypto.c
@@ -65,7 +65,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);
@@ -210,7 +209,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;
}
diff --git a/fs/erofs/data.c b/fs/erofs/data.c
index 0885b1f2fc925..f71c7b51bb720 100644
--- a/fs/erofs/data.c
+++ b/fs/erofs/data.c
@@ -239,19 +239,23 @@ int erofs_map_dev(struct super_block *sb, struct erofs_map_dev *map)
/*
* bit 30: I/O error occurred on this folio
* bit 29: CPU has dirty data in D-cache (needs aliasing handling);
- * bit 0 - 29: remaining parts to complete this folio
+ * bit 0 - 28: remaining parts to complete this folio, biased by 1 so that
+ * ->private stays non-NULL while the folio is attached
*/
#define EROFS_ONLINEFOLIO_EIO 30
#define EROFS_ONLINEFOLIO_DIRTY 29
+#define EROFS_ONLINEFOLIO_COUNT_MASK (BIT(EROFS_ONLINEFOLIO_DIRTY) - 1)
+#define EROFS_ONLINEFOLIO_BIAS 1
void erofs_onlinefolio_init(struct folio *folio)
{
union {
atomic_t o;
void *v;
- } u = { .o = ATOMIC_INIT(1) };
+ } u = { .o = ATOMIC_INIT(1 + EROFS_ONLINEFOLIO_BIAS) };
- 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)
@@ -265,14 +269,14 @@ void erofs_onlinefolio_end(struct folio *folio, int err, bool dirty)
do {
orig = atomic_read((atomic_t *)&folio->private);
- DBG_BUGON(orig <= 0);
+ DBG_BUGON((orig & EROFS_ONLINEFOLIO_COUNT_MASK) <= EROFS_ONLINEFOLIO_BIAS);
v = dirty << EROFS_ONLINEFOLIO_DIRTY;
v |= (orig - 1) | (!!err << EROFS_ONLINEFOLIO_EIO);
} while (atomic_cmpxchg((atomic_t *)&folio->private, orig, v) != orig);
- if (v & (BIT(EROFS_ONLINEFOLIO_DIRTY) - 1))
+ if ((v & EROFS_ONLINEFOLIO_COUNT_MASK) != EROFS_ONLINEFOLIO_BIAS)
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)));
diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c
index e1e25ca0d1904..78fd7d980e957 100644
--- a/fs/erofs/zdata.c
+++ b/fs/erofs/zdata.c
@@ -1898,21 +1898,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);
+ /* traverse from last to first for best metadata I/O performance */
+ while ((folio = readahead_folio_last(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/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 9940a6cecf1a2..2f7ab5888b078 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -2691,7 +2691,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)); \
}
@@ -2710,9 +2710,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)); \
}
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index e1bdd10b35f10..38f830a6467c9 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -484,7 +484,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,
@@ -555,7 +555,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/nfs/write.c b/fs/nfs/write.c
index 623e7ef1f73d5..b6967b5286691 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);
@@ -745,7 +744,6 @@ static void nfs_inode_remove_request(struct nfs_page *req)
spin_lock(&mapping->i_private_lock);
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/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/fs/ubifs/file.c b/fs/ubifs/file.c
index e73c28b12f97f..aa0298ce451ef 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
+ * not budgeted so it 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 the @PG_checked flag 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/buffer_head.h b/include/linux/buffer_head.h
index fd2c7115c0542..e47fbd0387b69 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,
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 dd09c438fa23e..2855739a0f379 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -2075,20 +2075,21 @@ 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
* offset of the folio, in units of PAGE_SIZE.
*
- * If pagecache pages are not associated with an inode, they are said to be
- * anonymous pages. These may become associated with the swapcache, and in that
- * case PG_swapcache is set, and page->private is an offset into the swapcache.
+ * If pagecache folios are not associated with an inode, they are said to be
+ * anonymous folios. These may become associated with the swapcache, and in that
+ * case PG_swapcache is set, and folio->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
- * refcount. The each user mapping also has a reference to the page.
+ * reference to the folio. Attaching filesystem private data via
+ * folio_attach_private() also increments the refcount. Each user mapping also
+ * has a reference to the folio.
*
* The pagecache pages are stored in a per-mapping radix tree, which is
* rooted at mapping->i_pages, and indexed by offset.
@@ -3022,9 +3023,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),
@@ -3062,10 +3063,16 @@ 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.
+ * Use data_race() since folio might not be locked.
+ */
+ ref_count += data_race(folio_test_fs_private(folio));
}
/* One reference per page table mapping. */
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index 6d815f6440c94..e35aece38b933 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)
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
index 7a863572adce7..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,9 +572,14 @@ 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)
+{
+ return folio->private;
+}
+
FOLIO_FLAG(private_2, FOLIO_HEAD_PAGE)
/* owner_2 can be set on tail pages for anon memory */
@@ -1170,7 +1171,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 +1195,23 @@ 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_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
@@ -1205,7 +1221,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_test_fs_private(folio) || folio_test_private_2(folio);
}
#undef PF_ANY
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index 0adfa6605653d..88b4c92b43575 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);
@@ -1416,6 +1414,7 @@ struct readahead_control {
bool dropbehind;
bool _workingset;
unsigned long _pflags;
+ bool _forward;
};
#define DEFINE_READAHEAD(ractl, f, r, m, i) \
@@ -1480,18 +1479,25 @@ void page_cache_async_readahead(struct address_space *mapping,
page_cache_async_ra(&ractl, folio, req_count);
}
+static inline void __readahead_advance(struct readahead_control *rac)
+{
+ if (rac->_forward)
+ rac->_index += rac->_batch_count;
+
+ rac->_nr_pages -= rac->_batch_count;
+ rac->_batch_count = 0;
+}
+
static inline struct folio *__readahead_folio(struct readahead_control *ractl)
{
struct folio *folio;
BUG_ON(ractl->_batch_count > ractl->_nr_pages);
- ractl->_nr_pages -= ractl->_batch_count;
- ractl->_index += ractl->_batch_count;
+ __readahead_advance(ractl);
+ ractl->_forward = true;
- if (!ractl->_nr_pages) {
- ractl->_batch_count = 0;
+ if (!ractl->_nr_pages)
return NULL;
- }
folio = xa_load(&ractl->mapping->i_pages, ractl->_index);
VM_BUG_ON_FOLIO(!folio_test_locked(folio), folio);
@@ -1517,6 +1523,39 @@ static inline struct folio *readahead_folio(struct readahead_control *ractl)
return folio;
}
+/**
+ * readahead_folio_last - 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_last(struct readahead_control *ractl)
+{
+ struct folio *folio;
+
+ /* Drop the previously returned batch from the remaining range. */
+ __readahead_advance(ractl);
+ ractl->_forward = false;
+
+ 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);
+
+ ractl->_batch_count = folio_nr_pages(folio);
+
+ folio_put(folio);
+ return folio;
+}
+
static inline unsigned int __readahead_batch(struct readahead_control *rac,
struct page **array, unsigned int array_sz)
{
@@ -1525,9 +1564,8 @@ static inline unsigned int __readahead_batch(struct readahead_control *rac,
struct folio *folio;
BUG_ON(rac->_batch_count > rac->_nr_pages);
- rac->_nr_pages -= rac->_batch_count;
- rac->_index += rac->_batch_count;
- rac->_batch_count = 0;
+ __readahead_advance(rac);
+ rac->_forward = true;
xas_set(&xas, rac->_index);
rcu_read_lock();
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/include/trace/events/pagemap.h b/include/trace/events/pagemap.h
index 36c3a90f0acca..5425ef7bbae6e 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_test_fs_private(folio) ? PAGEMAP_BUFFERS : 0) \
)
TRACE_EVENT(mm_lru_insertion,
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);
}
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)
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index ced400f72d43a..d085fd09466ef 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -4810,7 +4810,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_test_fs_private(folio) &&
folio_expected_ref_count(folio) != folio_ref_count(folio))
goto next;
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 7857728457952..4b6753b87162d 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.
+ * The hugetlb flags live in folio->private and are cleared by the above
+ * assignment. Restore the hugetlb_vmemmap_optimized flag.
*/
folio_set_hugetlb_vmemmap_optimized(folio);
diff --git a/mm/migrate.c b/mm/migrate.c
index 15b45832bcfa7..5ca1548ca6d61 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -835,7 +835,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))
@@ -1327,7 +1326,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_test_fs_private(src)) {
try_to_free_buffers(src);
goto out;
}
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index eeab25d6ce364..e03a1c46bce01 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_test_fs_private(folio));
if (mapping->host) {
/* !PageAnon && !swapper_space */
diff --git a/mm/vmscan.c b/mm/vmscan.c
index f11491ee9ed5c..29051c0f89881 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -955,7 +955,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_test_fs_private(folio))
return;
mapping = folio_mapping(folio);
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 825022a7a328f..24526185fd31f 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);
@@ -476,11 +471,6 @@ static void record_obj(unsigned long handle, unsigned long obj)
WRITE_ONCE(*(unsigned long *)handle, obj);
}
-static inline bool __maybe_unused is_first_zpdesc(struct zpdesc *zpdesc)
-{
- return PagePrivate(zpdesc_page(zpdesc));
-}
-
/* Protected by class->lock */
static inline int get_zspage_inuse(struct zspage *zspage)
{
@@ -496,7 +486,8 @@ static struct zpdesc *get_first_zpdesc(struct zspage *zspage)
{
struct zpdesc *first_zpdesc = zspage->first_zpdesc;
- VM_BUG_ON_PAGE(!is_first_zpdesc(first_zpdesc), zpdesc_page(first_zpdesc));
+ /* the first zpdesc must point back to this zspage */
+ VM_WARN_ON_ONCE_PAGE(first_zpdesc->zspage != zspage, zpdesc_page(first_zpdesc));
return first_zpdesc;
}
@@ -838,7 +829,8 @@ static inline bool obj_allocated(struct zpdesc *zpdesc, void *obj,
struct zspage *zspage = get_zspage(zpdesc);
if (unlikely(ZsHugePage(zspage))) {
- VM_BUG_ON_PAGE(!is_first_zpdesc(zpdesc), zpdesc_page(zpdesc));
+ /* only first zpdesc holds the handle */
+ VM_WARN_ON_ONCE_PAGE(zspage->first_zpdesc != zpdesc, zpdesc_page(zpdesc));
handle = zpdesc->handle;
} else
handle = *(unsigned long *)obj;
@@ -853,9 +845,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. */
@@ -1006,8 +995,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];
@@ -1015,7 +1004,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);
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",
|
| 61/3 | 2026/09/01 03:44 | llm | kmsan-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 16073 output: 200 thoughts: 1915 Thoughts: **KMSAN Assessment: Flag Removal and `page->private` Migration** Okay, let's break this down. This patch is essentially a refactoring, moving away from the `PG_private` page flag and migrating to direct checks of `page->private` or `folio->private`. My primary concern, as always, is whether this introduces a risk of uninitialized memory reads or information leaks to userspace, which is where KMSAN shines. The core of the change involves: * Removing `PG_private` and defining `__PG_folio` instead. Seems harmless on its own. * Updating numerous files to use `page_private(page)` or the equivalent `folio` functions instead of `PagePrivate(page)`. This is a straightforward find-and-replace, the question is what values are being read, and whether they're initialized. My analysis needs to focus on whether uninitialized memory is *introduced* or *exposed* to userspace. Standard KASAN should handle out-of-bounds, use-after-free, and other common memory corruption errors. KMSAN is for uninitialized memory reads. Specifically, I need to look for: 1. Kernel structures sent to user space where uninitialized fields could be a problem. 2. Conditional logic based on potentially uninitialized variables. 3. Allocations or initializations of data structures where uninitialized fields might be read later. 4. Potential for uninitialized bytes to be accessed through bounds checks. Let's examine the key areas: * `arch/x86/events/intel/bts.c` and `pt.c`: The change is simply replacing a macro check with a direct read of `page->private`. Crucially, if the bit wasn't set previously, `page->private` will be initialized to 0 because the page allocator initializes memory. If the bit wasn't set, then the result would be identical. No risk here. * `drivers/xen/balloon.c`: Explicitly zeroing `page->private`. This eliminates any possibility of uninitialized memory. * `fs/proc/page.c`: Removing the `KPF_PRIVATE` flag from `stable_page_flags`. Removing a flag from what's *read* doesn't cause uninitialized memory. * `fs/erofs/data.c` and `fs/erofs/zdata.c`: In the new `readahead_folio_last`, I need to ensure the `folio` is initialized before accessing its data. It's a page cache iterator, so the kernel is handling proper initialization and lifecycle, and no new variables or memory are introduced here, so this is fine. * `mm/hugetlb.c`, `mm/migrate.c`, `mm/page-writeback.c`, `mm/vmscan.c`, `mm/zsmalloc.c`: These are internal MM functions. Again, the change is mostly switching flag checks. `folio_test_fs_private` checks other flags (swapcache, hugetlb) along with the private flag, and no risk here since they rely on core mm data structures. The key observation is the `struct page` and `struct folio` are fundamental to memory management. The page allocator guarantees pages and folios are zeroed on allocation. The `page->private` field will be zero by default. There's no new user-space copy logic, no new system calls, no uninitialized stack variables being read, no new branching on uninitialized variables, and no new kernel-to-user memory transfers. Any bugs that might exist due to the changes are logical errors in the page cache or memory management, and those would be detectable by KASAN, LOCKDEP, or general kernel assertions. KMSAN is the wrong tool for those. Therefore, after a thorough review, `NeedsKMSAN` is `false`. The patch seems to be a safe refactoring. Time to call the `set-results` tool and move on. |
| 62/3 | 2026/09/01 03:44 | tool | set-results |
0mArgs:{
"KMSANReasoning": "The patch eliminates the PG_private page flag in favor of directly using folio-\u003eprivate (and folio_test_fs_private()), adjusting the mm subsystem, filesystems (Ceph, EROFS, F2FS, NFS, UBIFS), drivers, and tracing infrastructure accordingly.\n\nThese changes refactor internal kernel page/folio metadata management and page cache readahead iteration. They do not introduce or modify any user-space copy paths (no risk of uninitialized struct/padding info-leaks), do not introduce uninitialized stack or heap allocations, and do not introduce conditional branching on uninitialized data. Any potential regressions (such as refcount imbalances, page cache state inconsistencies, or NULL pointer dereferences) are covered by KASAN, LOCKDEP, and internal MM assertions. Therefore, a dedicated KMSAN fuzzing session is not warranted.",
"NeedsKMSAN": false
}Results: {
"KMSANReasoning": "The patch eliminates the PG_private page flag in favor of directly using folio-\u003eprivate (and folio_test_fs_private()), adjusting the mm subsystem, filesystems (Ceph, EROFS, F2FS, NFS, UBIFS), drivers, and tracing infrastructure accordingly.\n\nThese changes refactor internal kernel page/folio metadata management and page cache readahead iteration. They do not introduce or modify any user-space copy paths (no risk of uninitialized struct/padding info-leaks), do not introduce uninitialized stack or heap allocations, and do not introduce conditional branching on uninitialized data. Any potential regressions (such as refcount imbalances, page cache state inconsistencies, or NULL pointer dereferences) are covered by KASAN, LOCKDEP, and internal MM assertions. Therefore, a dedicated KMSAN fuzzing session is not warranted.",
"NeedsKMSAN": false
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|