| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/07/26 17:51 | flow | patch-triage |
2mArgs:null Results: {
"EnableConfigs": [
"HUGETLBFS",
"MEMORY_FAILURE",
"TRANSPARENT_HUGEPAGE"
],
"FocusSymbols": [
"hugetlb_page_hwpoison",
"hugetlb_unref_page_hwpoison",
"unpoison_memory",
"folio_clear_hugetlb_hwpoison"
],
"Reasoning": "The patch series introduces `LARGE_FOLIO` config and refactors how hwpoison is tracked for hugetlb folios. It replaces `adjust_range_hwpoison` in `fs/hugetlbfs/inode.c` with a generic one in `mm/filemap.c` and changes `hugetlbfs_read_iter` to `generic_file_read_iter`. It also modifies `folio_test_hwpoison` to `folio_has_hwpoisoned_page` in various places. These are functional changes to core kernel logic (mm, hugetlbfs, memory-failure) and should be fuzzed.",
"WorthFuzzing": true
} |
| 1/1 | 2026/07/26 17:51 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit 9b856ebd47ac50107c996236928dac5b63b3e96b\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Sun Jul 26 17:51:35 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/fs/Kconfig b/fs/Kconfig\nindex cf6ae64776e62c..eddac4ed214b12 100644\n--- a/fs/Kconfig\n+++ b/fs/Kconfig\n@@ -272,7 +272,7 @@ endif # HUGETLBFS\n \n config HUGETLB_PAGE\n \tdef_bool HUGETLBFS\n-\tselect XARRAY_MULTI\n+\tselect LARGE_FOLIO\n \n config HUGETLB_PAGE_OPTIMIZE_VMEMMAP\n \tdef_bool HUGETLB_PAGE\ndiff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c\nindex 216e1a0dd0b237..cef7e61b827d71 100644\n--- a/fs/hugetlbfs/inode.c\n+++ b/fs/hugetlbfs/inode.c\n@@ -187,113 +187,6 @@ hugetlb_get_unmapped_area(struct file *file, unsigned long addr,\n \treturn mm_get_unmapped_area_vmflags(file, addr0, len, pgoff, flags, 0);\n }\n \n-/*\n- * Someone wants to read @bytes from a HWPOISON hugetlb @folio from @offset.\n- * Returns the maximum number of bytes one can read without touching the 1st raw\n- * HWPOISON page.\n- */\n-static size_t adjust_range_hwpoison(struct folio *folio, size_t offset,\n-\t\tsize_t bytes)\n-{\n-\tstruct page *page = folio_page(folio, offset / PAGE_SIZE);\n-\tsize_t safe_bytes;\n-\n-\tif (is_raw_hwpoison_page_in_hugepage(page))\n-\t\treturn 0;\n-\t/* Safe to read the remaining bytes in this page. */\n-\tsafe_bytes = PAGE_SIZE - (offset % PAGE_SIZE);\n-\tpage++;\n-\n-\t/* Check each remaining page as long as we are not done yet. */\n-\tfor (; safe_bytes \u003c bytes; safe_bytes += PAGE_SIZE, page++)\n-\t\tif (is_raw_hwpoison_page_in_hugepage(page))\n-\t\t\tbreak;\n-\n-\treturn min(safe_bytes, bytes);\n-}\n-\n-/*\n- * Support for read() - Find the page attached to f_mapping and copy out the\n- * data. This provides functionality similar to filemap_read().\n- */\n-static ssize_t hugetlbfs_read_iter(struct kiocb *iocb, struct iov_iter *to)\n-{\n-\tstruct file *file = iocb-\u003eki_filp;\n-\tstruct hstate *h = hstate_file(file);\n-\tstruct address_space *mapping = file-\u003ef_mapping;\n-\tstruct inode *inode = mapping-\u003ehost;\n-\tunsigned long index = iocb-\u003eki_pos \u003e\u003e huge_page_shift(h);\n-\tunsigned long offset = iocb-\u003eki_pos \u0026 ~huge_page_mask(h);\n-\tunsigned long end_index;\n-\tloff_t isize;\n-\tssize_t retval = 0;\n-\n-\twhile (iov_iter_count(to)) {\n-\t\tstruct folio *folio;\n-\t\tsize_t nr, copied, want;\n-\n-\t\t/* nr is the maximum number of bytes to copy from this page */\n-\t\tnr = huge_page_size(h);\n-\t\tisize = i_size_read(inode);\n-\t\tif (!isize)\n-\t\t\tbreak;\n-\t\tend_index = (isize - 1) \u003e\u003e huge_page_shift(h);\n-\t\tif (index \u003e end_index)\n-\t\t\tbreak;\n-\t\tif (index == end_index) {\n-\t\t\tnr = ((isize - 1) \u0026 ~huge_page_mask(h)) + 1;\n-\t\t\tif (nr \u003c= offset)\n-\t\t\t\tbreak;\n-\t\t}\n-\t\tnr = nr - offset;\n-\n-\t\t/* Find the folio */\n-\t\tfolio = filemap_lock_hugetlb_folio(h, mapping, index);\n-\t\tif (IS_ERR(folio)) {\n-\t\t\t/*\n-\t\t\t * We have a HOLE, zero out the user-buffer for the\n-\t\t\t * length of the hole or request.\n-\t\t\t */\n-\t\t\tcopied = iov_iter_zero(nr, to);\n-\t\t} else {\n-\t\t\tfolio_unlock(folio);\n-\n-\t\t\tif (!folio_test_hwpoison(folio))\n-\t\t\t\twant = nr;\n-\t\t\telse {\n-\t\t\t\t/*\n-\t\t\t\t * Adjust how many bytes safe to read without\n-\t\t\t\t * touching the 1st raw HWPOISON page after\n-\t\t\t\t * offset.\n-\t\t\t\t */\n-\t\t\t\twant = adjust_range_hwpoison(folio, offset, nr);\n-\t\t\t\tif (want == 0) {\n-\t\t\t\t\tfolio_put(folio);\n-\t\t\t\t\tretval = -EIO;\n-\t\t\t\t\tbreak;\n-\t\t\t\t}\n-\t\t\t}\n-\n-\t\t\t/*\n-\t\t\t * We have the folio, copy it to user space buffer.\n-\t\t\t */\n-\t\t\tcopied = copy_folio_to_iter(folio, offset, want, to);\n-\t\t\tfolio_put(folio);\n-\t\t}\n-\t\toffset += copied;\n-\t\tretval += copied;\n-\t\tif (copied != nr \u0026\u0026 iov_iter_count(to)) {\n-\t\t\tif (!retval)\n-\t\t\t\tretval = -EFAULT;\n-\t\t\tbreak;\n-\t\t}\n-\t\tindex += offset \u003e\u003e huge_page_shift(h);\n-\t\toffset \u0026= ~huge_page_mask(h);\n-\t}\n-\tiocb-\u003eki_pos = ((loff_t)index \u003c\u003c huge_page_shift(h)) + offset;\n-\treturn retval;\n-}\n-\n static int hugetlbfs_write_begin(const struct kiocb *iocb,\n \t\t\tstruct address_space *mapping,\n \t\t\tloff_t pos, unsigned len,\n@@ -883,6 +776,17 @@ static struct inode *hugetlbfs_get_root(struct super_block *sb,\n \treturn inode;\n }\n \n+static void hugetlbfs_init_regular_inode(struct inode *inode)\n+{\n+\tstruct hstate *hstate = hstate_inode(inode);\n+\tunsigned int order = huge_page_order(hstate);\n+\n+\tinode-\u003ei_op = \u0026hugetlbfs_inode_operations;\n+\tinode-\u003ei_fop = \u0026hugetlbfs_file_operations;\n+\tmapping_set_folio_order_range(inode-\u003ei_mapping, order, order);\n+\tmapping_set_authoritative(inode-\u003ei_mapping);\n+}\n+\n /*\n * Hugetlbfs is not reclaimable; therefore its i_mmap_rwsem will never\n * be taken from reclaim -- unlike regular filesystems. This needs an\n@@ -926,8 +830,7 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb,\n \t\t\tinit_special_inode(inode, mode, dev);\n \t\t\tbreak;\n \t\tcase S_IFREG:\n-\t\t\tinode-\u003ei_op = \u0026hugetlbfs_inode_operations;\n-\t\t\tinode-\u003ei_fop = \u0026hugetlbfs_file_operations;\n+\t\t\thugetlbfs_init_regular_inode(inode);\n \t\t\tbreak;\n \t\tcase S_IFDIR:\n \t\t\tinode-\u003ei_op = \u0026hugetlbfs_dir_inode_operations;\n@@ -1206,7 +1109,7 @@ static void init_once(void *foo)\n }\n \n static const struct file_operations hugetlbfs_file_operations = {\n-\t.read_iter\t\t= hugetlbfs_read_iter,\n+\t.read_iter\t\t= generic_file_read_iter,\n \t.mmap\t\t\t= hugetlbfs_file_mmap,\n \t.fsync\t\t\t= noop_fsync,\n \t.get_unmapped_area\t= hugetlb_get_unmapped_area,\ndiff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h\nindex 2abaf99321e90d..1878642e75ec51 100644\n--- a/include/linux/hugetlb.h\n+++ b/include/linux/hugetlb.h\n@@ -165,7 +165,7 @@ bool hugetlbfs_pagecache_present(struct hstate *h,\n \t\t\t\t struct vm_area_struct *vma,\n \t\t\t\t unsigned long address);\n \n-struct address_space *hugetlb_folio_mapping_lock_write(struct folio *folio);\n+struct address_space *hugetlb_folio_mapping_lock_write(const struct folio *folio);\n \n extern int movable_gigantic_pages __read_mostly;\n extern int sysctl_hugetlb_shm_group __read_mostly;\n@@ -292,8 +292,7 @@ static inline unsigned long hugetlb_total_pages(void)\n \treturn 0;\n }\n \n-static inline struct address_space *hugetlb_folio_mapping_lock_write(\n-\t\t\t\t\t\t\tstruct folio *folio)\n+static inline struct address_space *hugetlb_folio_mapping_lock_write(const struct folio *folio)\n {\n \treturn NULL;\n }\n@@ -595,8 +594,8 @@ enum hugetlb_page_flags {\n #ifdef CONFIG_HUGETLB_PAGE\n #define TESTHPAGEFLAG(uname, flname)\t\t\t\t\\\n static __always_inline\t\t\t\t\t\t\\\n-bool folio_test_hugetlb_##flname(struct folio *folio)\t\t\\\n-\t{\tvoid *private = \u0026folio-\u003eprivate;\t\t\\\n+bool folio_test_hugetlb_##flname(const struct folio *folio)\t\\\n+\t{\tconst void *private = \u0026folio-\u003eprivate;\t\t\\\n \t\treturn test_bit(HPG_##flname, private);\t\t\\\n \t}\n \n@@ -616,7 +615,7 @@ void folio_clear_hugetlb_##flname(struct folio *folio)\t\t\\\n #else\n #define TESTHPAGEFLAG(uname, flname)\t\t\t\t\\\n static inline bool\t\t\t\t\t\t\\\n-folio_test_hugetlb_##flname(struct folio *folio)\t\t\\\n+folio_test_hugetlb_##flname(const struct folio *folio)\t\t\\\n \t{ return 0; }\n \n #define SETHPAGEFLAG(uname, flname)\t\t\t\t\\\n@@ -727,7 +726,7 @@ static inline struct hugepage_subpool *subpool_inode(struct inode *inode)\n \treturn HUGETLBFS_SB(inode-\u003ei_sb)-\u003espool;\n }\n \n-static inline struct hugepage_subpool *hugetlb_folio_subpool(struct folio *folio)\n+static inline struct hugepage_subpool *hugetlb_folio_subpool(const struct folio *folio)\n {\n \treturn folio-\u003e_hugetlb_subpool;\n }\n@@ -857,7 +856,7 @@ static inline bool arch_has_huge_bootmem_alloc(void)\n }\n #endif\n \n-static inline struct hstate *folio_hstate(struct folio *folio)\n+static inline struct hstate *folio_hstate(const struct folio *folio)\n {\n \tVM_BUG_ON_FOLIO(!folio_test_hugetlb(folio), folio);\n \treturn size_to_hstate(folio_size(folio));\n@@ -1070,11 +1069,6 @@ void hugetlb_register_node(struct node *node);\n void hugetlb_unregister_node(struct node *node);\n #endif\n \n-/*\n- * Check if a given raw @page in a hugepage is HWPOISON.\n- */\n-bool is_raw_hwpoison_page_in_hugepage(struct page *page);\n-\n static inline unsigned long huge_page_mask_align(struct file *file)\n {\n \treturn PAGE_MASK \u0026 ~huge_page_mask(hstate_file(file));\n@@ -1088,7 +1082,7 @@ static inline unsigned long huge_page_mask_align(struct file *file)\n \treturn 0;\n }\n \n-static inline struct hugepage_subpool *hugetlb_folio_subpool(struct folio *folio)\n+static inline struct hugepage_subpool *hugetlb_folio_subpool(const struct folio *folio)\n {\n \treturn NULL;\n }\n@@ -1157,7 +1151,7 @@ static inline struct hstate *hstate_vma(struct vm_area_struct *vma)\n \treturn NULL;\n }\n \n-static inline struct hstate *folio_hstate(struct folio *folio)\n+static inline struct hstate *folio_hstate(const struct folio *folio)\n {\n \treturn NULL;\n }\ndiff --git a/include/linux/mm_types.h b/include/linux/mm_types.h\nindex b18c2b2e7d2c65..86a2d0fee557be 100644\n--- a/include/linux/mm_types.h\n+++ b/include/linux/mm_types.h\n@@ -387,7 +387,7 @@ typedef unsigned short mm_id_t;\n * @_hugetlb_subpool: Do not use directly, use accessor in hugetlb.h.\n * @_hugetlb_cgroup: Do not use directly, use accessor in hugetlb_cgroup.h.\n * @_hugetlb_cgroup_rsvd: Do not use directly, use accessor in hugetlb_cgroup.h.\n- * @_hugetlb_hwpoison: Do not use directly, call raw_hwp_list_head().\n+ * @hugetlb_hwpoison: List of pages with hwpoison.\n * @_deferred_list: Folios to be split under memory pressure.\n * @_unused_slab_obj_exts: Placeholder to match obj_exts in struct slab.\n *\n@@ -499,7 +499,7 @@ struct folio {\n \t\t\tvoid *_hugetlb_subpool;\n \t\t\tvoid *_hugetlb_cgroup;\n \t\t\tvoid *_hugetlb_cgroup_rsvd;\n-\t\t\tvoid *_hugetlb_hwpoison;\n+\t\t\tstruct hwp_page *hugetlb_hwpoison;\n \t/* private: the union with struct page is transitional */\n \t\t};\n \t\tstruct page __page_3;\ndiff --git a/include/linux/page-flags.h b/include/linux/page-flags.h\nindex 7223f6f4e2b403..07cc7854b2de16 100644\n--- a/include/linux/page-flags.h\n+++ b/include/linux/page-flags.h\n@@ -893,14 +893,19 @@ static inline int PageTransCompound(const struct page *page)\n TESTPAGEFLAG_FALSE(TransCompound, transcompound)\n #endif\n \n-#if defined(CONFIG_MEMORY_FAILURE) \u0026\u0026 defined(CONFIG_TRANSPARENT_HUGEPAGE)\n+#if defined(CONFIG_MEMORY_FAILURE) \u0026\u0026 defined(CONFIG_LARGE_FOLIO)\n /*\n- * PageHasHWPoisoned indicates that at least one subpage is hwpoisoned in the\n- * compound page.\n+ * folio_has_hwpoisoned indicates that at least one page is hwpoisoned in the\n+ * folio. That page will usually also have the HWPoison flag set, but this\n+ * is not possible for folios which have HVO (see memory-failure for the\n+ * scheme used in that case). You probably don't want to call this directly;\n+ * use folio_has_hwpoisoned_page() instead.\n *\n * This flag is set by hwpoison handler. Cleared by THP split or free page.\n */\n FOLIO_FLAG(has_hwpoisoned, FOLIO_SECOND_PAGE)\n+FOLIO_TEST_SET_FLAG(has_hwpoisoned, FOLIO_SECOND_PAGE)\n+FOLIO_TEST_CLEAR_FLAG(has_hwpoisoned, FOLIO_SECOND_PAGE)\n #else\n FOLIO_FLAG_FALSE(has_hwpoisoned)\n #endif\n@@ -1041,8 +1046,29 @@ PAGE_TYPE_OPS(Slab, slab, slab)\n \n #ifdef CONFIG_HUGETLB_PAGE\n FOLIO_TYPE_OPS(hugetlb, hugetlb)\n+\n+#ifdef CONFIG_MEMORY_FAILURE\n+static inline bool folio_test_huge_poison(const struct folio *folio)\n+{\n+\treturn (READ_ONCE(folio-\u003epage.page_type) \u003e\u003e 23) ==\n+\t\t((PGTY_hugetlb \u003c\u003c 1) | 1);\n+}\n+\n+static inline void folio_set_huge_poison(struct folio *folio)\n+{\n+\tfolio-\u003epage.page_type |= (1 \u003c\u003c 23);\n+}\n+\n+static inline void folio_clear_huge_poison(struct folio *folio)\n+{\n+\tfolio-\u003epage.page_type \u0026= ~(1 \u003c\u003c 23);\n+}\n+#else\n+FOLIO_TEST_FLAG_FALSE(huge_poison)\n+#endif\n #else\n FOLIO_TEST_FLAG_FALSE(hugetlb)\n+FOLIO_TEST_FLAG_FALSE(huge_poison)\n #endif\n \n PAGE_TYPE_OPS(Zsmalloc, zsmalloc, zsmalloc)\n@@ -1068,10 +1094,14 @@ static inline bool PageHuge(const struct page *page)\n \treturn folio_test_hugetlb(page_folio(page));\n }\n \n+bool hugetlb_page_hwpoison(const struct folio *folio, const struct page *page);\n+bool hugetlb_unref_page_hwpoison(const struct page *page);\n+\n /*\n- * Check if a page is currently marked HWPoisoned. Note that this check is\n- * best effort only and inherently racy: there is no way to synchronize with\n- * failing hardware.\n+ * Check if a page is currently marked HWPoisoned. This check is best\n+ * effort only and inherently racy: there is no way to synchronize with\n+ * failing hardware. The caller may not have a refcount on the folio\n+ * containing the page, so we must be careful to not trip any assertions.\n */\n static inline bool is_page_hwpoison(const struct page *page)\n {\n@@ -1080,13 +1110,26 @@ static inline bool is_page_hwpoison(const struct page *page)\n \tif (PageHWPoison(page))\n \t\treturn true;\n \tfolio = page_folio(page);\n-\treturn folio_test_hugetlb(folio) \u0026\u0026 PageHWPoison(\u0026folio-\u003epage);\n+\tif (folio_test_huge_poison(folio))\n+\t\treturn hugetlb_unref_page_hwpoison(page);\n+\t/* In case we raced with hugetlb transferring flags */\n+\treturn PageHWPoison(page);\n+}\n+\n+static inline bool is_ref_page_hwpoison(const struct folio *folio,\n+\t\tconst struct page *page)\n+{\n+\tif (PageHWPoison(page))\n+\t\treturn true;\n+\tif (folio_test_hugetlb(folio))\n+\t\treturn hugetlb_page_hwpoison(folio, page);\n+\treturn false;\n }\n \n-static inline bool folio_contain_hwpoisoned_page(struct folio *folio)\n+static inline bool folio_has_hwpoisoned_page(const struct folio *folio)\n {\n-\treturn folio_test_hwpoison(folio) ||\n-\t (folio_test_large(folio) \u0026\u0026 folio_test_has_hwpoisoned(folio));\n+\treturn PageHWPoison(\u0026folio-\u003epage) ||\n+\t (folio_test_large(folio) \u0026\u0026 folio_test_has_hwpoisoned(folio));\n }\n \n bool is_free_buddy_page(const struct page *page);\ndiff --git a/include/linux/pagemap.h b/include/linux/pagemap.h\nindex 2c3718d592d6dd..22d48935ffda7c 100644\n--- a/include/linux/pagemap.h\n+++ b/include/linux/pagemap.h\n@@ -210,6 +210,7 @@ enum mapping_flags {\n \tAS_WRITEBACK_MAY_DEADLOCK_ON_RECLAIM = 9,\n \tAS_KERNEL_FILE = 10,\t/* mapping for a fake kernel file that shouldn't\n \t\t\t\t account usage to user cgroups */\n+\tAS_AUTHORITATIVE = 11,\t/* If we miss in the page cache, it's a hole */\n \t/* Bits 16-25 are used for FOLIO_ORDER */\n \tAS_FOLIO_ORDER_BITS = 5,\n \tAS_FOLIO_ORDER_MIN = 16,\n@@ -345,6 +346,16 @@ static inline bool mapping_writeback_may_deadlock_on_reclaim(const struct addres\n \treturn test_bit(AS_WRITEBACK_MAY_DEADLOCK_ON_RECLAIM, \u0026mapping-\u003eflags);\n }\n \n+static inline void mapping_set_authoritative(struct address_space *mapping)\n+{\n+\tset_bit(AS_AUTHORITATIVE, \u0026mapping-\u003eflags);\n+}\n+\n+static inline bool mapping_is_authoritative(const struct address_space *mapping)\n+{\n+\treturn test_bit(AS_AUTHORITATIVE, \u0026mapping-\u003eflags);\n+}\n+\n static inline gfp_t mapping_gfp_mask(const struct address_space *mapping)\n {\n \treturn mapping-\u003egfp_mask;\n@@ -373,7 +384,7 @@ static inline void mapping_set_gfp_mask(struct address_space *m, gfp_t mask)\n * assumptions about maximum order if THP are disabled, but 8 seems like\n * a good order (that's 1MB if you're using 4kB pages)\n */\n-#ifdef CONFIG_TRANSPARENT_HUGEPAGE\n+#ifdef CONFIG_LARGE_FOLIO\n #define PREFERRED_MAX_PAGECACHE_ORDER\tHPAGE_PMD_ORDER\n #else\n #define PREFERRED_MAX_PAGECACHE_ORDER\t8\n@@ -394,7 +405,7 @@ static inline void mapping_set_gfp_mask(struct address_space *m, gfp_t mask)\n */\n static inline size_t mapping_max_folio_size_supported(void)\n {\n-\tif (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE))\n+\tif (IS_ENABLED(CONFIG_LARGE_FOLIO))\n \t\treturn 1U \u003c\u003c (PAGE_SHIFT + MAX_PAGECACHE_ORDER);\n \treturn PAGE_SIZE;\n }\n@@ -405,29 +416,23 @@ static inline size_t mapping_max_folio_size_supported(void)\n * @min: Minimum folio order (between 0-MAX_PAGECACHE_ORDER inclusive).\n * @max: Maximum folio order (between @min-MAX_PAGECACHE_ORDER inclusive).\n *\n- * The filesystem should call this function in its inode constructor to\n- * indicate which base size (min) and maximum size (max) of folio the VFS\n- * can use to cache the contents of the file. This should only be used\n- * if the filesystem needs special handling of folio sizes (ie there is\n- * something the core cannot know).\n+ * The filesystem should call this function in its inode constructor\n+ * to indicate which size folios can be used to cache the contents of\n+ * the inode. This should only be used if the filesystem needs special\n+ * handling of folio sizes (ie there is something the core cannot know).\n * Do not tune it based on, eg, i_size.\n *\n+ * hugetlb calls this with orders larger than MAX_PAGECACHE_ORDER.\n+ * Normal filesystems should not do this.\n+ *\n * Context: This should not be called while the inode is active as it\n * is non-atomic.\n */\n static inline void mapping_set_folio_order_range(struct address_space *mapping,\n-\t\t\t\t\t\t unsigned int min,\n-\t\t\t\t\t\t unsigned int max)\n+\t\tunsigned int min, unsigned int max)\n {\n-\tif (!IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE))\n+\tif (!IS_ENABLED(CONFIG_LARGE_FOLIO))\n \t\treturn;\n-\n-\tif (min \u003e MAX_PAGECACHE_ORDER)\n-\t\tmin = MAX_PAGECACHE_ORDER;\n-\n-\tif (max \u003e MAX_PAGECACHE_ORDER)\n-\t\tmax = MAX_PAGECACHE_ORDER;\n-\n \tif (max \u003c min)\n \t\tmax = min;\n \n@@ -460,7 +465,7 @@ static inline void mapping_set_large_folios(struct address_space *mapping)\n static inline unsigned int\n mapping_max_folio_order(const struct address_space *mapping)\n {\n-\tif (!IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE))\n+\tif (!IS_ENABLED(CONFIG_LARGE_FOLIO))\n \t\treturn 0;\n \treturn (mapping-\u003eflags \u0026 AS_FOLIO_ORDER_MAX_MASK) \u003e\u003e AS_FOLIO_ORDER_MAX;\n }\n@@ -468,7 +473,7 @@ mapping_max_folio_order(const struct address_space *mapping)\n static inline unsigned int\n mapping_min_folio_order(const struct address_space *mapping)\n {\n-\tif (!IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE))\n+\tif (!IS_ENABLED(CONFIG_LARGE_FOLIO))\n \t\treturn 0;\n \treturn (mapping-\u003eflags \u0026 AS_FOLIO_ORDER_MIN_MASK) \u003e\u003e AS_FOLIO_ORDER_MIN;\n }\n@@ -524,7 +529,7 @@ static inline bool mapping_large_folio_support(const struct address_space *mappi\n *\n * Return: True if PMD-sized folios are supported, otherwise false.\n */\n-#ifdef CONFIG_TRANSPARENT_HUGEPAGE\n+#ifdef CONFIG_LARGE_FOLIO\n static inline bool mapping_pmd_folio_support(const struct address_space *mapping)\n {\n \t/* AS_FOLIO_ORDER is only reasonable for pagecache folios */\ndiff --git a/mm/Kconfig b/mm/Kconfig\nindex 9e0ca48249054f..e666dd14ca0c3d 100644\n--- a/mm/Kconfig\n+++ b/mm/Kconfig\n@@ -843,11 +843,15 @@ config PERSISTENT_HUGE_ZERO_FOLIO\n config MM_ID\n \tdef_bool n\n \n+config LARGE_FOLIO\n+\tdef_bool n\n+\tselect XARRAY_MULTI\n+\n menuconfig TRANSPARENT_HUGEPAGE\n \tbool \"Transparent Hugepage Support\"\n \tdepends on HAVE_ARCH_TRANSPARENT_HUGEPAGE \u0026\u0026 !PREEMPT_RT\n \tselect COMPACTION\n-\tselect XARRAY_MULTI\n+\tselect LARGE_FOLIO\n \tselect MM_ID\n \thelp\n \t Transparent Hugepages allows the kernel to use huge pages and\ndiff --git a/mm/filemap.c b/mm/filemap.c\nindex 58eb9d24064348..5a8cc20e624e4d 100644\n--- a/mm/filemap.c\n+++ b/mm/filemap.c\n@@ -2483,6 +2483,8 @@ static void filemap_get_read_batch(struct address_space *mapping,\n \n \t\tif (!folio_batch_add(fbatch, folio))\n \t\t\tbreak;\n+\t\tif (folio_has_hwpoisoned_page(folio))\n+\t\t\tbreak;\n \t\tif (!folio_test_uptodate(folio))\n \t\t\tbreak;\n \t\tif (folio_test_readahead(folio))\n@@ -2695,6 +2697,8 @@ static int filemap_get_pages(struct kiocb *iocb, size_t count,\n \tif (!folio_batch_count(fbatch)) {\n \t\tDEFINE_READAHEAD(ractl, filp, \u0026filp-\u003ef_ra, mapping, index);\n \n+\t\tif (mapping_is_authoritative(mapping))\n+\t\t\treturn 0;\n \t\tif (iocb-\u003eki_flags \u0026 IOCB_NOIO)\n \t\t\treturn -EAGAIN;\n \t\tif (iocb-\u003eki_flags \u0026 IOCB_NOWAIT)\n@@ -2749,6 +2753,29 @@ static inline bool pos_same_folio(loff_t pos1, loff_t pos2, struct folio *folio)\n \treturn (pos1 \u003e\u003e shift == pos2 \u003e\u003e shift);\n }\n \n+static size_t adjust_range_hwpoison(const struct folio *folio, size_t offset,\n+\t\tsize_t bytes)\n+{\n+\tconst struct page *page = folio_page(folio, offset / PAGE_SIZE);\n+\tsize_t safe_bytes;\n+\n+\tif (!folio_has_hwpoisoned_page(folio))\n+\t\treturn bytes;\n+\tif (is_ref_page_hwpoison(folio, page))\n+\t\treturn 0;\n+\n+\t/* Safe to read the remaining bytes in this page. */\n+\tsafe_bytes = PAGE_SIZE - (offset % PAGE_SIZE);\n+\tpage++;\n+\n+\t/* Check each remaining page as long as we are not done yet. */\n+\tfor (; safe_bytes \u003c bytes; safe_bytes += PAGE_SIZE, page++)\n+\t\tif (is_ref_page_hwpoison(folio, page))\n+\t\t\tbreak;\n+\n+\treturn min(safe_bytes, bytes);\n+}\n+\n static void filemap_end_dropbehind_read(struct folio *folio)\n {\n \tif (!folio_test_dropbehind(folio))\n@@ -2828,6 +2855,22 @@ ssize_t filemap_read(struct kiocb *iocb, struct iov_iter *iter,\n \t\t\tgoto put_folios;\n \t\tend_offset = min_t(loff_t, isize, iocb-\u003eki_pos + iter-\u003ecount);\n \n+\t\tif (!folio_batch_count(\u0026fbatch)) {\n+\t\t\tsize_t fsize = mapping_min_folio_nrbytes(mapping);\n+\t\t\tsize_t offset = iocb-\u003eki_pos \u0026 (fsize - 1);\n+\t\t\tsize_t bytes = min_t(loff_t, end_offset - iocb-\u003eki_pos,\n+\t\t\t\t\t fsize - offset);\n+\t\t\tsize_t copied = iov_iter_zero(bytes, iter);\n+\n+\t\t\talready_read += copied;\n+\t\t\tiocb-\u003eki_pos += copied;\n+\t\t\tlast_pos = iocb-\u003eki_pos;\n+\n+\t\t\tif (copied \u003c bytes)\n+\t\t\t\terror = -EFAULT;\n+\t\t\tcontinue;\n+\t\t}\n+\n \t\t/*\n \t\t * Once we start copying data, we don't want to be touching any\n \t\t * cachelines that might be contended:\n@@ -2862,14 +2905,18 @@ ssize_t filemap_read(struct kiocb *iocb, struct iov_iter *iter,\n \t\t\tif (writably_mapped)\n \t\t\t\tflush_dcache_folio(folio);\n \n-\t\t\tcopied = copy_folio_to_iter(folio, offset, bytes, iter);\n+\t\t\tcopied = adjust_range_hwpoison(folio, offset, bytes);\n+\t\t\tif (copied \u003c bytes)\n+\t\t\t\terror = -EIO;\n+\t\t\tcopied = copy_folio_to_iter(folio, offset, copied, iter);\n \n \t\t\talready_read += copied;\n \t\t\tiocb-\u003eki_pos += copied;\n \t\t\tlast_pos = iocb-\u003eki_pos;\n \n \t\t\tif (copied \u003c bytes) {\n-\t\t\t\terror = -EFAULT;\n+\t\t\t\tif (!error)\n+\t\t\t\t\terror = -EFAULT;\n \t\t\t\tbreak;\n \t\t\t}\n \t\t}\ndiff --git a/mm/huge_memory.c b/mm/huge_memory.c\nindex 2bccb0a53a0a60..3533403091074c 100644\n--- a/mm/huge_memory.c\n+++ b/mm/huge_memory.c\n@@ -4413,7 +4413,7 @@ static bool thp_underused(struct folio *folio)\n \tif (khugepaged_max_ptes_none == HPAGE_PMD_NR - 1)\n \t\treturn false;\n \n-\tif (folio_contain_hwpoisoned_page(folio))\n+\tif (folio_has_hwpoisoned_page(folio))\n \t\treturn false;\n \n \tfor (i = 0; i \u003c folio_nr_pages(folio); i++) {\ndiff --git a/mm/hugetlb.c b/mm/hugetlb.c\nindex 571212b80835ec..aaac6e2af4c24a 100644\n--- a/mm/hugetlb.c\n+++ b/mm/hugetlb.c\n@@ -1255,7 +1255,7 @@ static struct folio *dequeue_hugetlb_folio_node_exact(struct hstate *h,\n \t\tif (pin \u0026\u0026 !folio_is_longterm_pinnable(folio))\n \t\t\tcontinue;\n \n-\t\tif (folio_test_hwpoison(folio))\n+\t\tif (folio_test_has_hwpoisoned(folio))\n \t\t\tcontinue;\n \n \t\tif (is_migrate_isolate_page(\u0026folio-\u003epage))\n@@ -1498,10 +1498,10 @@ static void __update_and_free_hugetlb_folio(struct hstate *h,\n \t}\n \n \t/*\n-\t * Move PageHWPoison flag from head page to the raw error pages,\n-\t * which makes any healthy subpages reusable.\n+\t * Move HWPoison flag to each error page\n+\t * which makes any healthy pages reusable.\n \t */\n-\tif (unlikely(folio_test_hwpoison(folio)))\n+\tif (unlikely(folio_test_has_hwpoisoned(folio)))\n \t\tfolio_clear_hugetlb_hwpoison(folio);\n \n \tVM_BUG_ON_FOLIO(folio_ref_count(folio), folio);\n@@ -1775,7 +1775,7 @@ void init_new_hugetlb_folio(struct folio *folio)\n * stable. Due to locking order, we can only trylock_write. If we can\n * not get the lock, simply return NULL to caller.\n */\n-struct address_space *hugetlb_folio_mapping_lock_write(struct folio *folio)\n+struct address_space *hugetlb_folio_mapping_lock_write(const struct folio *folio)\n {\n \tstruct address_space *mapping = folio_mapping(folio);\n \n@@ -3998,7 +3998,7 @@ long demote_pool_huge_page(struct hstate *src, nodemask_t *nodes_allowed,\n \t\tstruct folio *folio, *next;\n \n \t\tlist_for_each_entry_safe(folio, next, \u0026src-\u003ehugepage_freelists[node], lru) {\n-\t\t\tif (folio_test_hwpoison(folio))\n+\t\t\tif (folio_test_has_hwpoisoned(folio))\n \t\t\t\tcontinue;\n \n \t\t\tremove_hugetlb_folio(src, folio, false);\n@@ -5809,7 +5809,7 @@ static vm_fault_t hugetlb_no_page(struct address_space *mapping,\n \t\t * don't have hwpoisoned swap entry for errored virtual address.\n \t\t * So we need to block hugepage fault by PG_hwpoison bit check.\n \t\t */\n-\t\tif (unlikely(folio_test_hwpoison(folio))) {\n+\t\tif (unlikely(folio_test_has_hwpoisoned(folio))) {\n \t\t\tret = VM_FAULT_HWPOISON_LARGE |\n \t\t\t\tVM_FAULT_SET_HINDEX(hstate_index(h));\n \t\t\tgoto backout_unlocked;\n@@ -6318,7 +6318,7 @@ int hugetlb_mfill_atomic_pte(pte_t *dst_pte,\n \tptl = huge_pte_lock(h, dst_mm, dst_pte);\n \n \tret = -EIO;\n-\tif (folio_test_hwpoison(folio))\n+\tif (folio_test_has_hwpoisoned(folio))\n \t\tgoto out_release_unlock;\n \n \tret = -EEXIST;\ndiff --git a/mm/memory-failure.c b/mm/memory-failure.c\nindex 51508a55c4055e..32f91935b21070 100644\n--- a/mm/memory-failure.c\n+++ b/mm/memory-failure.c\n@@ -1808,63 +1808,86 @@ EXPORT_SYMBOL_GPL(mf_dax_kill_procs);\n \n #ifdef CONFIG_HUGETLB_PAGE\n \n+/* Protects all lists of hwp_pages */\n+static DEFINE_SPINLOCK(hwp_page_lock);\n+\n /*\n- * Struct raw_hwp_page represents information about \"raw error page\",\n- * constructing singly linked list from -\u003e_hugetlb_hwpoison field of folio.\n+ * hwp_page represents information about \"error page\",\n+ * constructing singly linked list from folio-\u003ehugetlb_hwpoison field.\n */\n-struct raw_hwp_page {\n-\tstruct llist_node node;\n+struct hwp_page {\n+\tstruct hwp_page *next;\n \tstruct page *page;\n };\n \n-static inline struct llist_head *raw_hwp_list_head(struct folio *folio)\n+static bool precise_page_poisoned(const struct folio *folio,\n+\t\tconst struct page *page)\n {\n-\treturn (struct llist_head *)\u0026folio-\u003e_hugetlb_hwpoison;\n-}\n-\n-bool is_raw_hwpoison_page_in_hugepage(struct page *page)\n-{\n-\tstruct llist_head *raw_hwp_head;\n-\tstruct raw_hwp_page *p;\n-\tstruct folio *folio = page_folio(page);\n-\tbool ret = false;\n-\n-\tif (!folio_test_hwpoison(folio))\n-\t\treturn false;\n-\n-\tif (!folio_test_hugetlb(folio))\n-\t\treturn PageHWPoison(page);\n+\tconst struct hwp_page *p;\n+\tunsigned long flags;\n \n \t/*\n-\t * When RawHwpUnreliable is set, kernel lost track of which subpages\n-\t * are HWPOISON. So return as if ALL subpages are HWPOISONed.\n+\t * When RawHwpUnreliable is set, kernel lost track of which pages\n+\t * are HWPOISON. So return as if ALL pages are HWPOISONed.\n \t */\n \tif (folio_test_hugetlb_raw_hwp_unreliable(folio))\n \t\treturn true;\n \n-\tmutex_lock(\u0026mf_mutex);\n-\n-\traw_hwp_head = raw_hwp_list_head(folio);\n-\tllist_for_each_entry(p, raw_hwp_head-\u003efirst, node) {\n-\t\tif (page == p-\u003epage) {\n-\t\t\tret = true;\n+\tspin_lock_irqsave(\u0026hwp_page_lock, flags);\n+\tfor (p = folio-\u003ehugetlb_hwpoison; p; p = p-\u003enext) {\n+\t\tif (page == p-\u003epage)\n \t\t\tbreak;\n-\t\t}\n \t}\n+\tspin_unlock_irqrestore(\u0026hwp_page_lock, flags);\n \n-\tmutex_unlock(\u0026mf_mutex);\n+\treturn p != NULL;\n+}\n \n+/*\n+ * Check if a given @page in a hugetlb folio is HWPOISON.\n+ */\n+bool hugetlb_page_hwpoison(const struct folio *folio, const struct page *page)\n+{\n+\tif (!folio_test_has_hwpoisoned(folio))\n+\t\treturn false;\n+\n+\treturn precise_page_poisoned(folio, page);\n+}\n+\n+/*\n+ * We have no reference on the folio containing this page.\n+ * The hugetlb_lock keeps hugetlb folios from being freed.\n+ */\n+bool hugetlb_unref_page_hwpoison(const struct page *page)\n+{\n+\tconst struct folio *folio;\n+\tunsigned long flags;\n+\tbool ret;\n+\n+\tspin_lock_irqsave(\u0026hugetlb_lock, flags);\n+\tfolio = page_folio(page);\n+\tif (!folio_test_huge_poison(folio)) {\n+\t\tret = PageHWPoison(page);\n+\t\tgoto unlock;\n+\t}\n+\n+\tret = precise_page_poisoned(folio, page);\n+unlock:\n+\tspin_unlock_irqrestore(\u0026hugetlb_lock, flags);\n \treturn ret;\n }\n \n static unsigned long __folio_free_raw_hwp(struct folio *folio, bool move_flag)\n {\n-\tstruct llist_node *head;\n-\tstruct raw_hwp_page *p, *next;\n+\tstruct hwp_page *p, *next;\n \tunsigned long count = 0;\n \n-\thead = llist_del_all(raw_hwp_list_head(folio));\n-\tllist_for_each_entry_safe(p, next, head, node) {\n+\tnext = folio-\u003ehugetlb_hwpoison;\n+\tfolio-\u003ehugetlb_hwpoison = NULL;\n+\n+\twhile (next) {\n+\t\tp = next;\n+\t\tnext = p-\u003enext;\n \t\tif (move_flag)\n \t\t\tSetPageHWPoison(p-\u003epage);\n \t\telse\n@@ -1881,34 +1904,58 @@ static unsigned long __folio_free_raw_hwp(struct folio *folio, bool move_flag)\n #define\tMF_HUGETLB_FOLIO_PRE_POISONED\t3\t/* folio already poisoned */\n #define\tMF_HUGETLB_PAGE_PRE_POISONED\t4\t/* exact page already poisoned */\n #define\tMF_HUGETLB_RETRY\t\t5\t/* hugepage is busy, retry */\n+\n+static inline int hugetlb_set_poison(struct folio *folio)\n+{\n+\tif (folio_test_set_has_hwpoisoned(folio))\n+\t\treturn MF_HUGETLB_FOLIO_PRE_POISONED;\n+\tfolio_set_huge_poison(folio);\n+\treturn 0;\n+}\n+\n+static inline int hugetlb_clear_poison(struct folio *folio)\n+{\n+\tif (!folio_test_has_hwpoisoned(folio))\n+\t\treturn -EBUSY;\n+\tfolio_clear_huge_poison(folio);\n+\tfolio_clear_has_hwpoisoned(folio);\n+\treturn 0;\n+}\n+\n /*\n * Set hugetlb folio as hwpoisoned, update folio private raw hwpoison list\n * to keep track of the poisoned pages.\n */\n static int hugetlb_update_hwpoison(struct folio *folio, struct page *page)\n {\n-\tstruct llist_head *head;\n-\tstruct raw_hwp_page *raw_hwp;\n-\tstruct raw_hwp_page *p;\n-\tint ret = folio_test_set_hwpoison(folio) ? MF_HUGETLB_FOLIO_PRE_POISONED : 0;\n+\tstruct hwp_page *p;\n+\tunsigned long flags;\n+\tint ret = hugetlb_set_poison(folio);\n \n \t/*\n \t * Once the hwpoison hugepage has lost reliable raw error info,\n-\t * there is little meaning to keep additional error info precisely,\n-\t * so skip to add additional raw error info.\n+\t * there is no point in keeping additional error info precisely,\n+\t * so skip adding additional raw error info.\n \t */\n \tif (folio_test_hugetlb_raw_hwp_unreliable(folio))\n \t\treturn MF_HUGETLB_FOLIO_PRE_POISONED;\n-\thead = raw_hwp_list_head(folio);\n-\tllist_for_each_entry(p, head-\u003efirst, node) {\n+\n+\tspin_lock_irqsave(\u0026hwp_page_lock, flags);\n+\tfor (p = folio-\u003ehugetlb_hwpoison; p; p = p-\u003enext) {\n \t\tif (p-\u003epage == page)\n-\t\t\treturn MF_HUGETLB_PAGE_PRE_POISONED;\n+\t\t\tbreak;\n+\t}\n+\n+\tif (p) {\n+\t\tspin_unlock_irqrestore(\u0026hwp_page_lock, flags);\n+\t\treturn MF_HUGETLB_PAGE_PRE_POISONED;\n \t}\n \n-\traw_hwp = kmalloc_obj(struct raw_hwp_page, GFP_ATOMIC);\n-\tif (raw_hwp) {\n-\t\traw_hwp-\u003epage = page;\n-\t\tllist_add(\u0026raw_hwp-\u003enode, head);\n+\tp = kmalloc_obj(*p, GFP_ATOMIC);\n+\tif (p) {\n+\t\tp-\u003epage = page;\n+\t\tp-\u003enext = folio-\u003ehugetlb_hwpoison;\n+\t\tfolio-\u003ehugetlb_hwpoison = p;\n \t} else {\n \t\t/*\n \t\t * Failed to save raw error info. We no longer trace all\n@@ -1917,16 +1964,20 @@ static int hugetlb_update_hwpoison(struct folio *folio, struct page *page)\n \t\t */\n \t\tfolio_set_hugetlb_raw_hwp_unreliable(folio);\n \t\t/*\n-\t\t * Once hugetlb_raw_hwp_unreliable is set, raw_hwp_page is not\n+\t\t * Once hugetlb_raw_hwp_unreliable is set, hwp_page is not\n \t\t * used any more, so free it.\n \t\t */\n \t\t__folio_free_raw_hwp(folio, false);\n \t}\n+\tspin_unlock_irqrestore(\u0026hwp_page_lock, flags);\n \treturn ret;\n }\n \n static unsigned long folio_free_raw_hwp(struct folio *folio, bool move_flag)\n {\n+\tunsigned long count;\n+\tunsigned long flags;\n+\n \t/*\n \t * hugetlb_vmemmap_optimized hugepages can't be freed because struct\n \t * pages for tail pages are required but they don't exist.\n@@ -1941,7 +1992,11 @@ static unsigned long folio_free_raw_hwp(struct folio *folio, bool move_flag)\n \tif (folio_test_hugetlb_raw_hwp_unreliable(folio))\n \t\treturn 0;\n \n-\treturn __folio_free_raw_hwp(folio, move_flag);\n+\tspin_lock_irqsave(\u0026hwp_page_lock, flags);\n+\tcount = __folio_free_raw_hwp(folio, move_flag);\n+\tspin_unlock_irqrestore(\u0026hwp_page_lock, flags);\n+\n+\treturn count;\n }\n \n void folio_clear_hugetlb_hwpoison(struct folio *folio)\n@@ -1950,8 +2005,8 @@ void folio_clear_hugetlb_hwpoison(struct folio *folio)\n \t\treturn;\n \tif (folio_test_hugetlb_vmemmap_optimized(folio))\n \t\treturn;\n-\tfolio_clear_hwpoison(folio);\n \tfolio_free_raw_hwp(folio, true);\n+\tfolio_clear_has_hwpoisoned(folio);\n }\n \n static int get_huge_page_for_hwpoison(unsigned long pfn, int flags,\n@@ -2104,6 +2159,11 @@ static inline unsigned long folio_free_raw_hwp(struct folio *folio, bool flag)\n {\n \treturn 0;\n }\n+\n+static inline int hugetlb_clear_poison(struct folio *folio)\n+{\n+\treturn 0;\n+}\n #endif\t/* CONFIG_HUGETLB_PAGE */\n \n /* Drop the extra refcount in case we come from madvise() */\n@@ -2695,8 +2755,8 @@ int unpoison_memory(unsigned long pfn)\n \t\tgoto unlock_mutex;\n \t}\n \n-\tif (!PageHWPoison(p)) {\n-\t\tunpoison_pr_info(\"%#lx: page was already unpoisoned\\n\",\n+\tif (!is_page_hwpoison(p)) {\n+\t\tunpoison_pr_info(\"%#lx: page is not poisoned\\n\",\n \t\t\t\t pfn, \u0026unpoison_rs);\n \t\tgoto unlock_mutex;\n \t}\n@@ -2730,8 +2790,8 @@ int unpoison_memory(unsigned long pfn)\n \t\t\tcount = folio_free_raw_hwp(folio, false);\n \t\t\tif (count == 0)\n \t\t\t\tgoto unlock_mutex;\n+\t\t\tret = hugetlb_clear_poison(folio);\n \t\t}\n-\t\tret = folio_test_clear_hwpoison(folio) ? 0 : -EBUSY;\n \t} else if (ghp \u003c 0) {\n \t\tif (ghp == -EHWPOISON) {\n \t\t\tret = put_page_back_buddy(p) ? 0 : -EBUSY;\n@@ -2740,16 +2800,18 @@ int unpoison_memory(unsigned long pfn)\n \t\t\tunpoison_pr_info(\"%#lx: failed to grab page\\n\",\n \t\t\t\t\t pfn, \u0026unpoison_rs);\n \t\t}\n-\t} else {\n-\t\tif (folio_test_hugetlb(folio)) {\n-\t\t\thuge = true;\n-\t\t\tcount = folio_free_raw_hwp(folio, false);\n-\t\t\tif (count == 0) {\n-\t\t\t\tfolio_put(folio);\n-\t\t\t\tgoto unlock_mutex;\n-\t\t\t}\n+\t} else if (folio_test_hugetlb(folio)) {\n+\t\thuge = true;\n+\t\tcount = folio_free_raw_hwp(folio, false);\n+\t\tif (count == 0) {\n+\t\t\tfolio_put(folio);\n+\t\t\tgoto unlock_mutex;\n \t\t}\n-\n+\t\tfolio_put(folio);\n+\t\tret = hugetlb_clear_poison(folio);\n+\t\tif (!ret)\n+\t\t\tfolio_put(folio);\n+\t} else {\n \t\tfolio_put(folio);\n \t\tif (TestClearPageHWPoison(p)) {\n \t\t\tfolio_put(folio);\ndiff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c\nindex 7ac19fab226324..33007e8e546a09 100644\n--- a/mm/memory_hotplug.c\n+++ b/mm/memory_hotplug.c\n@@ -1813,7 +1813,7 @@ static void do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)\n \t\tif (folio_test_large(folio))\n \t\t\tpfn = folio_pfn(folio) + folio_nr_pages(folio) - 1;\n \n-\t\tif (folio_contain_hwpoisoned_page(folio)) {\n+\t\tif (folio_has_hwpoisoned_page(folio)) {\n \t\t\t/*\n \t\t\t * unmap_poisoned_folio() cannot handle large folios\n \t\t\t * in all cases yet.\ndiff --git a/mm/rmap.c b/mm/rmap.c\nindex 1c77d5dc06e9fa..fd19a0bfbfe76c 100644\n--- a/mm/rmap.c\n+++ b/mm/rmap.c\n@@ -1978,6 +1978,22 @@ static inline unsigned int folio_unmap_pte_batch(struct folio *folio,\n \t\t\t\t FPB_RESPECT_WRITE | FPB_RESPECT_SOFT_DIRTY);\n }\n \n+/*\n+ * Since we cannot split a hugetlb folio, we want to insert a poison\n+ * entry into the page table for the whole folio even if only one page\n+ * is poisoned. Otherwise, we've split down to the PTE level and we only\n+ * want to poison the precise page\n+ */\n+static bool ttu_create_hwpoison(const struct folio *folio,\n+\t\tconst struct page *page, enum ttu_flags flags)\n+{\n+\tif (!(flags \u0026 TTU_HWPOISON))\n+\t\treturn false;\n+\tif (folio_test_hugetlb(folio))\n+\t\treturn folio_test_has_hwpoisoned(folio);\n+\treturn PageHWPoison(page);\n+}\n+\n /*\n * @arg: enum ttu_flags will be passed to this argument\n */\n@@ -1993,7 +2009,6 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,\n \tenum ttu_flags flags = (enum ttu_flags)(long)arg;\n \tunsigned long nr_pages = 1, end_addr;\n \tunsigned long pfn;\n-\tunsigned long hsz = 0;\n \tint ptes = 0;\n \n \t/*\n@@ -2023,9 +2038,6 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,\n \t\t */\n \t\tadjust_range_if_pmd_sharing_possible(vma, \u0026range.start,\n \t\t\t\t\t\t \u0026range.end);\n-\n-\t\t/* We need the huge page size for set_huge_pte_at() */\n-\t\thsz = huge_page_size(hstate_vma(vma));\n \t}\n \tmmu_notifier_invalidate_range_start(\u0026range);\n \n@@ -2121,7 +2133,8 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,\n \t\t\t * The try_to_unmap() is only passed a hugetlb page\n \t\t\t * in the case where the hugetlb page is poisoned.\n \t\t\t */\n-\t\t\tVM_BUG_ON_PAGE(!PageHWPoison(subpage), subpage);\n+\t\t\tVM_BUG_ON_FOLIO(!folio_has_hwpoisoned_page(folio),\n+\t\t\t\t\tfolio);\n \t\t\t/*\n \t\t\t * huge_pmd_unshare may unmap an entire PMD page.\n \t\t\t * There is no way of knowing exactly which PMDs may\n@@ -2200,12 +2213,12 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,\n \t\t/* Update high watermark before we lower rss */\n \t\tupdate_hiwater_rss(mm);\n \n-\t\tif (PageHWPoison(subpage) \u0026\u0026 (flags \u0026 TTU_HWPOISON)) {\n+\t\tif (ttu_create_hwpoison(folio, subpage, flags)) {\n \t\t\tpteval = swp_entry_to_pte(make_hwpoison_entry(subpage));\n \t\t\tif (folio_test_hugetlb(folio)) {\n \t\t\t\thugetlb_count_sub(folio_nr_pages(folio), mm);\n \t\t\t\tset_huge_pte_at(mm, address, pvmw.pte, pteval,\n-\t\t\t\t\t\thsz);\n+\t\t\t\t\t\tfolio_size(folio));\n \t\t\t} else {\n \t\t\t\tdec_mm_counter(mm, mm_counter(folio));\n \t\t\t\tset_pte_at(mm, address, pvmw.pte, pteval);\n@@ -2423,7 +2436,6 @@ static bool try_to_migrate_one(struct folio *folio, struct vm_area_struct *vma,\n \tstruct mmu_notifier_range range;\n \tenum ttu_flags flags = (enum ttu_flags)(long)arg;\n \tunsigned long pfn;\n-\tunsigned long hsz = 0;\n \n \t/*\n \t * When racing against e.g. zap_pte_range() on another cpu,\n@@ -2452,9 +2464,6 @@ static bool try_to_migrate_one(struct folio *folio, struct vm_area_struct *vma,\n \t\t */\n \t\tadjust_range_if_pmd_sharing_possible(vma, \u0026range.start,\n \t\t\t\t\t\t \u0026range.end);\n-\n-\t\t/* We need the huge page size for set_huge_pte_at() */\n-\t\thsz = huge_page_size(hstate_vma(vma));\n \t}\n \tmmu_notifier_invalidate_range_start(\u0026range);\n \n@@ -2607,14 +2616,14 @@ static bool try_to_migrate_one(struct folio *folio, struct vm_area_struct *vma,\n \t\t/* Update high watermark before we lower rss */\n \t\tupdate_hiwater_rss(mm);\n \n-\t\tif (PageHWPoison(subpage)) {\n+\t\tif (ttu_create_hwpoison(folio, subpage, TTU_HWPOISON)) {\n \t\t\tVM_WARN_ON_FOLIO(folio_is_device_private(folio), folio);\n \n \t\t\tpteval = swp_entry_to_pte(make_hwpoison_entry(subpage));\n \t\t\tif (folio_test_hugetlb(folio)) {\n \t\t\t\thugetlb_count_sub(folio_nr_pages(folio), mm);\n \t\t\t\tset_huge_pte_at(mm, address, pvmw.pte, pteval,\n-\t\t\t\t\t\thsz);\n+\t\t\t\t\t\tfolio_size(folio));\n \t\t\t} else {\n \t\t\t\tdec_mm_counter(mm, mm_counter(folio));\n \t\t\t\tset_pte_at(mm, address, pvmw.pte, pteval);\n@@ -2644,7 +2653,8 @@ static bool try_to_migrate_one(struct folio *folio, struct vm_area_struct *vma,\n \t\t\tif (arch_unmap_one(mm, vma, address, pteval) \u003c 0) {\n \t\t\t\tif (folio_test_hugetlb(folio))\n \t\t\t\t\tset_huge_pte_at(mm, address, pvmw.pte,\n-\t\t\t\t\t\t\tpteval, hsz);\n+\t\t\t\t\t\t\tpteval,\n+\t\t\t\t\t\t\tfolio_size(folio));\n \t\t\t\telse\n \t\t\t\t\tset_pte_at(mm, address, pvmw.pte, pteval);\n \t\t\t\tret = false;\n@@ -2657,7 +2667,8 @@ static bool try_to_migrate_one(struct folio *folio, struct vm_area_struct *vma,\n \t\t\t\tif (anon_exclusive \u0026\u0026\n \t\t\t\t hugetlb_try_share_anon_rmap(folio)) {\n \t\t\t\t\tset_huge_pte_at(mm, address, pvmw.pte,\n-\t\t\t\t\t\t\tpteval, hsz);\n+\t\t\t\t\t\t\tpteval,\n+\t\t\t\t\t\t\tfolio_size(folio));\n \t\t\t\t\tret = false;\n \t\t\t\t\tpage_vma_mapped_walk_done(\u0026pvmw);\n \t\t\t\t\tbreak;\n@@ -2703,7 +2714,7 @@ static bool try_to_migrate_one(struct folio *folio, struct vm_area_struct *vma,\n \t\t\t}\n \t\t\tif (folio_test_hugetlb(folio))\n \t\t\t\tset_huge_pte_at(mm, address, pvmw.pte, swp_pte,\n-\t\t\t\t\t\thsz);\n+\t\t\t\t\t\tfolio_size(folio));\n \t\t\telse\n \t\t\t\tset_pte_at(mm, address, pvmw.pte, swp_pte);\n \t\t\ttrace_set_migration_pte(address, pte_val(swp_pte),\ndiff --git a/mm/shmem.c b/mm/shmem.c\nindex b51f83c970bb37..492c9bef362074 100644\n--- a/mm/shmem.c\n+++ b/mm/shmem.c\n@@ -3240,7 +3240,7 @@ shmem_write_begin(const struct kiocb *iocb, struct address_space *mapping,\n \tif (ret)\n \t\treturn ret;\n \n-\tif (folio_contain_hwpoisoned_page(folio)) {\n+\tif (folio_has_hwpoisoned_page(folio)) {\n \t\tfolio_unlock(folio);\n \t\tfolio_put(folio);\n \t\treturn -EIO;\ndiff --git a/mm/vmscan.c b/mm/vmscan.c\nindex 35c3bb15ae96a3..70e54ace0e741c 100644\n--- a/mm/vmscan.c\n+++ b/mm/vmscan.c\n@@ -1086,7 +1086,7 @@ static unsigned int shrink_folio_list(struct list_head *folio_list,\n \t\tif (!folio_trylock(folio))\n \t\t\tgoto keep;\n \n-\t\tif (folio_contain_hwpoisoned_page(folio)) {\n+\t\tif (folio_has_hwpoisoned_page(folio)) {\n \t\t\t/*\n \t\t\t * unmap_poisoned_folio() can't handle large\n \t\t\t * folio, just skip it. memory_failure() will\ndiff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c\nindex db57c5766ab604..94eedcc7f1a9e0 100644\n--- a/virt/kvm/guest_memfd.c\n+++ b/virt/kvm/guest_memfd.c\n@@ -774,7 +774,7 @@ static struct folio *__kvm_gmem_get_pfn(struct file *file,\n \tif (IS_ERR(folio))\n \t\treturn folio;\n \n-\tif (folio_test_hwpoison(folio)) {\n+\tif (folio_has_hwpoisoned_page(folio)) {\n \t\tfolio_unlock(folio);\n \t\tfolio_put(folio);\n \t\treturn ERR_PTR(-EHWPOISON);\n"
} |
| 2/1 | 2026/07/26 17:51 | agent | patch-evaluator |
2mModel:best-expensive Args: null Results: {
"EnableConfigs": [
"HUGETLBFS",
"MEMORY_FAILURE",
"TRANSPARENT_HUGEPAGE"
],
"FocusSymbols": [
"hugetlb_page_hwpoison",
"hugetlb_unref_page_hwpoison",
"unpoison_memory",
"folio_clear_hugetlb_hwpoison"
],
"Reasoning": "The patch series introduces `LARGE_FOLIO` config and refactors how hwpoison is tracked for hugetlb folios. It replaces `adjust_range_hwpoison` in `fs/hugetlbfs/inode.c` with a generic one in `mm/filemap.c` and changes `hugetlbfs_read_iter` to `generic_file_read_iter`. It also modifies `folio_test_hwpoison` to `folio_has_hwpoisoned_page` in various places. These are functional changes to core kernel logic (mm, hugetlbfs, memory-failure) and 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 9b856ebd47ac50107c996236928dac5b63b3e96b
Author: syz-cluster <triage@syzkaller.com>
Date: Sun Jul 26 17:51:35 2026 +0000
syz-cluster: applied patch under review
diff --git a/fs/Kconfig b/fs/Kconfig
index cf6ae64776e62c..eddac4ed214b12 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -272,7 +272,7 @@ endif # HUGETLBFS
config HUGETLB_PAGE
def_bool HUGETLBFS
- select XARRAY_MULTI
+ select LARGE_FOLIO
config HUGETLB_PAGE_OPTIMIZE_VMEMMAP
def_bool HUGETLB_PAGE
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 216e1a0dd0b237..cef7e61b827d71 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -187,113 +187,6 @@ hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
return mm_get_unmapped_area_vmflags(file, addr0, len, pgoff, flags, 0);
}
-/*
- * Someone wants to read @bytes from a HWPOISON hugetlb @folio from @offset.
- * Returns the maximum number of bytes one can read without touching the 1st raw
- * HWPOISON page.
- */
-static size_t adjust_range_hwpoison(struct folio *folio, size_t offset,
- size_t bytes)
-{
- struct page *page = folio_page(folio, offset / PAGE_SIZE);
- size_t safe_bytes;
-
- if (is_raw_hwpoison_page_in_hugepage(page))
- return 0;
- /* Safe to read the remaining bytes in this page. */
- safe_bytes = PAGE_SIZE - (offset % PAGE_SIZE);
- page++;
-
- /* Check each remaining page as long as we are not done yet. */
- for (; safe_bytes < bytes; safe_bytes += PAGE_SIZE, page++)
- if (is_raw_hwpoison_page_in_hugepage(page))
- break;
-
- return min(safe_bytes, bytes);
-}
-
-/*
- * Support for read() - Find the page attached to f_mapping and copy out the
- * data. This provides functionality similar to filemap_read().
- */
-static ssize_t hugetlbfs_read_iter(struct kiocb *iocb, struct iov_iter *to)
-{
- struct file *file = iocb->ki_filp;
- struct hstate *h = hstate_file(file);
- struct address_space *mapping = file->f_mapping;
- struct inode *inode = mapping->host;
- unsigned long index = iocb->ki_pos >> huge_page_shift(h);
- unsigned long offset = iocb->ki_pos & ~huge_page_mask(h);
- unsigned long end_index;
- loff_t isize;
- ssize_t retval = 0;
-
- while (iov_iter_count(to)) {
- struct folio *folio;
- size_t nr, copied, want;
-
- /* nr is the maximum number of bytes to copy from this page */
- nr = huge_page_size(h);
- isize = i_size_read(inode);
- if (!isize)
- break;
- end_index = (isize - 1) >> huge_page_shift(h);
- if (index > end_index)
- break;
- if (index == end_index) {
- nr = ((isize - 1) & ~huge_page_mask(h)) + 1;
- if (nr <= offset)
- break;
- }
- nr = nr - offset;
-
- /* Find the folio */
- folio = filemap_lock_hugetlb_folio(h, mapping, index);
- if (IS_ERR(folio)) {
- /*
- * We have a HOLE, zero out the user-buffer for the
- * length of the hole or request.
- */
- copied = iov_iter_zero(nr, to);
- } else {
- folio_unlock(folio);
-
- if (!folio_test_hwpoison(folio))
- want = nr;
- else {
- /*
- * Adjust how many bytes safe to read without
- * touching the 1st raw HWPOISON page after
- * offset.
- */
- want = adjust_range_hwpoison(folio, offset, nr);
- if (want == 0) {
- folio_put(folio);
- retval = -EIO;
- break;
- }
- }
-
- /*
- * We have the folio, copy it to user space buffer.
- */
- copied = copy_folio_to_iter(folio, offset, want, to);
- folio_put(folio);
- }
- offset += copied;
- retval += copied;
- if (copied != nr && iov_iter_count(to)) {
- if (!retval)
- retval = -EFAULT;
- break;
- }
- index += offset >> huge_page_shift(h);
- offset &= ~huge_page_mask(h);
- }
- iocb->ki_pos = ((loff_t)index << huge_page_shift(h)) + offset;
- return retval;
-}
-
static int hugetlbfs_write_begin(const struct kiocb *iocb,
struct address_space *mapping,
loff_t pos, unsigned len,
@@ -883,6 +776,17 @@ static struct inode *hugetlbfs_get_root(struct super_block *sb,
return inode;
}
+static void hugetlbfs_init_regular_inode(struct inode *inode)
+{
+ struct hstate *hstate = hstate_inode(inode);
+ unsigned int order = huge_page_order(hstate);
+
+ inode->i_op = &hugetlbfs_inode_operations;
+ inode->i_fop = &hugetlbfs_file_operations;
+ mapping_set_folio_order_range(inode->i_mapping, order, order);
+ mapping_set_authoritative(inode->i_mapping);
+}
+
/*
* Hugetlbfs is not reclaimable; therefore its i_mmap_rwsem will never
* be taken from reclaim -- unlike regular filesystems. This needs an
@@ -926,8 +830,7 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb,
init_special_inode(inode, mode, dev);
break;
case S_IFREG:
- inode->i_op = &hugetlbfs_inode_operations;
- inode->i_fop = &hugetlbfs_file_operations;
+ hugetlbfs_init_regular_inode(inode);
break;
case S_IFDIR:
inode->i_op = &hugetlbfs_dir_inode_operations;
@@ -1206,7 +1109,7 @@ static void init_once(void *foo)
}
static const struct file_operations hugetlbfs_file_operations = {
- .read_iter = hugetlbfs_read_iter,
+ .read_iter = generic_file_read_iter,
.mmap = hugetlbfs_file_mmap,
.fsync = noop_fsync,
.get_unmapped_area = hugetlb_get_unmapped_area,
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
index 2abaf99321e90d..1878642e75ec51 100644
--- a/include/linux/hugetlb.h
+++ b/include/linux/hugetlb.h
@@ -165,7 +165,7 @@ bool hugetlbfs_pagecache_present(struct hstate *h,
struct vm_area_struct *vma,
unsigned long address);
-struct address_space *hugetlb_folio_mapping_lock_write(struct folio *folio);
+struct address_space *hugetlb_folio_mapping_lock_write(const struct folio *folio);
extern int movable_gigantic_pages __read_mostly;
extern int sysctl_hugetlb_shm_group __read_mostly;
@@ -292,8 +292,7 @@ static inline unsigned long hugetlb_total_pages(void)
return 0;
}
-static inline struct address_space *hugetlb_folio_mapping_lock_write(
- struct folio *folio)
+static inline struct address_space *hugetlb_folio_mapping_lock_write(const struct folio *folio)
{
return NULL;
}
@@ -595,8 +594,8 @@ enum hugetlb_page_flags {
#ifdef CONFIG_HUGETLB_PAGE
#define TESTHPAGEFLAG(uname, flname) \
static __always_inline \
-bool folio_test_hugetlb_##flname(struct folio *folio) \
- { void *private = &folio->private; \
+bool folio_test_hugetlb_##flname(const struct folio *folio) \
+ { const void *private = &folio->private; \
return test_bit(HPG_##flname, private); \
}
@@ -616,7 +615,7 @@ void folio_clear_hugetlb_##flname(struct folio *folio) \
#else
#define TESTHPAGEFLAG(uname, flname) \
static inline bool \
-folio_test_hugetlb_##flname(struct folio *folio) \
+folio_test_hugetlb_##flname(const struct folio *folio) \
{ return 0; }
#define SETHPAGEFLAG(uname, flname) \
@@ -727,7 +726,7 @@ static inline struct hugepage_subpool *subpool_inode(struct inode *inode)
return HUGETLBFS_SB(inode->i_sb)->spool;
}
-static inline struct hugepage_subpool *hugetlb_folio_subpool(struct folio *folio)
+static inline struct hugepage_subpool *hugetlb_folio_subpool(const struct folio *folio)
{
return folio->_hugetlb_subpool;
}
@@ -857,7 +856,7 @@ static inline bool arch_has_huge_bootmem_alloc(void)
}
#endif
-static inline struct hstate *folio_hstate(struct folio *folio)
+static inline struct hstate *folio_hstate(const struct folio *folio)
{
VM_BUG_ON_FOLIO(!folio_test_hugetlb(folio), folio);
return size_to_hstate(folio_size(folio));
@@ -1070,11 +1069,6 @@ void hugetlb_register_node(struct node *node);
void hugetlb_unregister_node(struct node *node);
#endif
-/*
- * Check if a given raw @page in a hugepage is HWPOISON.
- */
-bool is_raw_hwpoison_page_in_hugepage(struct page *page);
-
static inline unsigned long huge_page_mask_align(struct file *file)
{
return PAGE_MASK & ~huge_page_mask(hstate_file(file));
@@ -1088,7 +1082,7 @@ static inline unsigned long huge_page_mask_align(struct file *file)
return 0;
}
-static inline struct hugepage_subpool *hugetlb_folio_subpool(struct folio *folio)
+static inline struct hugepage_subpool *hugetlb_folio_subpool(const struct folio *folio)
{
return NULL;
}
@@ -1157,7 +1151,7 @@ static inline struct hstate *hstate_vma(struct vm_area_struct *vma)
return NULL;
}
-static inline struct hstate *folio_hstate(struct folio *folio)
+static inline struct hstate *folio_hstate(const struct folio *folio)
{
return NULL;
}
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index b18c2b2e7d2c65..86a2d0fee557be 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -387,7 +387,7 @@ typedef unsigned short mm_id_t;
* @_hugetlb_subpool: Do not use directly, use accessor in hugetlb.h.
* @_hugetlb_cgroup: Do not use directly, use accessor in hugetlb_cgroup.h.
* @_hugetlb_cgroup_rsvd: Do not use directly, use accessor in hugetlb_cgroup.h.
- * @_hugetlb_hwpoison: Do not use directly, call raw_hwp_list_head().
+ * @hugetlb_hwpoison: List of pages with hwpoison.
* @_deferred_list: Folios to be split under memory pressure.
* @_unused_slab_obj_exts: Placeholder to match obj_exts in struct slab.
*
@@ -499,7 +499,7 @@ struct folio {
void *_hugetlb_subpool;
void *_hugetlb_cgroup;
void *_hugetlb_cgroup_rsvd;
- void *_hugetlb_hwpoison;
+ struct hwp_page *hugetlb_hwpoison;
/* private: the union with struct page is transitional */
};
struct page __page_3;
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
index 7223f6f4e2b403..07cc7854b2de16 100644
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -893,14 +893,19 @@ static inline int PageTransCompound(const struct page *page)
TESTPAGEFLAG_FALSE(TransCompound, transcompound)
#endif
-#if defined(CONFIG_MEMORY_FAILURE) && defined(CONFIG_TRANSPARENT_HUGEPAGE)
+#if defined(CONFIG_MEMORY_FAILURE) && defined(CONFIG_LARGE_FOLIO)
/*
- * PageHasHWPoisoned indicates that at least one subpage is hwpoisoned in the
- * compound page.
+ * folio_has_hwpoisoned indicates that at least one page is hwpoisoned in the
+ * folio. That page will usually also have the HWPoison flag set, but this
+ * is not possible for folios which have HVO (see memory-failure for the
+ * scheme used in that case). You probably don't want to call this directly;
+ * use folio_has_hwpoisoned_page() instead.
*
* This flag is set by hwpoison handler. Cleared by THP split or free page.
*/
FOLIO_FLAG(has_hwpoisoned, FOLIO_SECOND_PAGE)
+FOLIO_TEST_SET_FLAG(has_hwpoisoned, FOLIO_SECOND_PAGE)
+FOLIO_TEST_CLEAR_FLAG(has_hwpoisoned, FOLIO_SECOND_PAGE)
#else
FOLIO_FLAG_FALSE(has_hwpoisoned)
#endif
@@ -1041,8 +1046,29 @@ PAGE_TYPE_OPS(Slab, slab, slab)
#ifdef CONFIG_HUGETLB_PAGE
FOLIO_TYPE_OPS(hugetlb, hugetlb)
+
+#ifdef CONFIG_MEMORY_FAILURE
+static inline bool folio_test_huge_poison(const struct folio *folio)
+{
+ return (READ_ONCE(folio->page.page_type) >> 23) ==
+ ((PGTY_hugetlb << 1) | 1);
+}
+
+static inline void folio_set_huge_poison(struct folio *folio)
+{
+ folio->page.page_type |= (1 << 23);
+}
+
+static inline void folio_clear_huge_poison(struct folio *folio)
+{
+ folio->page.page_type &= ~(1 << 23);
+}
+#else
+FOLIO_TEST_FLAG_FALSE(huge_poison)
+#endif
#else
FOLIO_TEST_FLAG_FALSE(hugetlb)
+FOLIO_TEST_FLAG_FALSE(huge_poison)
#endif
PAGE_TYPE_OPS(Zsmalloc, zsmalloc, zsmalloc)
@@ -1068,10 +1094,14 @@ static inline bool PageHuge(const struct page *page)
return folio_test_hugetlb(page_folio(page));
}
+bool hugetlb_page_hwpoison(const struct folio *folio, const struct page *page);
+bool hugetlb_unref_page_hwpoison(const struct page *page);
+
/*
- * Check if a page is currently marked HWPoisoned. Note that this check is
- * best effort only and inherently racy: there is no way to synchronize with
- * failing hardware.
+ * Check if a page is currently marked HWPoisoned. This check is best
+ * effort only and inherently racy: there is no way to synchronize with
+ * failing hardware. The caller may not have a refcount on the folio
+ * containing the page, so we must be careful to not trip any assertions.
*/
static inline bool is_page_hwpoison(const struct page *page)
{
@@ -1080,13 +1110,26 @@ static inline bool is_page_hwpoison(const struct page *page)
if (PageHWPoison(page))
return true;
folio = page_folio(page);
- return folio_test_hugetlb(folio) && PageHWPoison(&folio->page);
+ if (folio_test_huge_poison(folio))
+ return hugetlb_unref_page_hwpoison(page);
+ /* In case we raced with hugetlb transferring flags */
+ return PageHWPoison(page);
+}
+
+static inline bool is_ref_page_hwpoison(const struct folio *folio,
+ const struct page *page)
+{
+ if (PageHWPoison(page))
+ return true;
+ if (folio_test_hugetlb(folio))
+ return hugetlb_page_hwpoison(folio, page);
+ return false;
}
-static inline bool folio_contain_hwpoisoned_page(struct folio *folio)
+static inline bool folio_has_hwpoisoned_page(const struct folio *folio)
{
- return folio_test_hwpoison(folio) ||
- (folio_test_large(folio) && folio_test_has_hwpoisoned(folio));
+ return PageHWPoison(&folio->page) ||
+ (folio_test_large(folio) && folio_test_has_hwpoisoned(folio));
}
bool is_free_buddy_page(const struct page *page);
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index 2c3718d592d6dd..22d48935ffda7c 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -210,6 +210,7 @@ enum mapping_flags {
AS_WRITEBACK_MAY_DEADLOCK_ON_RECLAIM = 9,
AS_KERNEL_FILE = 10, /* mapping for a fake kernel file that shouldn't
account usage to user cgroups */
+ AS_AUTHORITATIVE = 11, /* If we miss in the page cache, it's a hole */
/* Bits 16-25 are used for FOLIO_ORDER */
AS_FOLIO_ORDER_BITS = 5,
AS_FOLIO_ORDER_MIN = 16,
@@ -345,6 +346,16 @@ static inline bool mapping_writeback_may_deadlock_on_reclaim(const struct addres
return test_bit(AS_WRITEBACK_MAY_DEADLOCK_ON_RECLAIM, &mapping->flags);
}
+static inline void mapping_set_authoritative(struct address_space *mapping)
+{
+ set_bit(AS_AUTHORITATIVE, &mapping->flags);
+}
+
+static inline bool mapping_is_authoritative(const struct address_space *mapping)
+{
+ return test_bit(AS_AUTHORITATIVE, &mapping->flags);
+}
+
static inline gfp_t mapping_gfp_mask(const struct address_space *mapping)
{
return mapping->gfp_mask;
@@ -373,7 +384,7 @@ static inline void mapping_set_gfp_mask(struct address_space *m, gfp_t mask)
* assumptions about maximum order if THP are disabled, but 8 seems like
* a good order (that's 1MB if you're using 4kB pages)
*/
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+#ifdef CONFIG_LARGE_FOLIO
#define PREFERRED_MAX_PAGECACHE_ORDER HPAGE_PMD_ORDER
#else
#define PREFERRED_MAX_PAGECACHE_ORDER 8
@@ -394,7 +405,7 @@ static inline void mapping_set_gfp_mask(struct address_space *m, gfp_t mask)
*/
static inline size_t mapping_max_folio_size_supported(void)
{
- if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE))
+ if (IS_ENABLED(CONFIG_LARGE_FOLIO))
return 1U << (PAGE_SHIFT + MAX_PAGECACHE_ORDER);
return PAGE_SIZE;
}
@@ -405,29 +416,23 @@ static inline size_t mapping_max_folio_size_supported(void)
* @min: Minimum folio order (between 0-MAX_PAGECACHE_ORDER inclusive).
* @max: Maximum folio order (between @min-MAX_PAGECACHE_ORDER inclusive).
*
- * The filesystem should call this function in its inode constructor to
- * indicate which base size (min) and maximum size (max) of folio the VFS
- * can use to cache the contents of the file. This should only be used
- * if the filesystem needs special handling of folio sizes (ie there is
- * something the core cannot know).
+ * The filesystem should call this function in its inode constructor
+ * to indicate which size folios can be used to cache the contents of
+ * the inode. This should only be used if the filesystem needs special
+ * handling of folio sizes (ie there is something the core cannot know).
* Do not tune it based on, eg, i_size.
*
+ * hugetlb calls this with orders larger than MAX_PAGECACHE_ORDER.
+ * Normal filesystems should not do this.
+ *
* Context: This should not be called while the inode is active as it
* is non-atomic.
*/
static inline void mapping_set_folio_order_range(struct address_space *mapping,
- unsigned int min,
- unsigned int max)
+ unsigned int min, unsigned int max)
{
- if (!IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE))
+ if (!IS_ENABLED(CONFIG_LARGE_FOLIO))
return;
-
- if (min > MAX_PAGECACHE_ORDER)
- min = MAX_PAGECACHE_ORDER;
-
- if (max > MAX_PAGECACHE_ORDER)
- max = MAX_PAGECACHE_ORDER;
-
if (max < min)
max = min;
@@ -460,7 +465,7 @@ static inline void mapping_set_large_folios(struct address_space *mapping)
static inline unsigned int
mapping_max_folio_order(const struct address_space *mapping)
{
- if (!IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE))
+ if (!IS_ENABLED(CONFIG_LARGE_FOLIO))
return 0;
return (mapping->flags & AS_FOLIO_ORDER_MAX_MASK) >> AS_FOLIO_ORDER_MAX;
}
@@ -468,7 +473,7 @@ mapping_max_folio_order(const struct address_space *mapping)
static inline unsigned int
mapping_min_folio_order(const struct address_space *mapping)
{
- if (!IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE))
+ if (!IS_ENABLED(CONFIG_LARGE_FOLIO))
return 0;
return (mapping->flags & AS_FOLIO_ORDER_MIN_MASK) >> AS_FOLIO_ORDER_MIN;
}
@@ -524,7 +529,7 @@ static inline bool mapping_large_folio_support(const struct address_space *mappi
*
* Return: True if PMD-sized folios are supported, otherwise false.
*/
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+#ifdef CONFIG_LARGE_FOLIO
static inline bool mapping_pmd_folio_support(const struct address_space *mapping)
{
/* AS_FOLIO_ORDER is only reasonable for pagecache folios */
diff --git a/mm/Kconfig b/mm/Kconfig
index 9e0ca48249054f..e666dd14ca0c3d 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -843,11 +843,15 @@ config PERSISTENT_HUGE_ZERO_FOLIO
config MM_ID
def_bool n
+config LARGE_FOLIO
+ def_bool n
+ select XARRAY_MULTI
+
menuconfig TRANSPARENT_HUGEPAGE
bool "Transparent Hugepage Support"
depends on HAVE_ARCH_TRANSPARENT_HUGEPAGE && !PREEMPT_RT
select COMPACTION
- select XARRAY_MULTI
+ select LARGE_FOLIO
select MM_ID
help
Transparent Hugepages allows the kernel to use huge pages and
diff --git a/mm/filemap.c b/mm/filemap.c
index 58eb9d24064348..5a8cc20e624e4d 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -2483,6 +2483,8 @@ static void filemap_get_read_batch(struct address_space *mapping,
if (!folio_batch_add(fbatch, folio))
break;
+ if (folio_has_hwpoisoned_page(folio))
+ break;
if (!folio_test_uptodate(folio))
break;
if (folio_test_readahead(folio))
@@ -2695,6 +2697,8 @@ static int filemap_get_pages(struct kiocb *iocb, size_t count,
if (!folio_batch_count(fbatch)) {
DEFINE_READAHEAD(ractl, filp, &filp->f_ra, mapping, index);
+ if (mapping_is_authoritative(mapping))
+ return 0;
if (iocb->ki_flags & IOCB_NOIO)
return -EAGAIN;
if (iocb->ki_flags & IOCB_NOWAIT)
@@ -2749,6 +2753,29 @@ static inline bool pos_same_folio(loff_t pos1, loff_t pos2, struct folio *folio)
return (pos1 >> shift == pos2 >> shift);
}
+static size_t adjust_range_hwpoison(const struct folio *folio, size_t offset,
+ size_t bytes)
+{
+ const struct page *page = folio_page(folio, offset / PAGE_SIZE);
+ size_t safe_bytes;
+
+ if (!folio_has_hwpoisoned_page(folio))
+ return bytes;
+ if (is_ref_page_hwpoison(folio, page))
+ return 0;
+
+ /* Safe to read the remaining bytes in this page. */
+ safe_bytes = PAGE_SIZE - (offset % PAGE_SIZE);
+ page++;
+
+ /* Check each remaining page as long as we are not done yet. */
+ for (; safe_bytes < bytes; safe_bytes += PAGE_SIZE, page++)
+ if (is_ref_page_hwpoison(folio, page))
+ break;
+
+ return min(safe_bytes, bytes);
+}
+
static void filemap_end_dropbehind_read(struct folio *folio)
{
if (!folio_test_dropbehind(folio))
@@ -2828,6 +2855,22 @@ ssize_t filemap_read(struct kiocb *iocb, struct iov_iter *iter,
goto put_folios;
end_offset = min_t(loff_t, isize, iocb->ki_pos + iter->count);
+ if (!folio_batch_count(&fbatch)) {
+ size_t fsize = mapping_min_folio_nrbytes(mapping);
+ size_t offset = iocb->ki_pos & (fsize - 1);
+ size_t bytes = min_t(loff_t, end_offset - iocb->ki_pos,
+ fsize - offset);
+ size_t copied = iov_iter_zero(bytes, iter);
+
+ already_read += copied;
+ iocb->ki_pos += copied;
+ last_pos = iocb->ki_pos;
+
+ if (copied < bytes)
+ error = -EFAULT;
+ continue;
+ }
+
/*
* Once we start copying data, we don't want to be touching any
* cachelines that might be contended:
@@ -2862,14 +2905,18 @@ ssize_t filemap_read(struct kiocb *iocb, struct iov_iter *iter,
if (writably_mapped)
flush_dcache_folio(folio);
- copied = copy_folio_to_iter(folio, offset, bytes, iter);
+ copied = adjust_range_hwpoison(folio, offset, bytes);
+ if (copied < bytes)
+ error = -EIO;
+ copied = copy_folio_to_iter(folio, offset, copied, iter);
already_read += copied;
iocb->ki_pos += copied;
last_pos = iocb->ki_pos;
if (copied < bytes) {
- error = -EFAULT;
+ if (!error)
+ error = -EFAULT;
break;
}
}
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 2bccb0a53a0a60..3533403091074c 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -4413,7 +4413,7 @@ static bool thp_underused(struct folio *folio)
if (khugepaged_max_ptes_none == HPAGE_PMD_NR - 1)
return false;
- if (folio_contain_hwpoisoned_page(folio))
+ if (folio_has_hwpoisoned_page(folio))
return false;
for (i = 0; i < folio_nr_pages(folio); i++) {
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 571212b80835ec..aaac6e2af4c24a 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -1255,7 +1255,7 @@ static struct folio *dequeue_hugetlb_folio_node_exact(struct hstate *h,
if (pin && !folio_is_longterm_pinnable(folio))
continue;
- if (folio_test_hwpoison(folio))
+ if (folio_test_has_hwpoisoned(folio))
continue;
if (is_migrate_isolate_page(&folio->page))
@@ -1498,10 +1498,10 @@ static void __update_and_free_hugetlb_folio(struct hstate *h,
}
/*
- * Move PageHWPoison flag from head page to the raw error pages,
- * which makes any healthy subpages reusable.
+ * Move HWPoison flag to each error page
+ * which makes any healthy pages reusable.
*/
- if (unlikely(folio_test_hwpoison(folio)))
+ if (unlikely(folio_test_has_hwpoisoned(folio)))
folio_clear_hugetlb_hwpoison(folio);
VM_BUG_ON_FOLIO(folio_ref_count(folio), folio);
@@ -1775,7 +1775,7 @@ void init_new_hugetlb_folio(struct folio *folio)
* stable. Due to locking order, we can only trylock_write. If we can
* not get the lock, simply return NULL to caller.
*/
-struct address_space *hugetlb_folio_mapping_lock_write(struct folio *folio)
+struct address_space *hugetlb_folio_mapping_lock_write(const struct folio *folio)
{
struct address_space *mapping = folio_mapping(folio);
@@ -3998,7 +3998,7 @@ long demote_pool_huge_page(struct hstate *src, nodemask_t *nodes_allowed,
struct folio *folio, *next;
list_for_each_entry_safe(folio, next, &src->hugepage_freelists[node], lru) {
- if (folio_test_hwpoison(folio))
+ if (folio_test_has_hwpoisoned(folio))
continue;
remove_hugetlb_folio(src, folio, false);
@@ -5809,7 +5809,7 @@ static vm_fault_t hugetlb_no_page(struct address_space *mapping,
* don't have hwpoisoned swap entry for errored virtual address.
* So we need to block hugepage fault by PG_hwpoison bit check.
*/
- if (unlikely(folio_test_hwpoison(folio))) {
+ if (unlikely(folio_test_has_hwpoisoned(folio))) {
ret = VM_FAULT_HWPOISON_LARGE |
VM_FAULT_SET_HINDEX(hstate_index(h));
goto backout_unlocked;
@@ -6318,7 +6318,7 @@ int hugetlb_mfill_atomic_pte(pte_t *dst_pte,
ptl = huge_pte_lock(h, dst_mm, dst_pte);
ret = -EIO;
- if (folio_test_hwpoison(folio))
+ if (folio_test_has_hwpoisoned(folio))
goto out_release_unlock;
ret = -EEXIST;
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index 51508a55c4055e..32f91935b21070 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -1808,63 +1808,86 @@ EXPORT_SYMBOL_GPL(mf_dax_kill_procs);
#ifdef CONFIG_HUGETLB_PAGE
+/* Protects all lists of hwp_pages */
+static DEFINE_SPINLOCK(hwp_page_lock);
+
/*
- * Struct raw_hwp_page represents information about "raw error page",
- * constructing singly linked list from ->_hugetlb_hwpoison field of folio.
+ * hwp_page represents information about "error page",
+ * constructing singly linked list from folio->hugetlb_hwpoison field.
*/
-struct raw_hwp_page {
- struct llist_node node;
+struct hwp_page {
+ struct hwp_page *next;
struct page *page;
};
-static inline struct llist_head *raw_hwp_list_head(struct folio *folio)
+static bool precise_page_poisoned(const struct folio *folio,
+ const struct page *page)
{
- return (struct llist_head *)&folio->_hugetlb_hwpoison;
-}
-
-bool is_raw_hwpoison_page_in_hugepage(struct page *page)
-{
- struct llist_head *raw_hwp_head;
- struct raw_hwp_page *p;
- struct folio *folio = page_folio(page);
- bool ret = false;
-
- if (!folio_test_hwpoison(folio))
- return false;
-
- if (!folio_test_hugetlb(folio))
- return PageHWPoison(page);
+ const struct hwp_page *p;
+ unsigned long flags;
/*
- * When RawHwpUnreliable is set, kernel lost track of which subpages
- * are HWPOISON. So return as if ALL subpages are HWPOISONed.
+ * When RawHwpUnreliable is set, kernel lost track of which pages
+ * are HWPOISON. So return as if ALL pages are HWPOISONed.
*/
if (folio_test_hugetlb_raw_hwp_unreliable(folio))
return true;
- mutex_lock(&mf_mutex);
-
- raw_hwp_head = raw_hwp_list_head(folio);
- llist_for_each_entry(p, raw_hwp_head->first, node) {
- if (page == p->page) {
- ret = true;
+ spin_lock_irqsave(&hwp_page_lock, flags);
+ for (p = folio->hugetlb_hwpoison; p; p = p->next) {
+ if (page == p->page)
break;
- }
}
+ spin_unlock_irqrestore(&hwp_page_lock, flags);
- mutex_unlock(&mf_mutex);
+ return p != NULL;
+}
+/*
+ * Check if a given @page in a hugetlb folio is HWPOISON.
+ */
+bool hugetlb_page_hwpoison(const struct folio *folio, const struct page *page)
+{
+ if (!folio_test_has_hwpoisoned(folio))
+ return false;
+
+ return precise_page_poisoned(folio, page);
+}
+
+/*
+ * We have no reference on the folio containing this page.
+ * The hugetlb_lock keeps hugetlb folios from being freed.
+ */
+bool hugetlb_unref_page_hwpoison(const struct page *page)
+{
+ const struct folio *folio;
+ unsigned long flags;
+ bool ret;
+
+ spin_lock_irqsave(&hugetlb_lock, flags);
+ folio = page_folio(page);
+ if (!folio_test_huge_poison(folio)) {
+ ret = PageHWPoison(page);
+ goto unlock;
+ }
+
+ ret = precise_page_poisoned(folio, page);
+unlock:
+ spin_unlock_irqrestore(&hugetlb_lock, flags);
return ret;
}
static unsigned long __folio_free_raw_hwp(struct folio *folio, bool move_flag)
{
- struct llist_node *head;
- struct raw_hwp_page *p, *next;
+ struct hwp_page *p, *next;
unsigned long count = 0;
- head = llist_del_all(raw_hwp_list_head(folio));
- llist_for_each_entry_safe(p, next, head, node) {
+ next = folio->hugetlb_hwpoison;
+ folio->hugetlb_hwpoison = NULL;
+
+ while (next) {
+ p = next;
+ next = p->next;
if (move_flag)
SetPageHWPoison(p->page);
else
@@ -1881,34 +1904,58 @@ static unsigned long __folio_free_raw_hwp(struct folio *folio, bool move_flag)
#define MF_HUGETLB_FOLIO_PRE_POISONED 3 /* folio already poisoned */
#define MF_HUGETLB_PAGE_PRE_POISONED 4 /* exact page already poisoned */
#define MF_HUGETLB_RETRY 5 /* hugepage is busy, retry */
+
+static inline int hugetlb_set_poison(struct folio *folio)
+{
+ if (folio_test_set_has_hwpoisoned(folio))
+ return MF_HUGETLB_FOLIO_PRE_POISONED;
+ folio_set_huge_poison(folio);
+ return 0;
+}
+
+static inline int hugetlb_clear_poison(struct folio *folio)
+{
+ if (!folio_test_has_hwpoisoned(folio))
+ return -EBUSY;
+ folio_clear_huge_poison(folio);
+ folio_clear_has_hwpoisoned(folio);
+ return 0;
+}
+
/*
* Set hugetlb folio as hwpoisoned, update folio private raw hwpoison list
* to keep track of the poisoned pages.
*/
static int hugetlb_update_hwpoison(struct folio *folio, struct page *page)
{
- struct llist_head *head;
- struct raw_hwp_page *raw_hwp;
- struct raw_hwp_page *p;
- int ret = folio_test_set_hwpoison(folio) ? MF_HUGETLB_FOLIO_PRE_POISONED : 0;
+ struct hwp_page *p;
+ unsigned long flags;
+ int ret = hugetlb_set_poison(folio);
/*
* Once the hwpoison hugepage has lost reliable raw error info,
- * there is little meaning to keep additional error info precisely,
- * so skip to add additional raw error info.
+ * there is no point in keeping additional error info precisely,
+ * so skip adding additional raw error info.
*/
if (folio_test_hugetlb_raw_hwp_unreliable(folio))
return MF_HUGETLB_FOLIO_PRE_POISONED;
- head = raw_hwp_list_head(folio);
- llist_for_each_entry(p, head->first, node) {
+
+ spin_lock_irqsave(&hwp_page_lock, flags);
+ for (p = folio->hugetlb_hwpoison; p; p = p->next) {
if (p->page == page)
- return MF_HUGETLB_PAGE_PRE_POISONED;
+ break;
+ }
+
+ if (p) {
+ spin_unlock_irqrestore(&hwp_page_lock, flags);
+ return MF_HUGETLB_PAGE_PRE_POISONED;
}
- raw_hwp = kmalloc_obj(struct raw_hwp_page, GFP_ATOMIC);
- if (raw_hwp) {
- raw_hwp->page = page;
- llist_add(&raw_hwp->node, head);
+ p = kmalloc_obj(*p, GFP_ATOMIC);
+ if (p) {
+ p->page = page;
+ p->next = folio->hugetlb_hwpoison;
+ folio->hugetlb_hwpoison = p;
} else {
/*
* Failed to save raw error info. We no longer trace all
@@ -1917,16 +1964,20 @@ static int hugetlb_update_hwpoison(struct folio *folio, struct page *page)
*/
folio_set_hugetlb_raw_hwp_unreliable(folio);
/*
- * Once hugetlb_raw_hwp_unreliable is set, raw_hwp_page is not
+ * Once hugetlb_raw_hwp_unreliable is set, hwp_page is not
* used any more, so free it.
*/
__folio_free_raw_hwp(folio, false);
}
+ spin_unlock_irqrestore(&hwp_page_lock, flags);
return ret;
}
static unsigned long folio_free_raw_hwp(struct folio *folio, bool move_flag)
{
+ unsigned long count;
+ unsigned long flags;
+
/*
* hugetlb_vmemmap_optimized hugepages can't be freed because struct
* pages for tail pages are required but they don't exist.
@@ -1941,7 +1992,11 @@ static unsigned long folio_free_raw_hwp(struct folio *folio, bool move_flag)
if (folio_test_hugetlb_raw_hwp_unreliable(folio))
return 0;
- return __folio_free_raw_hwp(folio, move_flag);
+ spin_lock_irqsave(&hwp_page_lock, flags);
+ count = __folio_free_raw_hwp(folio, move_flag);
+ spin_unlock_irqrestore(&hwp_page_lock, flags);
+
+ return count;
}
void folio_clear_hugetlb_hwpoison(struct folio *folio)
@@ -1950,8 +2005,8 @@ void folio_clear_hugetlb_hwpoison(struct folio *folio)
return;
if (folio_test_hugetlb_vmemmap_optimized(folio))
return;
- folio_clear_hwpoison(folio);
folio_free_raw_hwp(folio, true);
+ folio_clear_has_hwpoisoned(folio);
}
static int get_huge_page_for_hwpoison(unsigned long pfn, int flags,
@@ -2104,6 +2159,11 @@ static inline unsigned long folio_free_raw_hwp(struct folio *folio, bool flag)
{
return 0;
}
+
+static inline int hugetlb_clear_poison(struct folio *folio)
+{
+ return 0;
+}
#endif /* CONFIG_HUGETLB_PAGE */
/* Drop the extra refcount in case we come from madvise() */
@@ -2695,8 +2755,8 @@ int unpoison_memory(unsigned long pfn)
goto unlock_mutex;
}
- if (!PageHWPoison(p)) {
- unpoison_pr_info("%#lx: page was already unpoisoned\n",
+ if (!is_page_hwpoison(p)) {
+ unpoison_pr_info("%#lx: page is not poisoned\n",
pfn, &unpoison_rs);
goto unlock_mutex;
}
@@ -2730,8 +2790,8 @@ int unpoison_memory(unsigned long pfn)
count = folio_free_raw_hwp(folio, false);
if (count == 0)
goto unlock_mutex;
+ ret = hugetlb_clear_poison(folio);
}
- ret = folio_test_clear_hwpoison(folio) ? 0 : -EBUSY;
} else if (ghp < 0) {
if (ghp == -EHWPOISON) {
ret = put_page_back_buddy(p) ? 0 : -EBUSY;
@@ -2740,16 +2800,18 @@ int unpoison_memory(unsigned long pfn)
unpoison_pr_info("%#lx: failed to grab page\n",
pfn, &unpoison_rs);
}
- } else {
- if (folio_test_hugetlb(folio)) {
- huge = true;
- count = folio_free_raw_hwp(folio, false);
- if (count == 0) {
- folio_put(folio);
- goto unlock_mutex;
- }
+ } else if (folio_test_hugetlb(folio)) {
+ huge = true;
+ count = folio_free_raw_hwp(folio, false);
+ if (count == 0) {
+ folio_put(folio);
+ goto unlock_mutex;
}
-
+ folio_put(folio);
+ ret = hugetlb_clear_poison(folio);
+ if (!ret)
+ folio_put(folio);
+ } else {
folio_put(folio);
if (TestClearPageHWPoison(p)) {
folio_put(folio);
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index 7ac19fab226324..33007e8e546a09 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -1813,7 +1813,7 @@ static void do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
if (folio_test_large(folio))
pfn = folio_pfn(folio) + folio_nr_pages(folio) - 1;
- if (folio_contain_hwpoisoned_page(folio)) {
+ if (folio_has_hwpoisoned_page(folio)) {
/*
* unmap_poisoned_folio() cannot handle large folios
* in all cases yet.
diff --git a/mm/rmap.c b/mm/rmap.c
index 1c77d5dc06e9fa..fd19a0bfbfe76c 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -1978,6 +1978,22 @@ static inline unsigned int folio_unmap_pte_batch(struct folio *folio,
FPB_RESPECT_WRITE | FPB_RESPECT_SOFT_DIRTY);
}
+/*
+ * Since we cannot split a hugetlb folio, we want to insert a poison
+ * entry into the page table for the whole folio even if only one page
+ * is poisoned. Otherwise, we've split down to the PTE level and we only
+ * want to poison the precise page
+ */
+static bool ttu_create_hwpoison(const struct folio *folio,
+ const struct page *page, enum ttu_flags flags)
+{
+ if (!(flags & TTU_HWPOISON))
+ return false;
+ if (folio_test_hugetlb(folio))
+ return folio_test_has_hwpoisoned(folio);
+ return PageHWPoison(page);
+}
+
/*
* @arg: enum ttu_flags will be passed to this argument
*/
@@ -1993,7 +2009,6 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,
enum ttu_flags flags = (enum ttu_flags)(long)arg;
unsigned long nr_pages = 1, end_addr;
unsigned long pfn;
- unsigned long hsz = 0;
int ptes = 0;
/*
@@ -2023,9 +2038,6 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,
*/
adjust_range_if_pmd_sharing_possible(vma, &range.start,
&range.end);
-
- /* We need the huge page size for set_huge_pte_at() */
- hsz = huge_page_size(hstate_vma(vma));
}
mmu_notifier_invalidate_range_start(&range);
@@ -2121,7 +2133,8 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,
* The try_to_unmap() is only passed a hugetlb page
* in the case where the hugetlb page is poisoned.
*/
- VM_BUG_ON_PAGE(!PageHWPoison(subpage), subpage);
+ VM_BUG_ON_FOLIO(!folio_has_hwpoisoned_page(folio),
+ folio);
/*
* huge_pmd_unshare may unmap an entire PMD page.
* There is no way of knowing exactly which PMDs may
@@ -2200,12 +2213,12 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,
/* Update high watermark before we lower rss */
update_hiwater_rss(mm);
- if (PageHWPoison(subpage) && (flags & TTU_HWPOISON)) {
+ if (ttu_create_hwpoison(folio, subpage, flags)) {
pteval = swp_entry_to_pte(make_hwpoison_entry(subpage));
if (folio_test_hugetlb(folio)) {
hugetlb_count_sub(folio_nr_pages(folio), mm);
set_huge_pte_at(mm, address, pvmw.pte, pteval,
- hsz);
+ folio_size(folio));
} else {
dec_mm_counter(mm, mm_counter(folio));
set_pte_at(mm, address, pvmw.pte, pteval);
@@ -2423,7 +2436,6 @@ static bool try_to_migrate_one(struct folio *folio, struct vm_area_struct *vma,
struct mmu_notifier_range range;
enum ttu_flags flags = (enum ttu_flags)(long)arg;
unsigned long pfn;
- unsigned long hsz = 0;
/*
* When racing against e.g. zap_pte_range() on another cpu,
@@ -2452,9 +2464,6 @@ static bool try_to_migrate_one(struct folio *folio, struct vm_area_struct *vma,
*/
adjust_range_if_pmd_sharing_possible(vma, &range.start,
&range.end);
-
- /* We need the huge page size for set_huge_pte_at() */
- hsz = huge_page_size(hstate_vma(vma));
}
mmu_notifier_invalidate_range_start(&range);
@@ -2607,14 +2616,14 @@ static bool try_to_migrate_one(struct folio *folio, struct vm_area_struct *vma,
/* Update high watermark before we lower rss */
update_hiwater_rss(mm);
- if (PageHWPoison(subpage)) {
+ if (ttu_create_hwpoison(folio, subpage, TTU_HWPOISON)) {
VM_WARN_ON_FOLIO(folio_is_device_private(folio), folio);
pteval = swp_entry_to_pte(make_hwpoison_entry(subpage));
if (folio_test_hugetlb(folio)) {
hugetlb_count_sub(folio_nr_pages(folio), mm);
set_huge_pte_at(mm, address, pvmw.pte, pteval,
- hsz);
+ folio_size(folio));
} else {
dec_mm_counter(mm, mm_counter(folio));
set_pte_at(mm, address, pvmw.pte, pteval);
@@ -2644,7 +2653,8 @@ static bool try_to_migrate_one(struct folio *folio, struct vm_area_struct *vma,
if (arch_unmap_one(mm, vma, address, pteval) < 0) {
if (folio_test_hugetlb(folio))
set_huge_pte_at(mm, address, pvmw.pte,
- pteval, hsz);
+ pteval,
+ folio_size(folio));
else
set_pte_at(mm, address, pvmw.pte, pteval);
ret = false;
@@ -2657,7 +2667,8 @@ static bool try_to_migrate_one(struct folio *folio, struct vm_area_struct *vma,
if (anon_exclusive &&
hugetlb_try_share_anon_rmap(folio)) {
set_huge_pte_at(mm, address, pvmw.pte,
- pteval, hsz);
+ pteval,
+ folio_size(folio));
ret = false;
page_vma_mapped_walk_done(&pvmw);
break;
@@ -2703,7 +2714,7 @@ static bool try_to_migrate_one(struct folio *folio, struct vm_area_struct *vma,
}
if (folio_test_hugetlb(folio))
set_huge_pte_at(mm, address, pvmw.pte, swp_pte,
- hsz);
+ folio_size(folio));
else
set_pte_at(mm, address, pvmw.pte, swp_pte);
trace_set_migration_pte(address, pte_val(swp_pte),
diff --git a/mm/shmem.c b/mm/shmem.c
index b51f83c970bb37..492c9bef362074 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -3240,7 +3240,7 @@ shmem_write_begin(const struct kiocb *iocb, struct address_space *mapping,
if (ret)
return ret;
- if (folio_contain_hwpoisoned_page(folio)) {
+ if (folio_has_hwpoisoned_page(folio)) {
folio_unlock(folio);
folio_put(folio);
return -EIO;
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 35c3bb15ae96a3..70e54ace0e741c 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -1086,7 +1086,7 @@ static unsigned int shrink_folio_list(struct list_head *folio_list,
if (!folio_trylock(folio))
goto keep;
- if (folio_contain_hwpoisoned_page(folio)) {
+ if (folio_has_hwpoisoned_page(folio)) {
/*
* unmap_poisoned_folio() can't handle large
* folio, just skip it. memory_failure() will
diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c
index db57c5766ab604..94eedcc7f1a9e0 100644
--- a/virt/kvm/guest_memfd.c
+++ b/virt/kvm/guest_memfd.c
@@ -774,7 +774,7 @@ static struct folio *__kvm_gmem_get_pfn(struct file *file,
if (IS_ERR(folio))
return folio;
- if (folio_test_hwpoison(folio)) {
+ if (folio_has_hwpoisoned_page(folio)) {
folio_unlock(folio);
folio_put(folio);
return ERR_PTR(-EHWPOISON);
|
| 3/2 | 2026/07/26 17:51 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 17367 output: 29 thoughts: 1020 Thoughts: **Fuzzing Target Identification: Memory Failure and Hugetlbfs Changes** Okay, so I need to assess this patch series for fuzzing relevance. My initial impression is that these are significant, functional changes – this hits hugetlbfs, memory failure (hwpoison, which is a big concern), and filemap read logic. My spider sense is tingling, this feels important. Specifically, it looks like `adjust_range_hwpoison` in `fs/hugetlbfs/inode.c` has been generalized and moved to `mm/filemap.c`, while `hugetlbfs_read_iter` is now using `generic_file_read_iter`. There's also some refactoring around `folio_test_hwpoison`, now `folio_has_hwpoisoned_page`, across the board, and the introduction of `LARGE_FOLIO` is another potential area. It looks like hwpoison tracking for hugetlb folios is being overhauled too, so I need to check the diff. Alright, diving into the changes. In `fs/hugetlbfs/inode.c`, `hugetlbfs_read_iter` is gone, `hugetlbfs_file_operations.read_iter` is now `generic_file_read_iter`, and there's a new `hugetlbfs_init_regular_inode` that uses some new folio-related functions. `include/linux/hugetlb.h` drops `is_raw_hwpoison_page_in_hugepage`. In `include/linux/page-flags.h` we see `folio_has_hwpoisoned`, `folio_test_huge_poison` being added, and `folio_contain_hwpoisoned_page` is renamed. `include/linux/pagemap.h` adds `AS_AUTHORITATIVE`, and related functions, and modifies `mapping_set_folio_order_range`. `mm/Kconfig` brings in `LARGE_FOLIO`. Now, the juicy stuff. `mm/filemap.c` is updated to check for `folio_has_hwpoisoned_page` and `mapping_is_authoritative` in `filemap_get_read_batch` and `filemap_get_pages`, respectively. The new `adjust_range_hwpoison` and modifications to `filemap_read` to handle hwpoisoned pages and authoritative mappings are there. `mm/memory-failure.c` gets several changes, including renames, new functions like `hugetlb_page_hwpoison`, `hugetlb_unref_page_hwpoison`, and modifications to existing ones. Finally, `mm/rmap.c` introduces `ttu_create_hwpoison` and modifies `try_to_unmap_one` and `try_to_migrate_one`. Conclusion: This patch series is definitely touching critical kernel areas: mm, hugetlbfs, and memory-failure. This *must* be fuzzed. Now, let's identify some potential focus symbols. `adjust_range_hwpoison` is static, so probably not a good target. `filemap_read` is already heavily fuzzed, so maybe too hot, but could still be useful. I'm going to look closely at these: `hugetlb_page_hwpoison`, `hugetlb_unref_page_hwpoison`, `hugetlb_update_hwpoison`, `folio_free_raw_hwp`, `unpoison_memory`, `ttu_create_hwpoison`, and `hugetlbfs_init_regular_inode`. Let's do some quick research to see which functions are actually exported. `hugetlb_page_hwpoison` is not static. `hugetlb_unref_page_hwpoison` is also not static, which is good. `unpoison_memory` looks non-static too. `hugetlb_update_hwpoison` is static, so no luck there. `filemap_read` is exported. I'm going to focus my search on `mm/memory-failure.c` to see if there's anything else about `unpoison_memory` and `hugetlb_page_hwpoison` that is relevant. |
| 4/2 | 2026/07/26 17:51 | tool | grepper |
0mArgs:{
"Expression": "^(int|void|bool).* hugetlb_page_hwpoison"
}Results: {
"Output": "include/linux/page-flags.h=1092=static inline bool PageHuge(const struct page *page)\n--\ninclude/linux/page-flags.h-1096-\ninclude/linux/page-flags.h:1097:bool hugetlb_page_hwpoison(const struct folio *folio, const struct page *page);\ninclude/linux/page-flags.h-1098-bool hugetlb_unref_page_hwpoison(const struct page *page);\n--\nmm/memory-failure.c=1823=static bool precise_page_poisoned(const struct folio *folio,\n--\nmm/memory-failure.c-1848- */\nmm/memory-failure.c:1849:bool hugetlb_page_hwpoison(const struct folio *folio, const struct page *page)\nmm/memory-failure.c-1850-{\n"
} |
| 5/2 | 2026/07/26 17:51 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 19565 output: 20 thoughts: 10 Thoughts: Okay, here's my interpretation of that thought process, tailored for an expert audience, and written in the first person: **Initial Assessment: Navigating the Landscape** Alright, before diving into the specifics, the mental model is starting with `unpoison_memory`. It's a key function, and the context suggests it's likely a critical component for a memory management or security system. Therefore, I need to understand its role. It's either a sanitizer, a validator, or a tool designed to clean up or restore corrupted memory regions. The name itself is fairly straightforward. My immediate thought is, "What kind of memory corruption are we talking about, and what's the environment?" |
| 6/2 | 2026/07/26 17:51 | tool | grepper |
0mArgs:{
"Expression": "^int unpoison_memory"
}Results: {
"Output": "mm/memory-failure.c=2705=core_initcall(memory_failure_init);\n--\nmm/memory-failure.c-2726- */\nmm/memory-failure.c:2727:int unpoison_memory(unsigned long pfn)\nmm/memory-failure.c-2728-{\n--\ntools/testing/selftests/mm/vm_util.c=660=int get_hardware_corrupted_size(unsigned long *val)\n--\ntools/testing/selftests/mm/vm_util.c-683-\ntools/testing/selftests/mm/vm_util.c:684:int unpoison_memory(unsigned long pfn)\ntools/testing/selftests/mm/vm_util.c-685-{\n--\ntools/testing/selftests/mm/vm_util.h=155=int get_hardware_corrupted_size(unsigned long *val);\ntools/testing/selftests/mm/vm_util.h:156:int unpoison_memory(unsigned long pfn);\ntools/testing/selftests/mm/vm_util.h-157-\n"
} |
| 7/2 | 2026/07/26 17:51 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 20038 output: 32 thoughts: 17 Thoughts: Okay, let's dive into this. Here's my thought process on tackling `hugetlb_unref_page_hwpoison`: **Analyzing `hugetlb_unref_page_hwpoison`** Right, so the first thing I need to do is to get a handle on what this function is actually doing. The name gives a few hints; it's related to huge pages (obviously), unreferencing them, and dealing with hardware poisoning. Given my deep understanding of memory management, I can infer that this likely plays a crucial role in cleaning up or handling errors when a huge page is no longer needed or has encountered a hardware issue. I'm probably going to start by tracing the calls to this function. Where is it being invoked? What's the context? Is it called during page deallocation, error handling, or both? Are there any specific error codes or flags that are passed in, or returned? I'll need to understand the interaction with the hardware. What kind of hardware poisoning are we talking about? Is it ECC errors, corrected or uncorrected, or some other hardware signal indicating page corruption? The code will likely need to interact with the CPU or memory controller to handle this. I'll be looking for potential race conditions or locking issues, especially in a multithreaded environment. Huge pages are often managed differently than regular pages, so I need to make sure the synchronization mechanisms are appropriate. Are there any critical sections that need careful attention? I'll also want to understand the impact on the system. Does this function potentially lead to data loss or system instability if it fails to handle poisoning correctly? What are the recovery mechanisms? Are there any performance considerations? How does it affect the overall huge page management strategy? Finally, are there any potential vulnerabilities or security implications? Does this function, if exploited, provide a way to bypass memory protection or leak sensitive information? Security is always on my mind. So, in essence, I'm going to methodically investigate the function's purpose, execution flow, hardware interactions, potential flaws, and impact on system stability and security. Time to dig in! |
| 8/2 | 2026/07/26 17:52 | tool | grepper |
0mArgs:{
"Expression": "^(int|void|bool).* hugetlb_unref_page_hwpoison"
}Results: {
"Output": "include/linux/page-flags.h=1097=bool hugetlb_page_hwpoison(const struct folio *folio, const struct page *page);\ninclude/linux/page-flags.h:1098:bool hugetlb_unref_page_hwpoison(const struct page *page);\ninclude/linux/page-flags.h-1099-\n--\nmm/memory-failure.c=1849=bool hugetlb_page_hwpoison(const struct folio *folio, const struct page *page)\n--\nmm/memory-failure.c-1860- */\nmm/memory-failure.c:1861:bool hugetlb_unref_page_hwpoison(const struct page *page)\nmm/memory-failure.c-1862-{\n"
} |
| 9/2 | 2026/07/26 17:52 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 20737 output: 23 thoughts: 10 Thoughts: Okay, here's my attempt at summarizing the thought process, tailored for an expert audience, and written in the first person: **Diving into `filemap_read`** Alright, time to dig into this. My initial instinct is to go straight to `filemap_read`. It's the core function; that's where the rubber meets the road, isn't it? I need to understand exactly how the file mapping works at this level, how we're translating the logical file offsets into physical page accesses, and what the overall flow looks like. This is where I'll get the granular details I'm looking for. Let's see how the magic happens, and how it handles the fundamental mechanics. I anticipate it deals with the page cache, of course, but it's important to see how the system is organized, and how the different components fit together. |
| 10/2 | 2026/07/26 17:52 | tool | grepper |
0mArgs:{
"Expression": "^ssize_t filemap_read"
}Results: {
"Output": "include/linux/fs.h=3063=extern int generic_file_rw_checks(struct file *file_in, struct file *file_out);\ninclude/linux/fs.h:3064:ssize_t filemap_read(struct kiocb *iocb, struct iov_iter *to,\ninclude/linux/fs.h-3065-\t\tssize_t already_read);\n--\nmm/filemap.c=2779=static void filemap_end_dropbehind_read(struct folio *folio)\n--\nmm/filemap.c-2803- */\nmm/filemap.c:2804:ssize_t filemap_read(struct kiocb *iocb, struct iov_iter *iter,\nmm/filemap.c-2805-\t\tssize_t already_read)\n"
} |
| 11/2 | 2026/07/26 17:52 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 21176 output: 27 thoughts: 102 Thoughts: **Analyzing Potential Hotspots and Alternatives** Okay, so I'm looking at this code and trying to optimize it. `filemap_read`... that's a *very* hot path. I need to be careful about listing it directly in the profiling or logging. It's too granular. I need to find something more meaningful and a bit higher level. Let's see... instead of `filemap_read`, maybe I should be focusing on the related functions that handle page poisoning or unpoisoning. Functions like `hugetlb_page_hwpoison`, `hugetlb_unref_page_hwpoison`, and `unpoison_memory` seem much more relevant, and they're likely indicators of the overall problem. And what about those `hugetlbfs` functions? `hugetlbfs_init_regular_inode` is defined as static, which would make it less interesting, as it wouldn't be exported. So, that leaves `hugetlbfs_get_inode`... I better go check that one out. That seems like a good place to focus to understand the inode retrieval path. Let's see what that one is doing and if it might be a better target for my analysis. |
| 12/2 | 2026/07/26 17:52 | tool | grepper |
0mArgs:{
"Expression": "^static struct inode \\*hugetlbfs_get_inode"
}Results: {
"Output": "fs/hugetlbfs/inode.c=796=static struct lock_class_key hugetlbfs_i_mmap_rwsem_key;\nfs/hugetlbfs/inode.c-797-\nfs/hugetlbfs/inode.c:798:static struct inode *hugetlbfs_get_inode(struct super_block *sb,\nfs/hugetlbfs/inode.c-799-\t\t\t\t\tstruct mnt_idmap *idmap,\n"
} |
| 13/2 | 2026/07/26 17:52 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 21697 output: 26 thoughts: 14 Thoughts: Okay, here's my attempt at summarizing that thought process, keeping in mind I'm speaking to an expert: **Investigating Memory Mapping Options** Right, so we're looking at memory mapping strategies... specifically, I'm wondering if `hugetlbfs_file_mmap` is the right fit for this scenario. We're dealing with potentially large files and performance implications, of course. I need to quickly assess if using huge pages with a file-backed mmap is going to offer the advantages we're hoping for. Are the overheads going to be manageable? Will the specific use case benefit significantly from the increased page size, or will it just introduce complexities we don't need? We should also be mindful of the potential caveats and configurations related to using this in production. It's a key question at the start of any memory intensive operation! |
| 14/2 | 2026/07/26 17:52 | tool | grepper |
0mArgs:{
"Expression": "^static int hugetlbfs_file_mmap"
}Results: {
"Output": "fs/hugetlbfs/inode.c=78=static const struct fs_parameter_spec hugetlb_fs_parameters[] = {\n--\nfs/hugetlbfs/inode.c-98-\nfs/hugetlbfs/inode.c:99:static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma)\nfs/hugetlbfs/inode.c-100-{\n"
} |
| 15/2 | 2026/07/26 17:52 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 22039 output: 20 thoughts: 224 Thoughts: **My Analysis of the Code Changes** Okay, so this patch is aimed at integrating authoritative mappings and handling hardware-poisoned pages more effectively within the file system operations. My understanding is that the core of the change lies in how the kernel interacts with the file system. Specifically, the patch is touching `filemap_read` and `filemap_get_pages`, which are fundamental for reading data from files. It's also making a key change to how hugetlbfs operates. Instead of using its specific `hugetlbfs_read_iter`, the code is moving to `generic_file_read_iter`. This is significant because `generic_file_read_iter` then leverages `filemap_read`. I can see this unifying the read path. To ensure proper functionality, I'll need to remember to include `hugetlb_page_hwpoison`, `hugetlb_unref_page_hwpoison`, and `unpoison_memory` in my list of key symbols for focus. These functions are clearly integral to managing poisoned memory within the hugetlbfs context. Now, before I dig deeper into the implementation details, I need to check the Kconfig options that are relevant. I'll need to know the specific configurations that control the features this patch is touching. I know `LARGE_FOLIO` is a likely candidate, triggered by `HUGETLB_PAGE` and `TRANSPARENT_HUGEPAGE`, since those are about memory management, specifically large pages. Also, `HUGETLBFS` is the main configuration option for hugetlbfs itself. Finally, `MEMORY_FAILURE` is the most important one related to handling hardware poisoning. I'll have to delve into `mm/Kconfig` to confirm the dependencies and defaults for `MEMORY_FAILURE`. |
| 16/2 | 2026/07/26 17:52 | tool | grepper |
0mArgs:{
"Expression": "^config MEMORY_FAILURE"
}Results: {
"Output": "mm/Kconfig=774=config ARCH_SUPPORTS_MEMORY_FAILURE\n--\nmm/Kconfig-776-\nmm/Kconfig:777:config MEMORY_FAILURE\nmm/Kconfig-778-\tdepends on MMU\n"
} |
| 17/2 | 2026/07/26 17:52 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 22736 output: 20 thoughts: 17 Thoughts: Okay, here's my interpretation of that thought process, from an expert's perspective: **Diving into the Kernel Configuration Landscape** Right, time to get to the heart of the matter. I need to understand how `HUGETLBFS` is configured within this kernel. Let's start with the standard practice, the Kconfig file for the filesystem itself. The obvious starting point is `fs/Kconfig`. It's almost always the place to find the main configuration options, dependencies, and descriptions for a filesystem like this. I'll need to see if it's enabled by default, what dependencies exist (like certain memory management features), and how the user can toggle it on or off. That's the first step to understanding its current build configuration. Knowing this will give a good grounding on how to proceed from here. |
| 18/2 | 2026/07/26 17:52 | tool | grepper |
0mError:no matches Args: {
"Expression": "^config HUGETLBFS"
}Results: {
"error": "no matches"
} |
| 19/2 | 2026/07/26 17:52 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 22962 output: 19 thoughts: 16 Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience and presented in the first person: **Navigating the Kernel Configuration Landscape** Right, *HUGETLBFS*... let's see, where was that again? Ah, yes, of course, the filesystem configuration options. My mental map takes me directly to `fs/Kconfig`. It's a fundamental part of the configuration system, and all those filesystem-related settings are organized within. No surprises there. Good. Makes sense. Time to investigate further within that file. |
| 20/2 | 2026/07/26 17:52 | tool | grepper |
0mArgs:{
"Expression": "config HUGETLBFS"
}Results: {
"Output": "fs/Kconfig=247=config ARCH_SUPPORTS_HUGETLBFS\n--\nfs/Kconfig-249-\nfs/Kconfig:250:menuconfig HUGETLBFS\nfs/Kconfig-251-\tbool \"HugeTLB file system support\"\n"
} |
| 21/2 | 2026/07/26 17:52 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 23194 output: 18 thoughts: 183 Thoughts: **Analyzing Huge Pages and Memory Poisoning** Okay, so I'm looking at these configurations: `HUGETLBFS` and `MEMORY_FAILURE`. I need to figure out the dependencies, and it looks like `LARGE_FOLIO` is selected by `HUGETLB_PAGE`, which, in turn, is a `def_bool` for `HUGETLBFS`. So, really, `HUGETLBFS` should be sufficient for what I'm trying to determine. Now, I want to confirm the reachability of `hugetlb_page_hwpoison`. I see it's called from `is_ref_page_hwpoison`, which in turn, is called from `adjust_range_hwpoison` in `mm/filemap.c`. Hmm, right, and `filemap_read` then calls `adjust_range_hwpoison`. Excellent, that confirms it – the functionality is definitely reachable. Next on my mental checklist is `unpoison_memory`. I need to remember, is that invoked by `madvise`, or is it sysfs-driven? Let me just double-check where that function is actually called... |
| 22/2 | 2026/07/26 17:52 | tool | grepper |
0mArgs:{
"Expression": "unpoison_memory"
}Results: {
"Output": "arch/s390/boot/kmsan.c-3-\narch/s390/boot/kmsan.c:4:void kmsan_unpoison_memory(const void *address, size_t size)\narch/s390/boot/kmsan.c-5-{\n--\narch/s390/include/asm/cpacf.h=631=static inline void cpacf_trng(u8 *ucbuf, unsigned long ucbuf_len,\n--\narch/s390/include/asm/cpacf.h-646-\t\t: \"cc\", \"memory\", \"0\");\narch/s390/include/asm/cpacf.h:647:\tkmsan_unpoison_memory(ucbuf, ucbuf_len);\narch/s390/include/asm/cpacf.h:648:\tkmsan_unpoison_memory(cbuf, cbuf_len);\narch/s390/include/asm/cpacf.h-649-}\n--\narch/s390/include/asm/cpu_mf.h=235=static __always_inline int stcctm(enum stcctm_ctr_set set, u64 range, u64 *dest)\n--\narch/s390/include/asm/cpu_mf.h-248-\t */\narch/s390/include/asm/cpu_mf.h:249:\tkmsan_unpoison_memory(dest, range * sizeof(u64));\narch/s390/include/asm/cpu_mf.h-250-\treturn CC_TRANSFORM(cc);\n--\narch/s390/include/asm/fpu-insn.h=388=static __always_inline void fpu_vstl(u8 v1, u32 index, const void *vxr)\n--\narch/s390/include/asm/fpu-insn.h-397-\t\t : \"memory\");\narch/s390/include/asm/fpu-insn.h:398:\tkmsan_unpoison_memory(vxr, size);\narch/s390/include/asm/fpu-insn.h-399-}\n--\narch/s390/include/asm/fpu-insn.h=403=static __always_inline void fpu_vstl(u8 v1, u32 index, const void *vxr)\n--\narch/s390/include/asm/fpu-insn.h-414-\t\t: \"memory\", \"1\");\narch/s390/include/asm/fpu-insn.h:415:\tkmsan_unpoison_memory(vxr, size);\narch/s390/include/asm/fpu-insn.h-416-}\n--\narch/s390/kernel/ftrace.c=283=void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,\n--\narch/s390/kernel/ftrace.c-297-\narch/s390/kernel/ftrace.c:298:\tkmsan_unpoison_memory(fregs, ftrace_regs_size());\narch/s390/kernel/ftrace.c-299-\tregs = ftrace_get_regs(fregs);\n--\narch/x86/include/asm/page_64.h=85=static inline void clear_pages(void *addr, unsigned int npages)\n--\narch/x86/include/asm/page_64.h-91-\t */\narch/x86/include/asm/page_64.h:92:\tkmsan_unpoison_memory(addr, len);\narch/x86/include/asm/page_64.h-93-\n--\narch/x86/lib/iomem.c=26=static void string_memcpy_fromio(void *to, const volatile void __iomem *from, size_t n)\n--\narch/x86/lib/iomem.c-44-\t/* KMSAN must treat values read from devices as initialized. */\narch/x86/lib/iomem.c:45:\tkmsan_unpoison_memory(orig_to, orig_n);\narch/x86/lib/iomem.c-46-}\n--\ncrypto/jitterentropy-kcapi.c=102=void jent_hash_time(struct sha3_ctx *hash_state, __u64 time, u8 *addtl,\n--\ncrypto/jitterentropy-kcapi.c-109-\ncrypto/jitterentropy-kcapi.c:110:\tkmsan_unpoison_memory(intermediary, sizeof(intermediary));\ncrypto/jitterentropy-kcapi.c-111-\n--\ndrivers/input/serio/libps2.c=262=int __ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command)\n--\ndrivers/input/serio/libps2.c-354-\t\t\tparam[i] = ps2dev-\u003ecmdbuf[(receive - 1) - i];\ndrivers/input/serio/libps2.c:355:\t\tkmsan_unpoison_memory(param, receive);\ndrivers/input/serio/libps2.c-356-\t}\n--\ninclude/linux/highmem.h=396=static inline void copy_user_highpage(struct page *to, struct page *from,\n--\ninclude/linux/highmem.h-403-\tcopy_user_page(vto, vfrom, vaddr, to);\ninclude/linux/highmem.h:404:\tkmsan_unpoison_memory(page_address(to), PAGE_SIZE);\ninclude/linux/highmem.h-405-\tkunmap_local(vto);\n--\ninclude/linux/highmem.h=434=static inline int copy_mc_user_highpage(struct page *to, struct page *from,\n--\ninclude/linux/highmem.h-443-\tif (!ret)\ninclude/linux/highmem.h:444:\t\tkmsan_unpoison_memory(page_address(to), PAGE_SIZE);\ninclude/linux/highmem.h-445-\tkunmap_local(vto);\n--\ninclude/linux/instrumented.h=161=instrument_copy_from_user_after(const void *to, const void __user *from,\n--\ninclude/linux/instrumented.h-163-{\ninclude/linux/instrumented.h:164:\tkmsan_unpoison_memory(to, n - left);\ninclude/linux/instrumented.h-165-}\n--\ninclude/linux/instrumented.h=195=static __always_inline void instrument_memcpy_after(void *to, const void *from,\n--\ninclude/linux/instrumented.h-212-\tu64 __tmp = (u64)(to);\t\t\t\t\\\ninclude/linux/instrumented.h:213:\tkmsan_unpoison_memory(\u0026__tmp, sizeof(__tmp));\t\\\ninclude/linux/instrumented.h-214-\tto = __tmp;\t\t\t\t\t\\\n--\ninclude/linux/kmsan-checks.h=27=void kmsan_poison_memory(const void *address, size_t size, gfp_t flags);\n--\ninclude/linux/kmsan-checks.h-29-/**\ninclude/linux/kmsan-checks.h:30: * kmsan_unpoison_memory() - Mark the memory range as initialized.\ninclude/linux/kmsan-checks.h-31- * @address: address to start with.\n--\ninclude/linux/kmsan-checks.h-36- */\ninclude/linux/kmsan-checks.h:37:void kmsan_unpoison_memory(const void *address, size_t size);\ninclude/linux/kmsan-checks.h-38-\n--\ninclude/linux/kmsan-checks.h=77=static inline void kmsan_poison_memory(const void *address, size_t size,\n--\ninclude/linux/kmsan-checks.h-80-}\ninclude/linux/kmsan-checks.h:81:static inline void kmsan_unpoison_memory(const void *address, size_t size)\ninclude/linux/kmsan-checks.h-82-{\n--\ninclude/linux/kmsan.h=221=void kmsan_handle_urb(const struct urb *urb, bool is_out);\n--\ninclude/linux/kmsan.h-227- * KMSAN unpoisons the contents of the passed pt_regs, preventing potential\ninclude/linux/kmsan.h:228: * false positive reports. Unlike kmsan_unpoison_memory(),\ninclude/linux/kmsan.h-229- * kmsan_unpoison_entry_regs() can be called from the regions where\n--\ninclude/linux/mm.h=4994=extern int memory_failure(unsigned long pfn, int flags);\ninclude/linux/mm.h:4995:extern int unpoison_memory(unsigned long pfn);\ninclude/linux/mm.h-4996-extern atomic_long_t num_poisoned_pages __read_mostly;\n--\nkernel/bpf/core.c=2401=static unsigned int PROG_NAME(stack_size)(const void *ctx, const struct bpf_insn *insn) \\\n--\nkernel/bpf/core.c-2405-\\\nkernel/bpf/core.c:2406:\tkmsan_unpoison_memory(stack, sizeof(stack)); \\\nkernel/bpf/core.c-2407-\tFP = (u64) (unsigned long) \u0026stack[ARRAY_SIZE(stack)]; \\\n--\nkernel/bpf/core.c=2414=static u64 PROG_NAME_ARGS(stack_size)(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5, \\\n--\nkernel/bpf/core.c-2419-\\\nkernel/bpf/core.c:2420:\tkmsan_unpoison_memory(stack, sizeof(stack)); \\\nkernel/bpf/core.c-2421-\tFP = (u64) (unsigned long) \u0026stack[ARRAY_SIZE(stack)]; \\\n--\nkernel/dma/swiotlb.c=858=static void swiotlb_bounce(struct device *dev, phys_addr_t tlb_addr, size_t size,\n--\nkernel/dma/swiotlb.c-917-\t\t\t} else {\nkernel/dma/swiotlb.c:918:\t\t\t\tkmsan_unpoison_memory(vaddr, sz);\nkernel/dma/swiotlb.c-919-\t\t\t\tmemcpy_to_page(page, offset, vaddr, sz);\n--\nkernel/dma/swiotlb.c-936-\t} else {\nkernel/dma/swiotlb.c:937:\t\tkmsan_unpoison_memory(vaddr, size);\nkernel/dma/swiotlb.c-938-\t\tmemcpy(phys_to_virt(orig_addr), vaddr, size);\n--\nkernel/kcov.c=151=static void kcov_remote_area_put(struct kcov_remote_area *area,\n--\nkernel/kcov.c-161-\t */\nkernel/kcov.c:162:\tkmsan_unpoison_memory(\u0026area-\u003elist, sizeof(area-\u003elist));\nkernel/kcov.c-163-}\n--\nkernel/trace/ftrace.c=8555=void arch_ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip,\n--\nkernel/trace/ftrace.c-8557-{\nkernel/trace/ftrace.c:8558:\tkmsan_unpoison_memory(fregs, ftrace_regs_size());\nkernel/trace/ftrace.c-8559-\t__ftrace_ops_list_func(ip, parent_ip, NULL, fregs);\n--\nlib/crypto/arm64/sha256.h=44=static bool sha256_finup_2x_arch(const struct __sha256_ctx *ctx,\n--\nlib/crypto/arm64/sha256.h-53-\t\t\tsha256_ce_finup2x(ctx, data1, data2, len, out1, out2);\nlib/crypto/arm64/sha256.h:54:\t\tkmsan_unpoison_memory(out1, SHA256_DIGEST_SIZE);\nlib/crypto/arm64/sha256.h:55:\t\tkmsan_unpoison_memory(out2, SHA256_DIGEST_SIZE);\nlib/crypto/arm64/sha256.h-56-\t\treturn true;\n--\nlib/crypto/s390/sha3.h=64=static inline bool s390_sha3(int func, const u8 *in, size_t in_len,\n--\nlib/crypto/s390/sha3.h-79-\tif (static_branch_likely(\u0026have_sha3_init_optim))\nlib/crypto/s390/sha3.h:80:\t\tkmsan_unpoison_memory(\u0026state, out_len);\nlib/crypto/s390/sha3.h-81-\n--\nlib/crypto/x86/sha256.h=70=static bool sha256_finup_2x_arch(const struct __sha256_ctx *ctx,\n--\nlib/crypto/x86/sha256.h-84-\t\tkernel_fpu_end();\nlib/crypto/x86/sha256.h:85:\t\tkmsan_unpoison_memory(out1, SHA256_DIGEST_SIZE);\nlib/crypto/x86/sha256.h:86:\t\tkmsan_unpoison_memory(out2, SHA256_DIGEST_SIZE);\nlib/crypto/x86/sha256.h-87-\t\treturn true;\n--\nlib/iomap.c=360=void ioread8_rep(const void __iomem *addr, void *dst, unsigned long count)\n--\nlib/iomap.c-363-\t/* KMSAN must treat values read from devices as initialized. */\nlib/iomap.c:364:\tkmsan_unpoison_memory(dst, count);\nlib/iomap.c-365-}\nlib/iomap.c=366=void ioread16_rep(const void __iomem *addr, void *dst, unsigned long count)\n--\nlib/iomap.c-369-\t/* KMSAN must treat values read from devices as initialized. */\nlib/iomap.c:370:\tkmsan_unpoison_memory(dst, count * 2);\nlib/iomap.c-371-}\nlib/iomap.c=372=void ioread32_rep(const void __iomem *addr, void *dst, unsigned long count)\n--\nlib/iomap.c-375-\t/* KMSAN must treat values read from devices as initialized. */\nlib/iomap.c:376:\tkmsan_unpoison_memory(dst, count * 4);\nlib/iomap.c-377-}\n--\nlib/stackdepot.c=434=depot_alloc_stack(unsigned long *entries, unsigned int nr_entries, u32 hash, depot_flags_t flags, void **prealloc)\n--\nlib/stackdepot.c-487-\t */\nlib/stackdepot.c:488:\tkmsan_unpoison_memory(stack, record_size);\nlib/stackdepot.c-489-\n--\nlib/stackdepot.c=760=unsigned int stack_depot_fetch(depot_stack_handle_t handle,\n--\nlib/stackdepot.c-769-\t */\nlib/stackdepot.c:770:\tkmsan_unpoison_memory(entries, sizeof(*entries));\nlib/stackdepot.c-771-\n--\nlib/zlib_dfltcc/dfltcc_util.h=29=static inline dfltcc_cc dfltcc(\n--\nlib/zlib_dfltcc/dfltcc_util.h-71- case DFLTCC_QAF:\nlib/zlib_dfltcc/dfltcc_util.h:72: kmsan_unpoison_memory(param, sizeof(struct dfltcc_qaf_param));\nlib/zlib_dfltcc/dfltcc_util.h-73- break;\nlib/zlib_dfltcc/dfltcc_util.h-74- case DFLTCC_GDHT:\nlib/zlib_dfltcc/dfltcc_util.h:75: kmsan_unpoison_memory(param, offsetof(struct dfltcc_param_v0, csb));\nlib/zlib_dfltcc/dfltcc_util.h-76- break;\nlib/zlib_dfltcc/dfltcc_util.h-77- case DFLTCC_CMPR:\nlib/zlib_dfltcc/dfltcc_util.h:78: kmsan_unpoison_memory(param, sizeof(struct dfltcc_param_v0));\nlib/zlib_dfltcc/dfltcc_util.h:79: kmsan_unpoison_memory(\nlib/zlib_dfltcc/dfltcc_util.h-80- orig_t2,\n--\nlib/zlib_dfltcc/dfltcc_util.h-84- case DFLTCC_XPND:\nlib/zlib_dfltcc/dfltcc_util.h:85: kmsan_unpoison_memory(param, sizeof(struct dfltcc_param_v0));\nlib/zlib_dfltcc/dfltcc_util.h:86: kmsan_unpoison_memory(orig_t2, t2 - orig_t2);\nlib/zlib_dfltcc/dfltcc_util.h-87- break;\n--\nmm/hwpoison-inject.c=144=static int hwpoison_unpoison(void *data, u64 val)\n--\nmm/hwpoison-inject.c-148-\nmm/hwpoison-inject.c:149:\treturn unpoison_memory(val);\nmm/hwpoison-inject.c-150-}\n--\nmm/kmsan/core.c=40=void kmsan_internal_task_create(struct task_struct *task)\n--\nmm/kmsan/core.c-45-\t__memset(ctx, 0, sizeof(*ctx));\nmm/kmsan/core.c:46:\tkmsan_internal_unpoison_memory(info, sizeof(*info), false);\nmm/kmsan/core.c-47-}\n--\nmm/kmsan/core.c=49=void kmsan_internal_poison_memory(void *address, size_t size, gfp_t flags,\n--\nmm/kmsan/core.c-60-\nmm/kmsan/core.c:61:void kmsan_internal_unpoison_memory(void *address, size_t size, bool checked)\nmm/kmsan/core.c-62-{\n--\nmm/kmsan/core.c=80=void kmsan_internal_memmove_metadata(void *dst, void *src, size_t n)\n--\nmm/kmsan/core.c-99-\t\t/* @src is untracked: mark @dst as initialized. */\nmm/kmsan/core.c:100:\t\tkmsan_internal_unpoison_memory(dst, n, /*checked*/ false);\nmm/kmsan/core.c-101-\t\treturn;\n--\nmm/kmsan/core.c=145=depot_stack_handle_t kmsan_internal_chain_origin(depot_stack_handle_t id)\n--\nmm/kmsan/core.c-185-\t */\nmm/kmsan/core.c:186:\tkmsan_internal_unpoison_memory(entries, sizeof(entries), false);\nmm/kmsan/core.c-187-\thandle = stack_depot_save(entries, ARRAY_SIZE(entries), __GFP_HIGH);\n--\nmm/kmsan/hooks.c=48=void kmsan_slab_alloc(struct kmem_cache *s, void *object, gfp_t flags)\n--\nmm/kmsan/hooks.c-62-\tif (flags \u0026 __GFP_ZERO)\nmm/kmsan/hooks.c:63:\t\tkmsan_internal_unpoison_memory(object, s-\u003eobject_size,\nmm/kmsan/hooks.c-64-\t\t\t\t\t KMSAN_POISON_CHECK);\n--\nmm/kmsan/hooks.c=93=void kmsan_kmalloc_large(const void *ptr, size_t size, gfp_t flags)\n--\nmm/kmsan/hooks.c-100-\tif (flags \u0026 __GFP_ZERO)\nmm/kmsan/hooks.c:101:\t\tkmsan_internal_unpoison_memory((void *)ptr, size,\nmm/kmsan/hooks.c-102-\t\t\t\t\t /*checked*/ true);\n--\nmm/kmsan/hooks.c=301=void kmsan_handle_urb(const struct urb *urb, bool is_out)\n--\nmm/kmsan/hooks.c-310-\telse\nmm/kmsan/hooks.c:311:\t\tkmsan_internal_unpoison_memory(urb-\u003etransfer_buffer,\nmm/kmsan/hooks.c-312-\t\t\t\t\t urb-\u003etransfer_buffer_length,\n--\nmm/kmsan/hooks.c=317=static void kmsan_handle_dma_page(const void *addr, size_t size,\n--\nmm/kmsan/hooks.c-323-\t\t\t\t\t /*user_addr*/ NULL, REASON_ANY);\nmm/kmsan/hooks.c:324:\t\tkmsan_internal_unpoison_memory((void *)addr, size,\nmm/kmsan/hooks.c-325-\t\t\t\t\t /*checked*/ false);\n--\nmm/kmsan/hooks.c-331-\tcase DMA_FROM_DEVICE:\nmm/kmsan/hooks.c:332:\t\tkmsan_internal_unpoison_memory((void *)addr, size,\nmm/kmsan/hooks.c-333-\t\t\t\t\t /*checked*/ false);\n--\nmm/kmsan/hooks.c=392=EXPORT_SYMBOL(kmsan_poison_memory);\n--\nmm/kmsan/hooks.c-397- */\nmm/kmsan/hooks.c:398:void kmsan_unpoison_memory(const void *address, size_t size)\nmm/kmsan/hooks.c-399-{\n--\nmm/kmsan/hooks.c-406-\t/* The users may want to poison/unpoison random memory. */\nmm/kmsan/hooks.c:407:\tkmsan_internal_unpoison_memory((void *)address, size,\nmm/kmsan/hooks.c-408-\t\t\t\t KMSAN_POISON_NOCHECK);\n--\nmm/kmsan/hooks.c-410-}\nmm/kmsan/hooks.c:411:EXPORT_SYMBOL(kmsan_unpoison_memory);\nmm/kmsan/hooks.c-412-\nmm/kmsan/hooks.c-413-/*\nmm/kmsan/hooks.c:414: * Version of kmsan_unpoison_memory() called from IRQ entry functions.\nmm/kmsan/hooks.c-415- */\nmm/kmsan/hooks.c=416=void kmsan_unpoison_entry_regs(const struct pt_regs *regs)\nmm/kmsan/hooks.c-417-{\nmm/kmsan/hooks.c:418:\tkmsan_unpoison_memory((void *)regs, sizeof(*regs));\nmm/kmsan/hooks.c-419-}\n--\nmm/kmsan/instrumentation.c=106=void __msan_instrument_asm_store(void *addr, uintptr_t size)\n--\nmm/kmsan/instrumentation.c-126-\t/* Unpoisoning the memory on best effort. */\nmm/kmsan/instrumentation.c:127:\tkmsan_internal_unpoison_memory(addr, size, /*checked*/ false);\nmm/kmsan/instrumentation.c-128-\tuser_access_restore(ua_flags);\n--\nmm/kmsan/instrumentation.c=210=void *__msan_memset(void *dst, int c, uintptr_t n)\n--\nmm/kmsan/instrumentation.c-225-\t */\nmm/kmsan/instrumentation.c:226:\tkmsan_internal_unpoison_memory(dst, n, /*checked*/ false);\nmm/kmsan/instrumentation.c-227-\tkmsan_leave_runtime();\n--\nmm/kmsan/instrumentation.c=297=void __msan_unpoison_alloca(void *address, uintptr_t size)\n--\nmm/kmsan/instrumentation.c-302-\tkmsan_enter_runtime();\nmm/kmsan/instrumentation.c:303:\tkmsan_internal_unpoison_memory(address, size, /*checked*/ true);\nmm/kmsan/instrumentation.c-304-\tkmsan_leave_runtime();\n--\nmm/kmsan/kmsan.h=155=void kmsan_internal_poison_memory(void *address, size_t size, gfp_t flags,\nmm/kmsan/kmsan.h-156-\t\t\t\t unsigned int poison_flags);\nmm/kmsan/kmsan.h:157:void kmsan_internal_unpoison_memory(void *address, size_t size, bool checked);\nmm/kmsan/kmsan.h-158-void kmsan_internal_set_shadow_origin(void *address, size_t size, int b,\n--\nmm/kmsan/kmsan_test.c=670=static void test_stackdepot_roundtrip(struct kunit *test)\n--\nmm/kmsan/kmsan_test.c-691-/*\nmm/kmsan/kmsan_test.c:692: * Test case: ensure that kmsan_unpoison_memory() and the instrumentation work\nmm/kmsan/kmsan_test.c-693- * the same.\nmm/kmsan/kmsan_test.c-694- */\nmm/kmsan/kmsan_test.c:695:static void test_unpoison_memory(struct kunit *test)\nmm/kmsan/kmsan_test.c-696-{\nmm/kmsan/kmsan_test.c:697:\tEXPECTATION_UNINIT_VALUE_FN(expect, \"test_unpoison_memory\");\nmm/kmsan/kmsan_test.c-698-\tvolatile char a[4], b[4];\n--\nmm/kmsan/kmsan_test.c-701-\t\ttest,\nmm/kmsan/kmsan_test.c:702:\t\t\"unpoisoning via the instrumentation vs. kmsan_unpoison_memory() (2 UMR reports)\\n\");\nmm/kmsan/kmsan_test.c-703-\n--\nmm/kmsan/kmsan_test.c-711-\t/* Initialize b[0] and check b[1]--b[3]. */\nmm/kmsan/kmsan_test.c:712:\tkmsan_unpoison_memory((char *)\u0026b[0], 1);\nmm/kmsan/kmsan_test.c-713-\tkmsan_check_memory((char *)\u0026b[1], 3);\n--\nmm/kmsan/kmsan_test.c=733=static struct kunit_case kmsan_test_cases[] = {\n--\nmm/kmsan/kmsan_test.c-759-\tKUNIT_CASE(test_stackdepot_roundtrip),\nmm/kmsan/kmsan_test.c:760:\tKUNIT_CASE(test_unpoison_memory),\nmm/kmsan/kmsan_test.c-761-\tKUNIT_CASE(test_copy_from_kernel_nofault),\n--\nmm/kmsan/report.c=86=void kmsan_print_origin(depot_stack_handle_t origin)\n--\nmm/kmsan/report.c-126-\t\t\t\tstack_depot_fetch(head, \u0026chained_entries);\nmm/kmsan/report.c:127:\t\t\tkmsan_internal_unpoison_memory(\nmm/kmsan/report.c-128-\t\t\t\tchained_entries,\n--\nmm/kmsan/shadow.c=151=void kmsan_copy_page_meta(struct page *dst, struct page *src)\n--\nmm/kmsan/shadow.c-157-\tif (!src || !page_has_metadata(src)) {\nmm/kmsan/shadow.c:158:\t\tkmsan_internal_unpoison_memory(page_address(dst), PAGE_SIZE,\nmm/kmsan/shadow.c-159-\t\t\t\t\t /*checked*/ false);\n--\nmm/memory-failure.c=1441=static int __get_unpoison_page(struct page *page)\n--\nmm/memory-failure.c-1482- *\nmm/memory-failure.c:1483: * When called from unpoison_memory(), the caller should already ensure that\nmm/memory-failure.c-1484- * the given page has PG_hwpoison. So it's never reused for other page\n--\nmm/memory-failure.c=2705=core_initcall(memory_failure_init);\n--\nmm/memory-failure.c-2715-/**\nmm/memory-failure.c:2716: * unpoison_memory - Unpoison a previously poisoned page\nmm/memory-failure.c-2717- * @pfn: Page number of the to be unpoisoned page\n--\nmm/memory-failure.c-2726- */\nmm/memory-failure.c:2727:int unpoison_memory(unsigned long pfn)\nmm/memory-failure.c-2728-{\n--\nmm/memory-failure.c-2831-}\nmm/memory-failure.c:2832:EXPORT_SYMBOL(unpoison_memory);\nmm/memory-failure.c-2833-\n--\nmm/page_alloc.c=1312=static __always_inline bool __free_pages_prepare(struct page *page,\n--\nmm/page_alloc.c-1354-\t\t * Mark the codetag as empty to avoid accounting error\nmm/page_alloc.c:1355:\t\t * when the page is freed by unpoison_memory().\nmm/page_alloc.c-1356-\t\t */\n--\nmm/slub.c=9624=static char *create_unique_id(struct kmem_cache *s)\n--\nmm/slub.c-9657-\t}\nmm/slub.c:9658:\tkmsan_unpoison_memory(name, p - name);\nmm/slub.c-9659-\treturn name;\n--\nmm/slub.c=9729=int sysfs_slab_alias(struct kmem_cache *s, const char *name)\n--\nmm/slub.c-9753-\talias_list = al;\nmm/slub.c:9754:\tkmsan_unpoison_memory(al, sizeof(*al));\nmm/slub.c-9755-\treturn 0;\n--\ntools/objtool/check.c=1091=static const char *uaccess_safe_builtin[] = {\n--\ntools/objtool/check.c-1234-\t\"kmsan_unpoison_entry_regs\",\ntools/objtool/check.c:1235:\t\"kmsan_unpoison_memory\",\ntools/objtool/check.c-1236-\t\"__msan_chain_origin\",\n--\ntools/testing/selftests/mm/memory-failure.c=203=static void cleanup(struct __test_metadata *_metadata, FIXTURE_DATA(memory_failure) * self,\n--\ntools/testing/selftests/mm/memory-failure.c-208-\ntools/testing/selftests/mm/memory-failure.c:209:\tASSERT_EQ(unpoison_memory(self-\u003epfn), 0);\ntools/testing/selftests/mm/memory-failure.c-210-\n--\ntools/testing/selftests/mm/vm_util.c=660=int get_hardware_corrupted_size(unsigned long *val)\n--\ntools/testing/selftests/mm/vm_util.c-683-\ntools/testing/selftests/mm/vm_util.c:684:int unpoison_memory(unsigned long pfn)\ntools/testing/selftests/mm/vm_util.c-685-{\n--\ntools/testing/selftests/mm/vm_util.h=155=int get_hardware_corrupted_size(unsigned long *val);\ntools/testing/selftests/mm/vm_util.h:156:int unpoison_memory(unsigned long pfn);\ntools/testing/selftests/mm/vm_util.h-157-\n"
} |
| 23/2 | 2026/07/26 17:52 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 32111 output: 27 thoughts: 51 Thoughts: Here's my thought process, as requested: **Tracing the Memory Poisoning Functionality** Okay, so I'm looking at `unpoison_memory`. The code says this function is exported and called from `hwpoison_unpoison` in `mm/hwpoison-inject.c`. Good, that means it's definitely reachable – it's not some dead code dangling in the ether. That's the first hurdle. Now, I need to understand *where* it's being used beyond that direct call. To get a better grasp of the broader picture, the next logical step seems to be to check `hugetlbfs_get_inode`. I'm guessing that might give me some context, especially if the code deals with hugepages. The relationship between those two is where I'll get more insight. |
| 24/2 | 2026/07/26 17:52 | tool | grepper |
0mArgs:{
"Expression": "^static struct inode \\*hugetlbfs_get_inode"
}Results: {
"Output": "fs/hugetlbfs/inode.c=796=static struct lock_class_key hugetlbfs_i_mmap_rwsem_key;\nfs/hugetlbfs/inode.c-797-\nfs/hugetlbfs/inode.c:798:static struct inode *hugetlbfs_get_inode(struct super_block *sb,\nfs/hugetlbfs/inode.c-799-\t\t\t\t\tstruct mnt_idmap *idmap,\n"
} |
| 25/2 | 2026/07/26 17:52 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 32494 output: 26 thoughts: 28 Thoughts: Here's my take on those thoughts: **Considering HugeTLB Implementation Details** Okay, so I'm digging into this `hugetlbfs` code again. I noticed that the `hugetlbfs_get_inode` function is marked as `static`. That's a good sign; it means it's scoped internally to this module, which simplifies understanding its impact and reduces potential for unexpected interactions with other kernel components. But, it got me thinking... what about `hugetlbfs_file_mmap`? Is that static too, or is it exposed in a way that warrants further scrutiny? I need to quickly determine its visibility and where it is being used to get a better handle on the overall design and any potential risks. I really hope it's well documented and easy to trace. I'll need to check the function's declaration and usage to understand its scope and potential interactions with the rest of the file system. |
| 26/2 | 2026/07/26 17:52 | tool | grepper |
0mArgs:{
"Expression": "^static int hugetlbfs_file_mmap"
}Results: {
"Output": "fs/hugetlbfs/inode.c=78=static const struct fs_parameter_spec hugetlb_fs_parameters[] = {\n--\nfs/hugetlbfs/inode.c-98-\nfs/hugetlbfs/inode.c:99:static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma)\nfs/hugetlbfs/inode.c-100-{\n"
} |
| 27/2 | 2026/07/26 17:53 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 32867 output: 28 thoughts: 17 Thoughts: Okay, here's my attempt at summarizing that thought process, keeping in mind I'm speaking to a fellow expert: **Diving into `hugetlbfs_get_unmapped_area`** Alright, time to dig into `hugetlbfs_get_unmapped_area`. That's where we start, right? Need to understand how the system's finding a free, contiguous chunk of virtual address space for these huge pages. It's the critical first step in all of this. What are the key considerations there? Are we dealing with the regular mmap infrastructure, or does this have its own custom logic? Gotta figure out how it interacts with the rest of the VM, what locking is involved, and of course, how it avoids fragmentation. This function is the foundation; understanding it is paramount to the entire huge page allocation process. Let's see how it's implemented. |
| 28/2 | 2026/07/26 17:53 | tool | grepper |
0mError:no matches Args: {
"Expression": "^static unsigned long hugetlb_get_unmapped_area"
}Results: {
"error": "no matches"
} |
| 29/2 | 2026/07/26 17:53 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 33116 output: 29 thoughts: 13 Thoughts: Okay, here's my attempt at summarizing those thoughts from an expert's perspective, using a first-person perspective: **Delving into the `hugetlbfs_file_operations`** Right, so I'm looking at this... and the immediate question that pops up, given my experience, is: "What about the `hugetlbfs_file_operations`?" That's the core of how hugetlbfs interacts with the filesystem layer, isn't it? It dictates how files within a hugetlbfs mount are opened, read, written, mapped, and generally managed. It's the critical bridge between the user-space applications and the low-level memory management that leverages those huge pages. I'm already mentally running through the various function pointers defined within that structure: `mmap`, `read`, `write`, `open`, `release`, and so on. Understanding their implementation is key. We know that `hugetlbfs` needs to handle specific issues related to the granularity of huge pages and how to present this to the application. I wonder if there are any subtle bugs lurking in there, or maybe optimizations that could be made, particularly when we're dealing with concurrent access. This is definitely a starting point to dive deeper to check on any recent changes or ongoing issues within the system. Let's see how this ties into the rest of the kernel's memory management. |
| 30/2 | 2026/07/26 17:53 | tool | grepper |
0mArgs:{
"Expression": "^static const struct file_operations hugetlbfs_file_operations"
}Results: {
"Output": "fs/hugetlbfs/inode.c=45=static const struct address_space_operations hugetlbfs_aops;\nfs/hugetlbfs/inode.c:46:static const struct file_operations hugetlbfs_file_operations;\nfs/hugetlbfs/inode.c-47-static const struct inode_operations hugetlbfs_dir_inode_operations;\n--\nfs/hugetlbfs/inode.c=1104=static void init_once(void *foo)\n--\nfs/hugetlbfs/inode.c-1110-\nfs/hugetlbfs/inode.c:1111:static const struct file_operations hugetlbfs_file_operations = {\nfs/hugetlbfs/inode.c-1112-\t.read_iter\t\t= generic_file_read_iter,\n"
} |
| 31/2 | 2026/07/26 17:53 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 33672 output: 26 thoughts: 205 Thoughts: **Refining the Fuzzing Strategy for HugeTLB Memory Poisoning** Okay, so I'm thinking about how to improve the fuzzing strategy around HugeTLB memory poisoning. I noticed that the `hugetlbfs_file_operations` structure uses `generic_file_read_iter`, which, in turn, calls `filemap_read`. That path potentially leads to `adjust_range_hwpoison`. Initially, I thought I could just list a more comprehensive set of functions. However, `generic_file_read_iter` is so common, it'll likely pollute the fuzzing results with noise. I need to be more targeted. I'm going to focus on the key, specific functions directly involved in poison and unpoison operations. I'll include `hugetlb_page_hwpoison`, `hugetlb_unref_page_hwpoison`, and `unpoison_memory` for now. But let me quickly check if any other exported functions were impacted by these changes. Ah, yes, `hugetlb_folio_mapping_lock_write` now takes `const struct folio *folio`. And `folio_clear_hugetlb_hwpoison` was also modified. I'll need to keep those in mind as I refine my analysis. These seem like the relevant entry points. |
| 32/2 | 2026/07/26 17:53 | tool | grepper |
0mArgs:{
"Expression": "^void folio_clear_hugetlb_hwpoison"
}Results: {
"Output": "mm/memory-failure.c=1976=static unsigned long folio_free_raw_hwp(struct folio *folio, bool move_flag)\n--\nmm/memory-failure.c-2001-\nmm/memory-failure.c:2002:void folio_clear_hugetlb_hwpoison(struct folio *folio)\nmm/memory-failure.c-2003-{\n"
} |
| 33/2 | 2026/07/26 17:53 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 34293 output: 28 thoughts: 20 Thoughts: Here's my take on the thought process, as requested: **Checking `folio_clear_hugetlb_hwpoison` Export Status** Okay, so I'm looking at this function name, `folio_clear_hugetlb_hwpoison`. Seems like a potentially important one for handling hardware-detected memory errors within the huge page system, specifically the folio framework. I'm immediately curious if it's actually exported. Is it designed to be used outside of the core kernel code, perhaps by a driver or other module that needs to interact with this particular aspect of huge page management? Time to verify its visibility. I need to confirm whether it's part of the public API or internal to the kernel's implementation. Knowing its export status gives me a crucial clue about its intended use and the design philosophy around it. It'll shape the way I think about it. |
| 34/2 | 2026/07/26 17:53 | tool | grepper |
0mError:no matches Args: {
"Expression": "EXPORT_SYMBOL.*folio_clear_hugetlb_hwpoison"
}Results: {
"error": "no matches"
} |
| 35/2 | 2026/07/26 17:53 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 34540 output: 26 thoughts: 53 Thoughts: Okay, here's my interpretation of those thoughts, presented as my own mental process, given my expertise: **Examining Potential Static Function Candidates for Modification** Right, so I'm trying to figure out where a specific function that isn't exported, but isn't static either, might be. The goal is to track down candidates. Given the context, it's probably related to some core internal functionality within a driver or library. Let's quickly rule out a few likely suspects by checking their properties. First up, I'll consider `hugetlb_update_hwpoison`. Ah, that one *is* static; so not what I'm looking for. That narrows things down. Next, let me check `hugetlb_mfill_atomic_pte`. Maybe that's the one I need. |
| 36/2 | 2026/07/26 17:53 | tool | grepper |
0mArgs:{
"Expression": "^int hugetlb_mfill_atomic_pte"
}Results: {
"Output": "include/linux/hugetlb.h=140=vm_fault_t hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,\n--\ninclude/linux/hugetlb.h-142-#ifdef CONFIG_USERFAULTFD\ninclude/linux/hugetlb.h:143:int hugetlb_mfill_atomic_pte(pte_t *dst_pte,\ninclude/linux/hugetlb.h-144-\t\t\t struct vm_area_struct *dst_vma,\n--\nmm/hugetlb.c=6136=static struct folio *alloc_hugetlb_folio_vma(struct hstate *h,\n--\nmm/hugetlb.c-6162- */\nmm/hugetlb.c:6163:int hugetlb_mfill_atomic_pte(pte_t *dst_pte,\nmm/hugetlb.c-6164-\t\t\t struct vm_area_struct *dst_vma,\n"
} |
| 37/2 | 2026/07/26 17:53 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 35052 output: 24 thoughts: 32 Thoughts: Okay, here's my interpretation of those thoughts, summarized in the first person, assuming the context is my expertise: **Checking the Non-Static Nature and Dependency** Right, so `hugetlb_mfill_atomic_pte` isn't static. That immediately raises a flag. I need to understand its visibility and potential for external usage. It's crucial for me to grasp the scope of this function. Now, I should shift my attention to `demote_pool_huge_page`. My intuition tells me there might be an interaction or dependency I need to examine between these two. I need to see how `demote_pool_huge_page` might call, or be called by, `hugetlb_mfill_atomic_pte`, or how their behaviors might interrelate in the larger context of huge page management. This is the next logical step in my analysis. |
| 38/2 | 2026/07/26 17:53 | tool | grepper |
0mArgs:{
"Expression": "^long demote_pool_huge_page"
}Results: {
"Output": "mm/hugetlb.c=3919=static long demote_free_hugetlb_folios(struct hstate *src, struct hstate *dst,\n--\nmm/hugetlb.c-3977-\nmm/hugetlb.c:3978:long demote_pool_huge_page(struct hstate *src, nodemask_t *nodes_allowed,\nmm/hugetlb.c-3979-\t\t\t unsigned long nr_to_demote)\n"
} |
| 39/2 | 2026/07/26 17:53 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 35428 output: 25 thoughts: 31 Thoughts: Here's my analysis of the situation: **Investigating `demote_pool_huge_page` and `init_new_hugetlb_folio`** Okay, so I see that `demote_pool_huge_page` isn't declared as static. This makes me immediately curious. I'm wondering what other code might be calling this function, and where it's being used beyond its immediate scope. Non-static functions always raise a flag; it means the potential for broader impact and perhaps more complex interactions. My next logical step is to check `init_new_hugetlb_folio`, as it's likely connected to the same memory management domain. I need to understand the relationship between these two, specifically how huge pages are allocated, deallocated, and potentially demoted within the system. Is there any potential for race conditions or unexpected behavior if `demote_pool_huge_page` is called from outside its presumed module? I need to understand the control flow. My expertise requires me to dig into the call stacks and understand the interaction of these two functions at a deeper level. I need to form a mental map of their involvement in the process of huge page management, and how that affects the bigger picture. |
| 40/2 | 2026/07/26 17:53 | tool | grepper |
0mArgs:{
"Expression": "^void init_new_hugetlb_folio"
}Results: {
"Output": "mm/hugetlb.c=1755=static void account_new_hugetlb_folio(struct hstate *h, struct folio *folio)\n--\nmm/hugetlb.c-1761-\nmm/hugetlb.c:1762:void init_new_hugetlb_folio(struct folio *folio)\nmm/hugetlb.c-1763-{\n"
} |
| 41/2 | 2026/07/26 17:53 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 35852 output: 20 thoughts: 80 Thoughts: **My Plan for Handling Hardware Poisoning in HugeTLB Pages** Okay, here's the plan. I need to get a handle on how hardware poisoning affects HugeTLB pages. My initial step is to incorporate a few key functions into `FocusSymbols`. Specifically, I'm going to add `hugetlb_page_hwpoison`, `hugetlb_unref_page_hwpoison`, `unpoison_memory`, and `folio_clear_hugetlb_hwpoison`. This seems crucial for tracking and managing the implications of memory errors within that particular memory space. Now, I'm also going to be looking at a couple of related kernel configurations. I'm assuming that both `HUGETLBFS` and `MEMORY_FAILURE` are set to `y` or the appropriate equivalent. I'll need to double check those. I can't be sure without doing some digging, but I suspect that `LARGE_FOLIO` is also a configuration option. I need to confirm whether that is the case and, if so, review what it does. |
| 42/2 | 2026/07/26 17:53 | tool | grepper |
0mArgs:{
"Expression": "^config LARGE_FOLIO"
}Results: {
"Output": "mm/Kconfig=843=config MM_ID\n--\nmm/Kconfig-845-\nmm/Kconfig:846:config LARGE_FOLIO\nmm/Kconfig-847-\tdef_bool n\n"
} |
| 43/2 | 2026/07/26 17:53 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 36246 output: 20 thoughts: 99 Thoughts: **Analyzing Huge Page Configuration** Okay, so `LARGE_FOLIO` is defined as a config option, right? And it's set as a boolean, dependent on `TRANSPARENT_HUGEPAGE` and `HUGETLB_PAGE`. Right, that makes sense. Let's see... `HUGETLB_PAGE` is also defined as a boolean, specifically linked to `HUGETLBFS`. Aha! So, if I enable `HUGETLBFS` and `MEMORY_FAILURE`, that should effectively enable `LARGE_FOLIO` through the dependency chain. Seems straightforward enough. Just to be absolutely certain, I'll quickly double-check the `HUGETLBFS` definition and related configurations within the file system Kconfig (`fs/Kconfig`). I always find it best to verify these dependencies to be sure I'm not missing any nuanced implications, especially when dealing with memory management. I want to ensure my mental model is accurate before proceeding. |
| 44/2 | 2026/07/26 17:53 | tool | grepper |
0mError:no matches Args: {
"Expression": "^config HUGETLBFS"
}Results: {
"error": "no matches"
} |
| 45/2 | 2026/07/26 17:53 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 36583 output: 21 thoughts: 13 Thoughts: Here's my attempt at summarizing the thought process, tailored for an expert audience and written in the first person: **Navigating the Kernel Configuration Landscape** Okay, so I'm looking at something in the kernel config... and it's immediately jumping out at me: `menuconfig HUGETLBFS`. Right, got it. That means I'm probably dealing with the HugeTLB Filesystem, which is usually a pretty good indicator of performance optimization scenarios, likely related to NUMA configurations or applications demanding significant memory resources with low latency requirements. This probably falls under one of the several use cases I am familiar with; whether a specific hardware platform that I am intimately aware of, an application that depends on this setting, or a system I was involved in that required such attention to memory layout. Let's see what the context is... This is certainly a starting point for diving into the memory management configuration. Now I need to see what's enabled, disabled, or set. It's time to dig deeper. |
| 46/2 | 2026/07/26 17:53 | tool | grepper |
0mArgs:{
"Expression": "^menuconfig HUGETLBFS"
}Results: {
"Output": "fs/Kconfig=247=config ARCH_SUPPORTS_HUGETLBFS\n--\nfs/Kconfig-249-\nfs/Kconfig:250:menuconfig HUGETLBFS\nfs/Kconfig-251-\tbool \"HugeTLB file system support\"\n"
} |
| 47/2 | 2026/07/26 17:54 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 36908 output: 20 thoughts: 29 Thoughts: Okay, here's my interpretation of those thoughts, tailored for an expert audience: **Kernel Configuration Context** Right, so we're looking at configurations. The initial prompt clearly points to `HUGETLBFS` as the relevant config option to consider. Seems straightforward enough. The next logical step is to cross-reference that with other, related configurations, and my internal process brings up the `MEMORY_FAILURE` configuration in `mm/Kconfig`. This lets me start to understand the connections between these configurations, and what other settings may be affected or related to `HUGETLBFS`. I want to fully understand the dependency graph, possible interactions, and potential implications for memory management and failure handling. I'm going to dig into how the `MEMORY_FAILURE` setting might influence or interact with the `HUGETLBFS` configuration. |
| 48/2 | 2026/07/26 17:54 | tool | grepper |
0mArgs:{
"Expression": "^config MEMORY_FAILURE"
}Results: {
"Output": "mm/Kconfig=774=config ARCH_SUPPORTS_MEMORY_FAILURE\n--\nmm/Kconfig-776-\nmm/Kconfig:777:config MEMORY_FAILURE\nmm/Kconfig-778-\tdepends on MMU\n"
} |
| 49/2 | 2026/07/26 17:54 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 37204 output: 236 thoughts: 302 Thoughts: **My Fuzzing Configuration for Hugetlb Folios and Memory-Failure Handling** Okay, so I've confirmed that `MEMORY_FAILURE` is definitely the right config to start with. Let's see... looking at the configurations, it looks like `TRANSPARENT_HUGEPAGE` is also modified, specifically to select `LARGE_FOLIO`. Makes sense; I should include `TRANSPARENT_HUGEPAGE` as well. Now, let's pull all of this together into a useful summary: I'm setting `WorthFuzzing` to `true`, of course. My `FocusSymbols` are going to target these crucial functions: `hugetlb_page_hwpoison`, `hugetlb_unref_page_hwpoison`, `unpoison_memory`, and `folio_clear_hugetlb_hwpoison`. My `EnableConfigs` are: `HUGETLBFS`, `MEMORY_FAILURE`, and `TRANSPARENT_HUGEPAGE`. I chose those because this patch series introduces the `LARGE_FOLIO` config and fundamentally changes how hardware poisoning is managed for hugetlb folios. It seems they're replacing the more specific `adjust_range_hwpoison` function in `fs/hugetlbfs/inode.c` with the generic version in `mm/filemap.c`. Also, `hugetlbfs_read_iter` has been updated to `generic_file_read_iter`. I also see changes to `folio_test_hwpoison` which is now `folio_has_hwpoisoned_page`. These are all core kernel logic changes (mm, hugetlbfs, memory-failure) which means they're critical areas for fuzzing and bug detection. |
| 50/2 | 2026/07/26 17:54 | tool | set-results |
0mArgs:{
"EnableConfigs": [
"HUGETLBFS",
"MEMORY_FAILURE",
"TRANSPARENT_HUGEPAGE"
],
"FocusSymbols": [
"hugetlb_page_hwpoison",
"hugetlb_unref_page_hwpoison",
"unpoison_memory",
"folio_clear_hugetlb_hwpoison"
],
"Reasoning": "The patch series introduces `LARGE_FOLIO` config and refactors how hwpoison is tracked for hugetlb folios. It replaces `adjust_range_hwpoison` in `fs/hugetlbfs/inode.c` with a generic one in `mm/filemap.c` and changes `hugetlbfs_read_iter` to `generic_file_read_iter`. It also modifies `folio_test_hwpoison` to `folio_has_hwpoisoned_page` in various places. These are functional changes to core kernel logic (mm, hugetlbfs, memory-failure) and should be fuzzed.",
"WorthFuzzing": true
}Results: {
"EnableConfigs": [
"HUGETLBFS",
"MEMORY_FAILURE",
"TRANSPARENT_HUGEPAGE"
],
"FocusSymbols": [
"hugetlb_page_hwpoison",
"hugetlb_unref_page_hwpoison",
"unpoison_memory",
"folio_clear_hugetlb_hwpoison"
],
"Reasoning": "The patch series introduces `LARGE_FOLIO` config and refactors how hwpoison is tracked for hugetlb folios. It replaces `adjust_range_hwpoison` in `fs/hugetlbfs/inode.c` with a generic one in `mm/filemap.c` and changes `hugetlbfs_read_iter` to `generic_file_read_iter`. It also modifies `folio_test_hwpoison` to `folio_has_hwpoisoned_page` in various places. These are functional changes to core kernel logic (mm, hugetlbfs, memory-failure) and should be fuzzed.",
"WorthFuzzing": true
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|