| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/07/20 03:38 | flow | patch-triage |
1mArgs:null Results: {
"EnableConfigs": [
"DAMON",
"DAMON_SYSFS",
"DAMON_VADDR",
"TRANSPARENT_HUGEPAGE"
],
"FocusSymbols": [
"damos_va_split",
"target_order_store",
"target_order_show"
],
"Reasoning": "The patch introduces a new DAMON action `DAMOS_SPLIT` to split large folios down to a specified order. It adds sysfs interfaces to configure the target order and implements the splitting logic in `damos_va_split` using `split_folio_to_order`. This is a functional change to the memory management subsystem and should be fuzzed to ensure the folio splitting logic and sysfs interface handle edge cases correctly.",
"WorthFuzzing": true
} |
| 1/1 | 2026/07/20 03:38 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit 7adf884411492e2d70200a1d4a5b2ae571a54db8\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Mon Jul 20 03:38:08 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/Documentation/ABI/testing/sysfs-kernel-mm-damon b/Documentation/ABI/testing/sysfs-kernel-mm-damon\nindex 907a504fb64c54..ee8e260a631cf2 100644\n--- a/Documentation/ABI/testing/sysfs-kernel-mm-damon\n+++ b/Documentation/ABI/testing/sysfs-kernel-mm-damon\n@@ -265,6 +265,13 @@ Contact:\tSJ Park \u003csj@kernel.org\u003e\n Description:\tAction's target NUMA node id. Supported by only relevant\n \t\tactions.\n \n+What:\t\t/sys/kernel/mm/damon/admin/kdamonds/\u003cK\u003e/contexts/\u003cC\u003e/schemes/\u003cS\u003e/target_order\n+Date:\t\tJul 2026\n+Contact:\tSJ Park \u003csj@kernel.org\u003e\n+Description:\tTarget folio order for the ``split`` action. Large folios in\n+\t\tthe target region are split down to this order. Valid values\n+\t\tare 0 (order-0 base pages) and 2..HPAGE_PMD_ORDER-1.\n+\n What:\t\t/sys/kernel/mm/damon/admin/kdamonds/\u003cK\u003e/contexts/\u003cC\u003e/schemes/\u003cS\u003e/apply_interval_us\n Date:\t\tSep 2023\n Contact:\tSJ Park \u003csj@kernel.org\u003e\ndiff --git a/Documentation/mm/damon/design.rst b/Documentation/mm/damon/design.rst\nindex aed6cb1cf48310..87a801954b1b30 100644\n--- a/Documentation/mm/damon/design.rst\n+++ b/Documentation/mm/damon/design.rst\n@@ -549,6 +549,11 @@ that supports each action are as below.\n Supported by ``vaddr`` and ``fvaddr`` operations set. When\n TRANSPARENT_HUGEPAGE is disabled, the application of the action will just\n fail.\n+ - ``split``: Split each large folio in the region down to the order specified\n+ by the scheme's ``target_order`` (``0`` for order-0 base pages, or\n+ ``2..HPAGE_PMD_ORDER-1``). Supported by ``vaddr`` and ``fvaddr`` operations\n+ set. When TRANSPARENT_HUGEPAGE is disabled, the application of the action\n+ will just fail.\n - ``lru_prio``: Prioritize the region on its LRU lists.\n Supported by ``paddr`` operations set.\n - ``lru_deprio``: Deprioritize the region on its LRU lists.\ndiff --git a/include/linux/damon.h b/include/linux/damon.h\nindex f69442a9d43128..88b61b900a36db 100644\n--- a/include/linux/damon.h\n+++ b/include/linux/damon.h\n@@ -110,6 +110,7 @@ struct damon_target {\n * @DAMOS_HUGEPAGE:\tCall ``madvise()`` for the region with MADV_HUGEPAGE.\n * @DAMOS_NOHUGEPAGE:\tCall ``madvise()`` for the region with MADV_NOHUGEPAGE.\n * @DAMOS_COLLAPSE:\tCall ``madvise()`` for the region with MADV_COLLAPSE.\n+ * @DAMOS_SPLIT:\tSplit each large folio in the region to a smaller order.\n * @DAMOS_LRU_PRIO:\tPrioritize the region on its LRU lists.\n * @DAMOS_LRU_DEPRIO:\tDeprioritize the region on its LRU lists.\n * @DAMOS_MIGRATE_HOT: Migrate the regions prioritizing warmer regions.\n@@ -130,6 +131,7 @@ enum damos_action {\n \tDAMOS_HUGEPAGE,\n \tDAMOS_NOHUGEPAGE,\n \tDAMOS_COLLAPSE,\n+\tDAMOS_SPLIT,\n \tDAMOS_LRU_PRIO,\n \tDAMOS_LRU_DEPRIO,\n \tDAMOS_MIGRATE_HOT,\n@@ -582,10 +584,15 @@ struct damos {\n \tstruct damos_quota quota;\n \tstruct damos_watermarks wmarks;\n \tunion {\n-\t\tstruct {\n-\t\t\tint target_nid;\n-\t\t\tstruct damos_migrate_dests migrate_dests;\n-\t\t};\n+\t\tint target_nid;\n+\t\tstruct damos_migrate_dests migrate_dests;\n+\t\t/*\n+\t\t * @order: target folio order for DAMOS_SPLIT.\n+\t\t * Split large folios down to this order. 0 for\n+\t\t * order-0 base pages, 2..HPAGE_PMD_ORDER-1 for\n+\t\t * smaller mTHP. Order-1 is rejected.\n+\t\t */\n+\t\tunsigned int order;\n \t};\n \tstruct list_head core_filters;\n \tstruct list_head ops_filters;\ndiff --git a/mm/damon/core.c b/mm/damon/core.c\nindex 806a67d02a6e90..394c62455ad56b 100644\n--- a/mm/damon/core.c\n+++ b/mm/damon/core.c\n@@ -693,6 +693,7 @@ struct damos *damon_new_scheme(struct damos_access_pattern *pattern,\n \t\treturn NULL;\n \tscheme-\u003epattern = *pattern;\n \tscheme-\u003eaction = action;\n+\tscheme-\u003eorder = 0;\n \tscheme-\u003eapply_interval_us = apply_interval_us;\n \t/*\n \t * next_apply_sis will be set when kdamond starts. While kdamond is\n@@ -1446,6 +1447,7 @@ static int damos_commit(struct damos *dst, struct damos *src)\n \n \tdst-\u003epattern = src-\u003epattern;\n \tdst-\u003eaction = src-\u003eaction;\n+\tdst-\u003eorder = src-\u003eorder;\n \tdst-\u003eapply_interval_us = src-\u003eapply_interval_us;\n \n \terr = damos_commit_quota(\u0026dst-\u003equota, \u0026src-\u003equota);\ndiff --git a/mm/damon/sysfs-schemes.c b/mm/damon/sysfs-schemes.c\nindex 32f495a96b17a8..725ed81ccf6cac 100644\n--- a/mm/damon/sysfs-schemes.c\n+++ b/mm/damon/sysfs-schemes.c\n@@ -4,7 +4,9 @@\n */\n \n #include \u003clinux/slab.h\u003e\n+#include \u003clinux/mm.h\u003e\n #include \u003clinux/numa.h\u003e\n+#include \u003clinux/huge_mm.h\u003e\n \n #include \"sysfs-common.h\"\n \n@@ -2260,6 +2262,7 @@ struct damon_sysfs_scheme {\n \tstruct damon_sysfs_stats *stats;\n \tstruct damon_sysfs_scheme_regions *tried_regions;\n \tint target_nid;\n+\tunsigned int target_order;\n \tstruct damos_sysfs_dests *dests;\n };\n \n@@ -2293,6 +2296,10 @@ static struct damos_sysfs_action_name damos_sysfs_action_names[] = {\n \t\t.action = DAMOS_COLLAPSE,\n \t\t.name = \"collapse\",\n \t},\n+\t{\n+\t\t.action = DAMOS_SPLIT,\n+\t\t.name = \"split\",\n+\t},\n \t{\n \t\t.action = DAMOS_LRU_PRIO,\n \t\t.name = \"lru_prio\",\n@@ -2326,6 +2333,7 @@ static struct damon_sysfs_scheme *damon_sysfs_scheme_alloc(\n \tscheme-\u003eaction = action;\n \tscheme-\u003eapply_interval_us = apply_interval_us;\n \tscheme-\u003etarget_nid = NUMA_NO_NODE;\n+\tscheme-\u003etarget_order = 0;\n \treturn scheme;\n }\n \n@@ -2645,6 +2653,40 @@ static ssize_t target_nid_store(struct kobject *kobj,\n \treturn err ? err : count;\n }\n \n+static ssize_t target_order_show(struct kobject *kobj,\n+\t\tstruct kobj_attribute *attr, char *buf)\n+{\n+\tstruct damon_sysfs_scheme *scheme = container_of(kobj,\n+\t\t\tstruct damon_sysfs_scheme, kobj);\n+\n+\treturn sysfs_emit(buf, \"%u\\n\", scheme-\u003etarget_order);\n+}\n+\n+static ssize_t target_order_store(struct kobject *kobj,\n+\t\tstruct kobj_attribute *attr, const char *buf, size_t count)\n+{\n+\tstruct damon_sysfs_scheme *scheme = container_of(kobj,\n+\t\t\tstruct damon_sysfs_scheme, kobj);\n+\tunsigned int val;\n+\tint err;\n+\n+\terr = kstrtouint(buf, 0, \u0026val);\n+\tif (err)\n+\t\treturn err;\n+\n+#ifdef CONFIG_TRANSPARENT_HUGEPAGE\n+\t/* Valid split targets: 0 (order-0 base pages) or 2..HPAGE_PMD_ORDER-1. */\n+\tif (val != 0 \u0026\u0026 (val \u003c 2 || val \u003e= HPAGE_PMD_ORDER))\n+\t\treturn -EINVAL;\n+#else\n+\tif (val != 0)\n+\t\treturn -EINVAL;\n+#endif\n+\n+\tscheme-\u003etarget_order = val;\n+\treturn count;\n+}\n+\n static void damon_sysfs_scheme_release(struct kobject *kobj)\n {\n \tkfree(container_of(kobj, struct damon_sysfs_scheme, kobj));\n@@ -2659,10 +2701,14 @@ static struct kobj_attribute damon_sysfs_scheme_apply_interval_us_attr =\n static struct kobj_attribute damon_sysfs_scheme_target_nid_attr =\n \t\t__ATTR_RW_MODE(target_nid, 0600);\n \n+static struct kobj_attribute damon_sysfs_scheme_target_order_attr =\n+\t\t__ATTR_RW_MODE(target_order, 0600);\n+\n static struct attribute *damon_sysfs_scheme_attrs[] = {\n \t\u0026damon_sysfs_scheme_action_attr.attr,\n \t\u0026damon_sysfs_scheme_apply_interval_us_attr.attr,\n \t\u0026damon_sysfs_scheme_target_nid_attr.attr,\n+\t\u0026damon_sysfs_scheme_target_order_attr.attr,\n \tNULL,\n };\n ATTRIBUTE_GROUPS(damon_sysfs_scheme);\n@@ -3011,6 +3057,8 @@ static struct damos *damon_sysfs_mk_scheme(\n \tif (!scheme)\n \t\treturn NULL;\n \n+\tscheme-\u003eorder = sysfs_scheme-\u003etarget_order;\n+\n \terr = damos_sysfs_add_quota_score(sysfs_quotas-\u003egoals, \u0026scheme-\u003equota);\n \tif (err) {\n \t\tdamon_destroy_scheme(scheme);\ndiff --git a/mm/damon/vaddr.c b/mm/damon/vaddr.c\nindex d10b8042adb5ba..a8607448584d55 100644\n--- a/mm/damon/vaddr.c\n+++ b/mm/damon/vaddr.c\n@@ -6,6 +6,7 @@\n #define pr_fmt(fmt) \"damon-va: \" fmt\n \n #include \u003clinux/highmem.h\u003e\n+#include \u003clinux/huge_mm.h\u003e\n #include \u003clinux/hugetlb.h\u003e\n #include \u003clinux/mman.h\u003e\n #include \u003clinux/mmu_notifier.h\u003e\n@@ -896,6 +897,111 @@ static unsigned long damos_va_stat(struct damon_target *target,\n \treturn 0;\n }\n \n+/*\n+ * damos_va_split() - Split large folios in a region down to @target_order\n+ * using the existing split_folio_to_order().\n+ *\n+ * Locking: folio_walk_start() returns the folio with the page table lock\n+ * held. split_folio_to_order() must not run under the page table lock,\n+ * so we pin the folio (reference + lock), end the walk to drop the page\n+ * table lock, and split while holding only mmap_read_lock.\n+ * split_folio_to_order() returns -EBUSY for a raced or pinned folio;\n+ * we skip such folios.\n+ */\n+static unsigned long damos_va_split(struct damon_target *target,\n+\t\tstruct damon_region *r, struct damos *s,\n+\t\tunsigned long *sz_filter_passed)\n+{\n+\tunsigned int target_order = s-\u003eorder;\n+\tunsigned long addr = ALIGN_DOWN(r-\u003ear.start, PAGE_SIZE);\n+\tunsigned long end = r-\u003ear.end;\n+\tunsigned long applied = 0;\n+\tstruct mm_struct *mm;\n+\n+\tmm = damon_get_mm(target);\n+\tif (!mm)\n+\t\treturn 0;\n+\n+\twhile (addr \u003c end) {\n+\t\tstruct vm_area_struct *vma;\n+\t\tstruct folio *folio;\n+\t\tstruct folio_walk fw;\n+\t\tunsigned long folio_sz = 0;\n+\n+\t\tif (mmap_read_lock_killable(mm))\n+\t\t\tbreak;\n+\n+\t\tvma = vma_lookup(mm, addr);\n+\t\tif (!vma) {\n+\t\t\t/* Skip the gap to the next VMA, if any. */\n+\t\t\tvma = find_vma(mm, addr);\n+\t\t\tmmap_read_unlock(mm);\n+\t\t\tif (!vma || vma-\u003evm_start \u003e= end)\n+\t\t\t\tbreak;\n+\t\t\taddr = vma-\u003evm_start;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\t/* Folios in these VMAs are not our business. */\n+\t\tif (vma-\u003evm_flags \u0026 (VM_HUGETLB | VM_MIXEDMAP)) {\n+\t\t\taddr = vma-\u003evm_end;\n+\t\t\tmmap_read_unlock(mm);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tfolio = folio_walk_start(\u0026fw, vma, addr, 0);\n+\t\tif (!folio) {\n+\t\t\tmmap_read_unlock(mm);\n+\t\t\taddr += PAGE_SIZE;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tfolio_sz = folio_size(folio);\n+\n+\t\t/*\n+\t\t * For file-backed folios, @target_order may be below the\n+\t\t * filesystem's minimum folio order (mapping_min_folio_order()).\n+\t\t * split_folio_to_order() will simply fail in that case and\n+\t\t * we skip the folio. This is a safe no-op; future work can\n+\t\t * adjust target_order upward like split_huge_pages_in_pid()\n+\t\t * does when a specific filesystem needs it.\n+\t\t */\n+\n+\t\t/* Honour the scheme's operations-layer filters. */\n+\t\tif (damos_ops_has_filter(s)) {\n+\t\t\tif (damos_va_filter_out(s, folio, vma, addr,\n+\t\t\t\t\tfw.level == FW_LEVEL_PTE ? fw.ptep : NULL,\n+\t\t\t\t\tfw.level == FW_LEVEL_PMD ? fw.pmdp : NULL)) {\n+\t\t\t\tfolio_walk_end(\u0026fw, vma);\n+\t\t\t\tmmap_read_unlock(mm);\n+\t\t\t\tgoto next;\n+\t\t\t}\n+\t\t\t*sz_filter_passed += folio_sz;\n+\t\t}\n+\n+\t\tif (folio_order(folio) \u003e target_order \u0026\u0026 folio_trylock(folio)) {\n+\t\t\tfolio_get(folio);\n+\t\t\t/* Drop the page table lock before splitting. */\n+\t\t\tfolio_walk_end(\u0026fw, vma);\n+\n+\t\t\tif (!split_folio_to_order(folio, target_order))\n+\t\t\t\tapplied += folio_sz;\n+\n+\t\t\tfolio_unlock(folio);\n+\t\t\tfolio_put(folio);\n+\t\t} else {\n+\t\t\tfolio_walk_end(\u0026fw, vma);\n+\t\t}\n+\t\tmmap_read_unlock(mm);\n+next:\n+\t\taddr = ALIGN_DOWN(addr, folio_sz) + folio_sz;\n+\t\tcond_resched();\n+\t}\n+\n+\tmmput(mm);\n+\treturn applied;\n+}\n+\n static unsigned long damon_va_apply_scheme(struct damon_ctx *ctx,\n \t\tstruct damon_target *t, struct damon_region *r,\n \t\tstruct damos *scheme, unsigned long *sz_filter_passed)\n@@ -926,6 +1032,8 @@ static unsigned long damon_va_apply_scheme(struct damon_ctx *ctx,\n \t\treturn damos_va_migrate(t, r, scheme, sz_filter_passed);\n \tcase DAMOS_STAT:\n \t\treturn damos_va_stat(t, r, scheme, sz_filter_passed);\n+\tcase DAMOS_SPLIT:\n+\t\treturn damos_va_split(t, r, scheme, sz_filter_passed);\n \tdefault:\n \t\t/*\n \t\t * DAMOS actions that are not yet supported by 'vaddr'.\ndiff --git a/tools/testing/selftests/damon/Makefile b/tools/testing/selftests/damon/Makefile\nindex ece244e5c5b95c..a623c271355ffe 100644\n--- a/tools/testing/selftests/damon/Makefile\n+++ b/tools/testing/selftests/damon/Makefile\n@@ -12,6 +12,7 @@ TEST_PROGS += sysfs.sh\n TEST_PROGS += sysfs.py\n TEST_PROGS += sysfs_update_schemes_tried_regions_wss_estimation.py\n TEST_PROGS += damos_quota.py damos_quota_goal.py damos_apply_interval.py\n+TEST_PROGS += damos_split.py\n TEST_PROGS += damos_tried_regions.py damon_nr_regions.py\n TEST_PROGS += sysfs_refresh.py\n TEST_PROGS += reclaim.sh lru_sort.sh\ndiff --git a/tools/testing/selftests/damon/_damon_sysfs.py b/tools/testing/selftests/damon/_damon_sysfs.py\nindex e6a2265d721e8b..5a01f31ad9f26d 100644\n--- a/tools/testing/selftests/damon/_damon_sysfs.py\n+++ b/tools/testing/selftests/damon/_damon_sysfs.py\n@@ -419,6 +419,7 @@ class Damos:\n filters = None\n apply_interval_us = None\n target_nid = None\n+ target_order = None\n dests = None\n idx = None\n context = None\n@@ -429,7 +430,7 @@ class Damos:\n def __init__(self, action='stat', access_pattern=DamosAccessPattern(),\n quota=DamosQuota(), watermarks=DamosWatermarks(),\n core_filters=[], ops_filters=[], filters=[], target_nid=0,\n- dests=DamosDests(), apply_interval_us=0):\n+ target_order=0, dests=DamosDests(), apply_interval_us=0):\n self.action = action\n self.access_pattern = access_pattern\n self.access_pattern.scheme = self\n@@ -448,6 +449,7 @@ class Damos:\n self.filters.scheme = self\n \n self.target_nid = target_nid\n+ self.target_order = target_order\n self.dests = dests\n self.dests.scheme = self\n \n@@ -492,6 +494,11 @@ class Damos:\n if err is not None:\n return err\n \n+ err = write_file(os.path.join(self.sysfs_dir(), 'target_order'), '%d' %\n+ self.target_order)\n+ if err is not None:\n+ return err\n+\n err = self.dests.stage()\n if err is not None:\n return err\ndiff --git a/tools/testing/selftests/damon/damos_split.py b/tools/testing/selftests/damon/damos_split.py\nnew file mode 100644\nindex 00000000000000..089fbe0f0d4d3b\n--- /dev/null\n+++ b/tools/testing/selftests/damon/damos_split.py\n@@ -0,0 +1,125 @@\n+#!/usr/bin/env python3\n+# SPDX-License-Identifier: GPL-2.0\n+#\n+# Functional test for the DAMOS_SPLIT action.\n+#\n+# A child process allocates a MADV_HUGEPAGE-backed anonymous region and\n+# faults it in so that it is backed by (m)THPs. The parent then runs a\n+# DAMON/DAMOS scheme with action 'split' and target_order 0 against the\n+# child and checks that the huge pages are split into base pages, i.e. the\n+# child's AnonHugePages (as reported by /proc/\u003cpid\u003e/smaps) drops.\n+\n+import ctypes\n+import os\n+import signal\n+import sys\n+import time\n+\n+import _damon_sysfs\n+\n+PMD_SIZE = 2 * 1024 * 1024\n+MADV_HUGEPAGE = 14\n+PROT_READ_WRITE = 0x1 | 0x2\n+MAP_PRIVATE_ANON = 0x2 | 0x20\n+REGION_SIZE = 32 * PMD_SIZE\n+\n+def child_workload():\n+ '''Allocate a PMD-aligned, THP-backed region, fault it in, then idle.'''\n+ libc = ctypes.CDLL('libc.so.6', use_errno=True)\n+ libc.mmap.restype = ctypes.c_void_p\n+ libc.mmap.argtypes = [ctypes.c_void_p, ctypes.c_size_t, ctypes.c_int,\n+ ctypes.c_int, ctypes.c_int, ctypes.c_long]\n+ libc.madvise.argtypes = [ctypes.c_void_p, ctypes.c_size_t, ctypes.c_int]\n+\n+ # Over-allocate so that a PMD-aligned window is available.\n+ raw = libc.mmap(None, REGION_SIZE + PMD_SIZE, PROT_READ_WRITE,\n+ MAP_PRIVATE_ANON, -1, 0)\n+ if raw is None or raw == ctypes.c_void_p(-1).value:\n+ os._exit(2)\n+ base = (raw + PMD_SIZE - 1) \u0026 ~(PMD_SIZE - 1)\n+ libc.madvise(ctypes.c_void_p(base), REGION_SIZE, MADV_HUGEPAGE)\n+\n+ buf = (ctypes.c_char * REGION_SIZE).from_address(base)\n+ for off in range(0, REGION_SIZE, 4096):\n+ buf[off] = 1\n+\n+ # Ready; idle until the parent tears us down.\n+ signal.pause()\n+\n+def anon_huge_kb(pid):\n+ total = 0\n+ try:\n+ with open('/proc/%d/smaps' % pid) as f:\n+ for line in f:\n+ if line.startswith('AnonHugePages:'):\n+ total += int(line.split()[1])\n+ except FileNotFoundError:\n+ return -1\n+ return total\n+\n+def main():\n+ if not os.path.exists('/sys/kernel/mm/transparent_hugepage/enabled'):\n+ print('SKIP: transparent hugepage is not available')\n+ exit(0)\n+\n+ pid = os.fork()\n+ if pid == 0:\n+ child_workload()\n+ os._exit(0)\n+\n+ try:\n+ # Give the child time to fault in its huge pages.\n+ time.sleep(2)\n+ before = anon_huge_kb(pid)\n+ if before \u003c= 0:\n+ print('SKIP: workload did not get any THP (AnonHugePages=%d)'\n+ % before)\n+ os.kill(pid, signal.SIGKILL)\n+ exit(0)\n+\n+ # Split every large folio in the target down to order-0 base pages.\n+ kdamonds = _damon_sysfs.Kdamonds([_damon_sysfs.Kdamond(\n+ contexts=[_damon_sysfs.DamonCtx(\n+ ops='vaddr',\n+ targets=[_damon_sysfs.DamonTarget(pid=pid)],\n+ schemes=[_damon_sysfs.Damos(\n+ action='split',\n+ target_order=0,\n+ # match every region regardless of access/age/size, so\n+ # the ARM64 stale-TLB blind spot cannot mask the target\n+ access_pattern=_damon_sysfs.DamosAccessPattern(\n+ size=[0, 2**64 - 1],\n+ nr_accesses=[0, 2**64 - 1],\n+ age=[0, 2**64 - 1]),\n+ apply_interval_us=0)])])])\n+ err = kdamonds.start()\n+ if err is not None:\n+ print('kdamonds start failed: %s' % err)\n+ os.kill(pid, signal.SIGKILL)\n+ exit(1)\n+\n+ # Let the scheme find and split the regions.\n+ after = before\n+ for _ in range(50):\n+ time.sleep(0.2)\n+ after = anon_huge_kb(pid)\n+ if after == 0:\n+ break\n+\n+ kdamonds.stop()\n+ os.kill(pid, signal.SIGKILL)\n+\n+ if after \u003e= before:\n+ print('FAIL: AnonHugePages did not shrink: before=%d KiB '\n+ 'after=%d KiB' % (before, after))\n+ exit(1)\n+ print('PASS: AnonHugePages %d KiB -\u003e %d KiB after DAMOS_SPLIT'\n+ % (before, after))\n+ finally:\n+ try:\n+ os.kill(pid, signal.SIGKILL)\n+ except ProcessLookupError:\n+ pass\n+\n+if __name__ == '__main__':\n+ main()\ndiff --git a/tools/testing/selftests/damon/sysfs.py b/tools/testing/selftests/damon/sysfs.py\nindex 3ffa054b63867d..49d3c319dfd898 100755\n--- a/tools/testing/selftests/damon/sysfs.py\n+++ b/tools/testing/selftests/damon/sysfs.py\n@@ -131,11 +131,12 @@ def assert_scheme_committed(scheme, dump):\n 'hugepage': 3,\n 'nohugepage': 4,\n 'collapse': 5,\n- 'lru_prio': 6,\n- 'lru_deprio': 7,\n- 'migrate_hot': 8,\n- 'migrate_cold': 9,\n- 'stat': 10,\n+ 'split': 6,\n+ 'lru_prio': 7,\n+ 'lru_deprio': 8,\n+ 'migrate_hot': 9,\n+ 'migrate_cold': 10,\n+ 'stat': 11,\n }\n assert_true(dump['action'] == action_val[scheme.action], 'action', dump)\n assert_true(dump['apply_interval_us'] == scheme. apply_interval_us,\n"
} |
| 2/1 | 2026/07/20 03:38 | agent | patch-evaluator |
1mModel:gemini-3.1-pro-preview Args: null Results: {
"EnableConfigs": [
"DAMON",
"DAMON_SYSFS",
"DAMON_VADDR",
"TRANSPARENT_HUGEPAGE"
],
"FocusSymbols": [
"damos_va_split",
"target_order_store",
"target_order_show"
],
"Reasoning": "The patch introduces a new DAMON action `DAMOS_SPLIT` to split large folios down to a specified order. It adds sysfs interfaces to configure the target order and implements the splitting logic in `damos_va_split` using `split_folio_to_order`. This is a functional change to the memory management subsystem and should be fuzzed to ensure the folio splitting logic and sysfs interface handle edge cases correctly.",
"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). 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. 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. Do not list too generic configs (we already have them enabled). Only list those that specifically cover the modified code. 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 7adf884411492e2d70200a1d4a5b2ae571a54db8
Author: syz-cluster <triage@syzkaller.com>
Date: Mon Jul 20 03:38:08 2026 +0000
syz-cluster: applied patch under review
diff --git a/Documentation/ABI/testing/sysfs-kernel-mm-damon b/Documentation/ABI/testing/sysfs-kernel-mm-damon
index 907a504fb64c54..ee8e260a631cf2 100644
--- a/Documentation/ABI/testing/sysfs-kernel-mm-damon
+++ b/Documentation/ABI/testing/sysfs-kernel-mm-damon
@@ -265,6 +265,13 @@ Contact: SJ Park <sj@kernel.org>
Description: Action's target NUMA node id. Supported by only relevant
actions.
+What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/target_order
+Date: Jul 2026
+Contact: SJ Park <sj@kernel.org>
+Description: Target folio order for the ``split`` action. Large folios in
+ the target region are split down to this order. Valid values
+ are 0 (order-0 base pages) and 2..HPAGE_PMD_ORDER-1.
+
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/apply_interval_us
Date: Sep 2023
Contact: SJ Park <sj@kernel.org>
diff --git a/Documentation/mm/damon/design.rst b/Documentation/mm/damon/design.rst
index aed6cb1cf48310..87a801954b1b30 100644
--- a/Documentation/mm/damon/design.rst
+++ b/Documentation/mm/damon/design.rst
@@ -549,6 +549,11 @@ that supports each action are as below.
Supported by ``vaddr`` and ``fvaddr`` operations set. When
TRANSPARENT_HUGEPAGE is disabled, the application of the action will just
fail.
+ - ``split``: Split each large folio in the region down to the order specified
+ by the scheme's ``target_order`` (``0`` for order-0 base pages, or
+ ``2..HPAGE_PMD_ORDER-1``). Supported by ``vaddr`` and ``fvaddr`` operations
+ set. When TRANSPARENT_HUGEPAGE is disabled, the application of the action
+ will just fail.
- ``lru_prio``: Prioritize the region on its LRU lists.
Supported by ``paddr`` operations set.
- ``lru_deprio``: Deprioritize the region on its LRU lists.
diff --git a/include/linux/damon.h b/include/linux/damon.h
index f69442a9d43128..88b61b900a36db 100644
--- a/include/linux/damon.h
+++ b/include/linux/damon.h
@@ -110,6 +110,7 @@ struct damon_target {
* @DAMOS_HUGEPAGE: Call ``madvise()`` for the region with MADV_HUGEPAGE.
* @DAMOS_NOHUGEPAGE: Call ``madvise()`` for the region with MADV_NOHUGEPAGE.
* @DAMOS_COLLAPSE: Call ``madvise()`` for the region with MADV_COLLAPSE.
+ * @DAMOS_SPLIT: Split each large folio in the region to a smaller order.
* @DAMOS_LRU_PRIO: Prioritize the region on its LRU lists.
* @DAMOS_LRU_DEPRIO: Deprioritize the region on its LRU lists.
* @DAMOS_MIGRATE_HOT: Migrate the regions prioritizing warmer regions.
@@ -130,6 +131,7 @@ enum damos_action {
DAMOS_HUGEPAGE,
DAMOS_NOHUGEPAGE,
DAMOS_COLLAPSE,
+ DAMOS_SPLIT,
DAMOS_LRU_PRIO,
DAMOS_LRU_DEPRIO,
DAMOS_MIGRATE_HOT,
@@ -582,10 +584,15 @@ struct damos {
struct damos_quota quota;
struct damos_watermarks wmarks;
union {
- struct {
- int target_nid;
- struct damos_migrate_dests migrate_dests;
- };
+ int target_nid;
+ struct damos_migrate_dests migrate_dests;
+ /*
+ * @order: target folio order for DAMOS_SPLIT.
+ * Split large folios down to this order. 0 for
+ * order-0 base pages, 2..HPAGE_PMD_ORDER-1 for
+ * smaller mTHP. Order-1 is rejected.
+ */
+ unsigned int order;
};
struct list_head core_filters;
struct list_head ops_filters;
diff --git a/mm/damon/core.c b/mm/damon/core.c
index 806a67d02a6e90..394c62455ad56b 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -693,6 +693,7 @@ struct damos *damon_new_scheme(struct damos_access_pattern *pattern,
return NULL;
scheme->pattern = *pattern;
scheme->action = action;
+ scheme->order = 0;
scheme->apply_interval_us = apply_interval_us;
/*
* next_apply_sis will be set when kdamond starts. While kdamond is
@@ -1446,6 +1447,7 @@ static int damos_commit(struct damos *dst, struct damos *src)
dst->pattern = src->pattern;
dst->action = src->action;
+ dst->order = src->order;
dst->apply_interval_us = src->apply_interval_us;
err = damos_commit_quota(&dst->quota, &src->quota);
diff --git a/mm/damon/sysfs-schemes.c b/mm/damon/sysfs-schemes.c
index 32f495a96b17a8..725ed81ccf6cac 100644
--- a/mm/damon/sysfs-schemes.c
+++ b/mm/damon/sysfs-schemes.c
@@ -4,7 +4,9 @@
*/
#include <linux/slab.h>
+#include <linux/mm.h>
#include <linux/numa.h>
+#include <linux/huge_mm.h>
#include "sysfs-common.h"
@@ -2260,6 +2262,7 @@ struct damon_sysfs_scheme {
struct damon_sysfs_stats *stats;
struct damon_sysfs_scheme_regions *tried_regions;
int target_nid;
+ unsigned int target_order;
struct damos_sysfs_dests *dests;
};
@@ -2293,6 +2296,10 @@ static struct damos_sysfs_action_name damos_sysfs_action_names[] = {
.action = DAMOS_COLLAPSE,
.name = "collapse",
},
+ {
+ .action = DAMOS_SPLIT,
+ .name = "split",
+ },
{
.action = DAMOS_LRU_PRIO,
.name = "lru_prio",
@@ -2326,6 +2333,7 @@ static struct damon_sysfs_scheme *damon_sysfs_scheme_alloc(
scheme->action = action;
scheme->apply_interval_us = apply_interval_us;
scheme->target_nid = NUMA_NO_NODE;
+ scheme->target_order = 0;
return scheme;
}
@@ -2645,6 +2653,40 @@ static ssize_t target_nid_store(struct kobject *kobj,
return err ? err : count;
}
+static ssize_t target_order_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct damon_sysfs_scheme *scheme = container_of(kobj,
+ struct damon_sysfs_scheme, kobj);
+
+ return sysfs_emit(buf, "%u\n", scheme->target_order);
+}
+
+static ssize_t target_order_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ struct damon_sysfs_scheme *scheme = container_of(kobj,
+ struct damon_sysfs_scheme, kobj);
+ unsigned int val;
+ int err;
+
+ err = kstrtouint(buf, 0, &val);
+ if (err)
+ return err;
+
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+ /* Valid split targets: 0 (order-0 base pages) or 2..HPAGE_PMD_ORDER-1. */
+ if (val != 0 && (val < 2 || val >= HPAGE_PMD_ORDER))
+ return -EINVAL;
+#else
+ if (val != 0)
+ return -EINVAL;
+#endif
+
+ scheme->target_order = val;
+ return count;
+}
+
static void damon_sysfs_scheme_release(struct kobject *kobj)
{
kfree(container_of(kobj, struct damon_sysfs_scheme, kobj));
@@ -2659,10 +2701,14 @@ static struct kobj_attribute damon_sysfs_scheme_apply_interval_us_attr =
static struct kobj_attribute damon_sysfs_scheme_target_nid_attr =
__ATTR_RW_MODE(target_nid, 0600);
+static struct kobj_attribute damon_sysfs_scheme_target_order_attr =
+ __ATTR_RW_MODE(target_order, 0600);
+
static struct attribute *damon_sysfs_scheme_attrs[] = {
&damon_sysfs_scheme_action_attr.attr,
&damon_sysfs_scheme_apply_interval_us_attr.attr,
&damon_sysfs_scheme_target_nid_attr.attr,
+ &damon_sysfs_scheme_target_order_attr.attr,
NULL,
};
ATTRIBUTE_GROUPS(damon_sysfs_scheme);
@@ -3011,6 +3057,8 @@ static struct damos *damon_sysfs_mk_scheme(
if (!scheme)
return NULL;
+ scheme->order = sysfs_scheme->target_order;
+
err = damos_sysfs_add_quota_score(sysfs_quotas->goals, &scheme->quota);
if (err) {
damon_destroy_scheme(scheme);
diff --git a/mm/damon/vaddr.c b/mm/damon/vaddr.c
index d10b8042adb5ba..a8607448584d55 100644
--- a/mm/damon/vaddr.c
+++ b/mm/damon/vaddr.c
@@ -6,6 +6,7 @@
#define pr_fmt(fmt) "damon-va: " fmt
#include <linux/highmem.h>
+#include <linux/huge_mm.h>
#include <linux/hugetlb.h>
#include <linux/mman.h>
#include <linux/mmu_notifier.h>
@@ -896,6 +897,111 @@ static unsigned long damos_va_stat(struct damon_target *target,
return 0;
}
+/*
+ * damos_va_split() - Split large folios in a region down to @target_order
+ * using the existing split_folio_to_order().
+ *
+ * Locking: folio_walk_start() returns the folio with the page table lock
+ * held. split_folio_to_order() must not run under the page table lock,
+ * so we pin the folio (reference + lock), end the walk to drop the page
+ * table lock, and split while holding only mmap_read_lock.
+ * split_folio_to_order() returns -EBUSY for a raced or pinned folio;
+ * we skip such folios.
+ */
+static unsigned long damos_va_split(struct damon_target *target,
+ struct damon_region *r, struct damos *s,
+ unsigned long *sz_filter_passed)
+{
+ unsigned int target_order = s->order;
+ unsigned long addr = ALIGN_DOWN(r->ar.start, PAGE_SIZE);
+ unsigned long end = r->ar.end;
+ unsigned long applied = 0;
+ struct mm_struct *mm;
+
+ mm = damon_get_mm(target);
+ if (!mm)
+ return 0;
+
+ while (addr < end) {
+ struct vm_area_struct *vma;
+ struct folio *folio;
+ struct folio_walk fw;
+ unsigned long folio_sz = 0;
+
+ if (mmap_read_lock_killable(mm))
+ break;
+
+ vma = vma_lookup(mm, addr);
+ if (!vma) {
+ /* Skip the gap to the next VMA, if any. */
+ vma = find_vma(mm, addr);
+ mmap_read_unlock(mm);
+ if (!vma || vma->vm_start >= end)
+ break;
+ addr = vma->vm_start;
+ continue;
+ }
+
+ /* Folios in these VMAs are not our business. */
+ if (vma->vm_flags & (VM_HUGETLB | VM_MIXEDMAP)) {
+ addr = vma->vm_end;
+ mmap_read_unlock(mm);
+ continue;
+ }
+
+ folio = folio_walk_start(&fw, vma, addr, 0);
+ if (!folio) {
+ mmap_read_unlock(mm);
+ addr += PAGE_SIZE;
+ continue;
+ }
+
+ folio_sz = folio_size(folio);
+
+ /*
+ * For file-backed folios, @target_order may be below the
+ * filesystem's minimum folio order (mapping_min_folio_order()).
+ * split_folio_to_order() will simply fail in that case and
+ * we skip the folio. This is a safe no-op; future work can
+ * adjust target_order upward like split_huge_pages_in_pid()
+ * does when a specific filesystem needs it.
+ */
+
+ /* Honour the scheme's operations-layer filters. */
+ if (damos_ops_has_filter(s)) {
+ if (damos_va_filter_out(s, folio, vma, addr,
+ fw.level == FW_LEVEL_PTE ? fw.ptep : NULL,
+ fw.level == FW_LEVEL_PMD ? fw.pmdp : NULL)) {
+ folio_walk_end(&fw, vma);
+ mmap_read_unlock(mm);
+ goto next;
+ }
+ *sz_filter_passed += folio_sz;
+ }
+
+ if (folio_order(folio) > target_order && folio_trylock(folio)) {
+ folio_get(folio);
+ /* Drop the page table lock before splitting. */
+ folio_walk_end(&fw, vma);
+
+ if (!split_folio_to_order(folio, target_order))
+ applied += folio_sz;
+
+ folio_unlock(folio);
+ folio_put(folio);
+ } else {
+ folio_walk_end(&fw, vma);
+ }
+ mmap_read_unlock(mm);
+next:
+ addr = ALIGN_DOWN(addr, folio_sz) + folio_sz;
+ cond_resched();
+ }
+
+ mmput(mm);
+ return applied;
+}
+
static unsigned long damon_va_apply_scheme(struct damon_ctx *ctx,
struct damon_target *t, struct damon_region *r,
struct damos *scheme, unsigned long *sz_filter_passed)
@@ -926,6 +1032,8 @@ static unsigned long damon_va_apply_scheme(struct damon_ctx *ctx,
return damos_va_migrate(t, r, scheme, sz_filter_passed);
case DAMOS_STAT:
return damos_va_stat(t, r, scheme, sz_filter_passed);
+ case DAMOS_SPLIT:
+ return damos_va_split(t, r, scheme, sz_filter_passed);
default:
/*
* DAMOS actions that are not yet supported by 'vaddr'.
diff --git a/tools/testing/selftests/damon/Makefile b/tools/testing/selftests/damon/Makefile
index ece244e5c5b95c..a623c271355ffe 100644
--- a/tools/testing/selftests/damon/Makefile
+++ b/tools/testing/selftests/damon/Makefile
@@ -12,6 +12,7 @@ TEST_PROGS += sysfs.sh
TEST_PROGS += sysfs.py
TEST_PROGS += sysfs_update_schemes_tried_regions_wss_estimation.py
TEST_PROGS += damos_quota.py damos_quota_goal.py damos_apply_interval.py
+TEST_PROGS += damos_split.py
TEST_PROGS += damos_tried_regions.py damon_nr_regions.py
TEST_PROGS += sysfs_refresh.py
TEST_PROGS += reclaim.sh lru_sort.sh
diff --git a/tools/testing/selftests/damon/_damon_sysfs.py b/tools/testing/selftests/damon/_damon_sysfs.py
index e6a2265d721e8b..5a01f31ad9f26d 100644
--- a/tools/testing/selftests/damon/_damon_sysfs.py
+++ b/tools/testing/selftests/damon/_damon_sysfs.py
@@ -419,6 +419,7 @@ class Damos:
filters = None
apply_interval_us = None
target_nid = None
+ target_order = None
dests = None
idx = None
context = None
@@ -429,7 +430,7 @@ class Damos:
def __init__(self, action='stat', access_pattern=DamosAccessPattern(),
quota=DamosQuota(), watermarks=DamosWatermarks(),
core_filters=[], ops_filters=[], filters=[], target_nid=0,
- dests=DamosDests(), apply_interval_us=0):
+ target_order=0, dests=DamosDests(), apply_interval_us=0):
self.action = action
self.access_pattern = access_pattern
self.access_pattern.scheme = self
@@ -448,6 +449,7 @@ class Damos:
self.filters.scheme = self
self.target_nid = target_nid
+ self.target_order = target_order
self.dests = dests
self.dests.scheme = self
@@ -492,6 +494,11 @@ class Damos:
if err is not None:
return err
+ err = write_file(os.path.join(self.sysfs_dir(), 'target_order'), '%d' %
+ self.target_order)
+ if err is not None:
+ return err
+
err = self.dests.stage()
if err is not None:
return err
diff --git a/tools/testing/selftests/damon/damos_split.py b/tools/testing/selftests/damon/damos_split.py
new file mode 100644
index 00000000000000..089fbe0f0d4d3b
--- /dev/null
+++ b/tools/testing/selftests/damon/damos_split.py
@@ -0,0 +1,125 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0
+#
+# Functional test for the DAMOS_SPLIT action.
+#
+# A child process allocates a MADV_HUGEPAGE-backed anonymous region and
+# faults it in so that it is backed by (m)THPs. The parent then runs a
+# DAMON/DAMOS scheme with action 'split' and target_order 0 against the
+# child and checks that the huge pages are split into base pages, i.e. the
+# child's AnonHugePages (as reported by /proc/<pid>/smaps) drops.
+
+import ctypes
+import os
+import signal
+import sys
+import time
+
+import _damon_sysfs
+
+PMD_SIZE = 2 * 1024 * 1024
+MADV_HUGEPAGE = 14
+PROT_READ_WRITE = 0x1 | 0x2
+MAP_PRIVATE_ANON = 0x2 | 0x20
+REGION_SIZE = 32 * PMD_SIZE
+
+def child_workload():
+ '''Allocate a PMD-aligned, THP-backed region, fault it in, then idle.'''
+ libc = ctypes.CDLL('libc.so.6', use_errno=True)
+ libc.mmap.restype = ctypes.c_void_p
+ libc.mmap.argtypes = [ctypes.c_void_p, ctypes.c_size_t, ctypes.c_int,
+ ctypes.c_int, ctypes.c_int, ctypes.c_long]
+ libc.madvise.argtypes = [ctypes.c_void_p, ctypes.c_size_t, ctypes.c_int]
+
+ # Over-allocate so that a PMD-aligned window is available.
+ raw = libc.mmap(None, REGION_SIZE + PMD_SIZE, PROT_READ_WRITE,
+ MAP_PRIVATE_ANON, -1, 0)
+ if raw is None or raw == ctypes.c_void_p(-1).value:
+ os._exit(2)
+ base = (raw + PMD_SIZE - 1) & ~(PMD_SIZE - 1)
+ libc.madvise(ctypes.c_void_p(base), REGION_SIZE, MADV_HUGEPAGE)
+
+ buf = (ctypes.c_char * REGION_SIZE).from_address(base)
+ for off in range(0, REGION_SIZE, 4096):
+ buf[off] = 1
+
+ # Ready; idle until the parent tears us down.
+ signal.pause()
+
+def anon_huge_kb(pid):
+ total = 0
+ try:
+ with open('/proc/%d/smaps' % pid) as f:
+ for line in f:
+ if line.startswith('AnonHugePages:'):
+ total += int(line.split()[1])
+ except FileNotFoundError:
+ return -1
+ return total
+
+def main():
+ if not os.path.exists('/sys/kernel/mm/transparent_hugepage/enabled'):
+ print('SKIP: transparent hugepage is not available')
+ exit(0)
+
+ pid = os.fork()
+ if pid == 0:
+ child_workload()
+ os._exit(0)
+
+ try:
+ # Give the child time to fault in its huge pages.
+ time.sleep(2)
+ before = anon_huge_kb(pid)
+ if before <= 0:
+ print('SKIP: workload did not get any THP (AnonHugePages=%d)'
+ % before)
+ os.kill(pid, signal.SIGKILL)
+ exit(0)
+
+ # Split every large folio in the target down to order-0 base pages.
+ kdamonds = _damon_sysfs.Kdamonds([_damon_sysfs.Kdamond(
+ contexts=[_damon_sysfs.DamonCtx(
+ ops='vaddr',
+ targets=[_damon_sysfs.DamonTarget(pid=pid)],
+ schemes=[_damon_sysfs.Damos(
+ action='split',
+ target_order=0,
+ # match every region regardless of access/age/size, so
+ # the ARM64 stale-TLB blind spot cannot mask the target
+ access_pattern=_damon_sysfs.DamosAccessPattern(
+ size=[0, 2**64 - 1],
+ nr_accesses=[0, 2**64 - 1],
+ age=[0, 2**64 - 1]),
+ apply_interval_us=0)])])])
+ err = kdamonds.start()
+ if err is not None:
+ print('kdamonds start failed: %s' % err)
+ os.kill(pid, signal.SIGKILL)
+ exit(1)
+
+ # Let the scheme find and split the regions.
+ after = before
+ for _ in range(50):
+ time.sleep(0.2)
+ after = anon_huge_kb(pid)
+ if after == 0:
+ break
+
+ kdamonds.stop()
+ os.kill(pid, signal.SIGKILL)
+
+ if after >= before:
+ print('FAIL: AnonHugePages did not shrink: before=%d KiB '
+ 'after=%d KiB' % (before, after))
+ exit(1)
+ print('PASS: AnonHugePages %d KiB -> %d KiB after DAMOS_SPLIT'
+ % (before, after))
+ finally:
+ try:
+ os.kill(pid, signal.SIGKILL)
+ except ProcessLookupError:
+ pass
+
+if __name__ == '__main__':
+ main()
diff --git a/tools/testing/selftests/damon/sysfs.py b/tools/testing/selftests/damon/sysfs.py
index 3ffa054b63867d..49d3c319dfd898 100755
--- a/tools/testing/selftests/damon/sysfs.py
+++ b/tools/testing/selftests/damon/sysfs.py
@@ -131,11 +131,12 @@ def assert_scheme_committed(scheme, dump):
'hugepage': 3,
'nohugepage': 4,
'collapse': 5,
- 'lru_prio': 6,
- 'lru_deprio': 7,
- 'migrate_hot': 8,
- 'migrate_cold': 9,
- 'stat': 10,
+ 'split': 6,
+ 'lru_prio': 7,
+ 'lru_deprio': 8,
+ 'migrate_hot': 9,
+ 'migrate_cold': 10,
+ 'stat': 11,
}
assert_true(dump['action'] == action_val[scheme.action], 'action', dump)
assert_true(dump['apply_interval_us'] == scheme. apply_interval_us,
|
| 3/2 | 2026/07/20 03:38 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 8769 output: 19 thoughts: 475 Thoughts: **DAMON Split Action: Focused Assessment** Okay, so we've got this new patch series introducing a `DAMOS_SPLIT` action for DAMON. It sounds like this is going to be splitting large folios down to a defined order, which is definitely a functional change within the kernel's memory management. I need to zero in on this. First, I need to check the scope. The patch touches documentation, `damon.h`, core DAMON files, sysfs interaction, virtual address handling, and selftests. Seems pretty spread out. My immediate concern is the `mm/damon/vaddr.c` file; specifically, the new `damos_va_split` function which presumably is the core of this. It looks like it uses `split_folio_to_order` - this will need to be well-fuzzed. I'm thinking the key areas to analyze will be `damos_va_split`, then the sysfs interface handlers for the split functionality: `target_order_store` and `target_order_show`. Configuration is key here. DAMON itself is enabled by `CONFIG_DAMON`, the sysfs interface by `CONFIG_DAMON_SYSFS`, and the virtual address operations by `CONFIG_DAMON_VADDR`. I also need to verify whether `split_folio_to_order` interacts with transparent hugepages, so I should look in `mm/damon/sysfs-schemes.c`. Aha! Looks like `CONFIG_TRANSPARENT_HUGEPAGE` is definitely relevant. The code checks for it. So this is a parameter of the split operation itself: `val` can be 0 or between 2 and `HPAGE_PMD_ORDER-1` if hugepages are enabled. If not, only 0 is allowed. Right, I'll need to run a `git grep` on this to confirm my understanding of the configs required for this functionality. I need to make sure I understand the conditional compilation and how that impacts the fuzzer's strategy. |
| 4/2 | 2026/07/20 03:38 | tool | grepper |
0mArgs:{
"Expression": "DAMON_SYSFS"
}Results: {
"Output": "Documentation/admin-guide/mm/damon/usage.rst=37=sysfs Interface\n--\nDocumentation/admin-guide/mm/damon/usage.rst-39-\nDocumentation/admin-guide/mm/damon/usage.rst:40:DAMON sysfs interface is built when ``CONFIG_DAMON_SYSFS`` is defined. It\nDocumentation/admin-guide/mm/damon/usage.rst-41-creates multiple directories and files under its sysfs directory,\n--\nDocumentation/translations/zh_CN/admin-guide/mm/damon/usage.rst=35=sysfs接口\nDocumentation/translations/zh_CN/admin-guide/mm/damon/usage.rst-36-=========\nDocumentation/translations/zh_CN/admin-guide/mm/damon/usage.rst:37:DAMON的sysfs接口是在定义 ``CONFIG_DAMON_SYSFS`` 时建立的。它在其sysfs目录下创建多\nDocumentation/translations/zh_CN/admin-guide/mm/damon/usage.rst-38-个目录和文件, ``\u003csysfs\u003e/kernel/mm/damon/`` 。你可以通过对该目录下的文件进行写入和\n--\nDocumentation/translations/zh_TW/admin-guide/mm/damon/usage.rst=35=sysfs接口\nDocumentation/translations/zh_TW/admin-guide/mm/damon/usage.rst-36-=========\nDocumentation/translations/zh_TW/admin-guide/mm/damon/usage.rst:37:DAMON的sysfs接口是在定義 ``CONFIG_DAMON_SYSFS`` 時建立的。它在其sysfs目錄下創建多\nDocumentation/translations/zh_TW/admin-guide/mm/damon/usage.rst-38-個目錄和文件, ``\u003csysfs\u003e/kernel/mm/damon/`` 。你可以通過對該目錄下的文件進行寫入和\n--\nmm/damon/Kconfig=56=config DAMON_VADDR_KUNIT_TEST\n--\nmm/damon/Kconfig-67-\nmm/damon/Kconfig:68:config DAMON_SYSFS\nmm/damon/Kconfig-69-\tbool \"DAMON sysfs interface\"\n--\nmm/damon/Kconfig-75-\nmm/damon/Kconfig:76:config DAMON_SYSFS_KUNIT_TEST\nmm/damon/Kconfig-77-\tbool \"Test for damon sysfs interface\" if !KUNIT_ALL_TESTS\nmm/damon/Kconfig:78:\tdepends on DAMON_SYSFS \u0026\u0026 KUNIT=y\nmm/damon/Kconfig-79-\tdefault KUNIT_ALL_TESTS\n--\nmm/damon/Makefile=5=obj-$(CONFIG_DAMON_PADDR)\t+= ops-common.o paddr.o\nmm/damon/Makefile:6:obj-$(CONFIG_DAMON_SYSFS)\t+= sysfs-common.o sysfs-schemes.o sysfs.o\nmm/damon/Makefile-7-obj-$(CONFIG_DAMON_RECLAIM)\t+= modules-common.o reclaim.o\n--\nmm/damon/sysfs.c=1829=enum damon_sysfs_cmd {\nmm/damon/sysfs.c:1830:\t/* @DAMON_SYSFS_CMD_ON: Turn the kdamond on. */\nmm/damon/sysfs.c:1831:\tDAMON_SYSFS_CMD_ON,\nmm/damon/sysfs.c:1832:\t/* @DAMON_SYSFS_CMD_OFF: Turn the kdamond off. */\nmm/damon/sysfs.c:1833:\tDAMON_SYSFS_CMD_OFF,\nmm/damon/sysfs.c:1834:\t/* @DAMON_SYSFS_CMD_COMMIT: Update kdamond inputs. */\nmm/damon/sysfs.c:1835:\tDAMON_SYSFS_CMD_COMMIT,\nmm/damon/sysfs.c-1836-\t/*\nmm/damon/sysfs.c:1837:\t * @DAMON_SYSFS_CMD_COMMIT_SCHEMES_QUOTA_GOALS: Commit the quota goals\nmm/damon/sysfs.c-1838-\t * to DAMON.\nmm/damon/sysfs.c-1839-\t */\nmm/damon/sysfs.c:1840:\tDAMON_SYSFS_CMD_COMMIT_SCHEMES_QUOTA_GOALS,\nmm/damon/sysfs.c-1841-\t/*\nmm/damon/sysfs.c:1842:\t * @DAMON_SYSFS_CMD_UPDATE_SCHEMES_STATS: Update scheme stats sysfs\nmm/damon/sysfs.c-1843-\t * files.\nmm/damon/sysfs.c-1844-\t */\nmm/damon/sysfs.c:1845:\tDAMON_SYSFS_CMD_UPDATE_SCHEMES_STATS,\nmm/damon/sysfs.c-1846-\t/*\nmm/damon/sysfs.c:1847:\t * @DAMON_SYSFS_CMD_UPDATE_SCHEMES_TRIED_BYTES: Update\nmm/damon/sysfs.c-1848-\t * tried_regions/total_bytes sysfs files for each scheme.\nmm/damon/sysfs.c-1849-\t */\nmm/damon/sysfs.c:1850:\tDAMON_SYSFS_CMD_UPDATE_SCHEMES_TRIED_BYTES,\nmm/damon/sysfs.c-1851-\t/*\nmm/damon/sysfs.c:1852:\t * @DAMON_SYSFS_CMD_UPDATE_SCHEMES_TRIED_REGIONS: Update schemes tried\nmm/damon/sysfs.c-1853-\t * regions\nmm/damon/sysfs.c-1854-\t */\nmm/damon/sysfs.c:1855:\tDAMON_SYSFS_CMD_UPDATE_SCHEMES_TRIED_REGIONS,\nmm/damon/sysfs.c-1856-\t/*\nmm/damon/sysfs.c:1857:\t * @DAMON_SYSFS_CMD_CLEAR_SCHEMES_TRIED_REGIONS: Clear schemes tried\nmm/damon/sysfs.c-1858-\t * regions\nmm/damon/sysfs.c-1859-\t */\nmm/damon/sysfs.c:1860:\tDAMON_SYSFS_CMD_CLEAR_SCHEMES_TRIED_REGIONS,\nmm/damon/sysfs.c-1861-\t/*\nmm/damon/sysfs.c:1862:\t * @DAMON_SYSFS_CMD_UPDATE_SCHEMES_EFFECTIVE_QUOTAS: Update the\nmm/damon/sysfs.c-1863-\t * effective size quota of the scheme in bytes.\nmm/damon/sysfs.c-1864-\t */\nmm/damon/sysfs.c:1865:\tDAMON_SYSFS_CMD_UPDATE_SCHEMES_EFFECTIVE_QUOTAS,\nmm/damon/sysfs.c-1866-\t/*\nmm/damon/sysfs.c:1867:\t * @DAMON_SYSFS_CMD_UPDATE_TUNED_INTERVALS: Update the tuned monitoring\nmm/damon/sysfs.c-1868-\t * intervals.\nmm/damon/sysfs.c-1869-\t */\nmm/damon/sysfs.c:1870:\tDAMON_SYSFS_CMD_UPDATE_TUNED_INTERVALS,\nmm/damon/sysfs.c-1871-\t/*\nmm/damon/sysfs.c:1872:\t * @NR_DAMON_SYSFS_CMDS: Total number of DAMON sysfs commands.\nmm/damon/sysfs.c-1873-\t */\nmm/damon/sysfs.c:1874:\tNR_DAMON_SYSFS_CMDS,\nmm/damon/sysfs.c-1875-};\n--\nmm/damon/sysfs.c=1891=static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr,\n--\nmm/damon/sysfs.c-1908-\treturn sysfs_emit(buf, \"%s\\n\", running ?\nmm/damon/sysfs.c:1909:\t\t\tdamon_sysfs_cmd_strs[DAMON_SYSFS_CMD_ON] :\nmm/damon/sysfs.c:1910:\t\t\tdamon_sysfs_cmd_strs[DAMON_SYSFS_CMD_OFF]);\nmm/damon/sysfs.c-1911-}\n--\nmm/damon/sysfs.c=2362=static int damon_sysfs_handle_cmd(enum damon_sysfs_cmd cmd,\n--\nmm/damon/sysfs.c-2364-{\nmm/damon/sysfs.c:2365:\tif (cmd != DAMON_SYSFS_CMD_OFF \u0026\u0026 kdamond-\u003econtexts-\u003enr != 1)\nmm/damon/sysfs.c-2366-\t\treturn -EINVAL;\n--\nmm/damon/sysfs.c-2368-\tswitch (cmd) {\nmm/damon/sysfs.c:2369:\tcase DAMON_SYSFS_CMD_ON:\nmm/damon/sysfs.c-2370-\t\treturn damon_sysfs_turn_damon_on(kdamond);\nmm/damon/sysfs.c:2371:\tcase DAMON_SYSFS_CMD_OFF:\nmm/damon/sysfs.c-2372-\t\treturn damon_sysfs_turn_damon_off(kdamond);\nmm/damon/sysfs.c:2373:\tcase DAMON_SYSFS_CMD_COMMIT:\nmm/damon/sysfs.c-2374-\t\treturn damon_sysfs_damon_call(\nmm/damon/sysfs.c-2375-\t\t\t\tdamon_sysfs_commit_input, kdamond);\nmm/damon/sysfs.c:2376:\tcase DAMON_SYSFS_CMD_COMMIT_SCHEMES_QUOTA_GOALS:\nmm/damon/sysfs.c-2377-\t\treturn damon_sysfs_damon_call(\n--\nmm/damon/sysfs.c-2379-\t\t\t\tkdamond);\nmm/damon/sysfs.c:2380:\tcase DAMON_SYSFS_CMD_UPDATE_SCHEMES_STATS:\nmm/damon/sysfs.c-2381-\t\treturn damon_sysfs_damon_call(\nmm/damon/sysfs.c-2382-\t\t\t\tdamon_sysfs_upd_schemes_stats, kdamond);\nmm/damon/sysfs.c:2383:\tcase DAMON_SYSFS_CMD_UPDATE_SCHEMES_TRIED_BYTES:\nmm/damon/sysfs.c-2384-\t\treturn damon_sysfs_update_schemes_tried_regions(kdamond, true);\nmm/damon/sysfs.c:2385:\tcase DAMON_SYSFS_CMD_UPDATE_SCHEMES_TRIED_REGIONS:\nmm/damon/sysfs.c-2386-\t\treturn damon_sysfs_update_schemes_tried_regions(kdamond, false);\nmm/damon/sysfs.c:2387:\tcase DAMON_SYSFS_CMD_CLEAR_SCHEMES_TRIED_REGIONS:\nmm/damon/sysfs.c-2388-\t\treturn damon_sysfs_schemes_clear_regions(\nmm/damon/sysfs.c-2389-\t\t\tkdamond-\u003econtexts-\u003econtexts_arr[0]-\u003eschemes);\nmm/damon/sysfs.c:2390:\tcase DAMON_SYSFS_CMD_UPDATE_SCHEMES_EFFECTIVE_QUOTAS:\nmm/damon/sysfs.c-2391-\t\treturn damon_sysfs_damon_call(\n--\nmm/damon/sysfs.c-2393-\t\t\t\tkdamond);\nmm/damon/sysfs.c:2394:\tcase DAMON_SYSFS_CMD_UPDATE_TUNED_INTERVALS:\nmm/damon/sysfs.c-2395-\t\treturn damon_sysfs_damon_call(\n--\nmm/damon/sysfs.c=2402=static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,\n--\nmm/damon/sysfs.c-2411-\t\treturn -EBUSY;\nmm/damon/sysfs.c:2412:\tfor (cmd = 0; cmd \u003c NR_DAMON_SYSFS_CMDS; cmd++) {\nmm/damon/sysfs.c-2413-\t\tif (sysfs_streq(buf, damon_sysfs_cmd_strs[cmd])) {\n--\nmm/damon/tests/.kunitconfig=13=CONFIG_SYSFS=y\nmm/damon/tests/.kunitconfig:14:CONFIG_DAMON_SYSFS=y\nmm/damon/tests/.kunitconfig:15:CONFIG_DAMON_SYSFS_KUNIT_TEST=y\nmm/damon/tests/.kunitconfig-16-\n--\nmm/damon/tests/sysfs-kunit.h-5-\nmm/damon/tests/sysfs-kunit.h:6:#ifdef CONFIG_DAMON_SYSFS_KUNIT_TEST\nmm/damon/tests/sysfs-kunit.h-7-\nmm/damon/tests/sysfs-kunit.h:8:#ifndef _DAMON_SYSFS_TEST_H\nmm/damon/tests/sysfs-kunit.h:9:#define _DAMON_SYSFS_TEST_H\nmm/damon/tests/sysfs-kunit.h-10-\n--\nmm/damon/tests/sysfs-kunit.h=106=kunit_test_suite(damon_sysfs_test_suite);\nmm/damon/tests/sysfs-kunit.h-107-\nmm/damon/tests/sysfs-kunit.h:108:#endif /* _DAMON_SYSFS_TEST_H */\nmm/damon/tests/sysfs-kunit.h-109-\nmm/damon/tests/sysfs-kunit.h:110:#endif /* CONFIG_DAMON_SYSFS_KUNIT_TEST */\n--\ntools/testing/selftests/damon/config=1=CONFIG_DAMON=y\ntools/testing/selftests/damon/config:2:CONFIG_DAMON_SYSFS=y\ntools/testing/selftests/damon/config-3-CONFIG_DAMON_PADDR=y\n"
} |
| 5/2 | 2026/07/20 03:38 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 13475 output: 19 thoughts: 48 Thoughts: Okay, here's my interpretation of those thoughts, framed as my own: **Config Checks and Dependencies** Right, so I'm looking at a set of configurations – `DAMON`, `DAMON_SYSFS`, `DAMON_VADDR`, and `TRANSPARENT_HUGEPAGE`. Seems like a pretty standard set of DAMON-related features. Before I go too far, let's just make sure `DAMON_VADDR` is actually a valid config option. Gotta verify these things, especially when dealing with potentially complex dependencies. A quick sanity check now can save a lot of headaches later on down the line. We don't want to waste time down a rabbit hole for something that does not exist. |
| 6/2 | 2026/07/20 03:38 | tool | grepper |
0mArgs:{
"Expression": "DAMON_VADDR"
}Results: {
"Output": "mm/damon/Kconfig=26=config DAMON_KUNIT_TEST\n--\nmm/damon/Kconfig-37-\nmm/damon/Kconfig:38:config DAMON_VADDR\nmm/damon/Kconfig-39-\tbool \"Data access monitoring operations for virtual address spaces\"\n--\nmm/damon/Kconfig=47=config DAMON_PADDR\n--\nmm/damon/Kconfig-55-\nmm/damon/Kconfig:56:config DAMON_VADDR_KUNIT_TEST\nmm/damon/Kconfig-57-\tbool \"Test for DAMON operations\" if !KUNIT_ALL_TESTS\nmm/damon/Kconfig:58:\tdepends on DAMON_VADDR \u0026\u0026 KUNIT=y\nmm/damon/Kconfig-59-\tdefault KUNIT_ALL_TESTS\n--\nmm/damon/Makefile=3=obj-y\t\t\t\t:= core.o\nmm/damon/Makefile:4:obj-$(CONFIG_DAMON_VADDR)\t+= ops-common.o vaddr.o\nmm/damon/Makefile-5-obj-$(CONFIG_DAMON_PADDR)\t+= ops-common.o paddr.o\n--\nmm/damon/tests/.kunitconfig=8=CONFIG_PAGE_IDLE_FLAG=y\nmm/damon/tests/.kunitconfig:9:CONFIG_DAMON_VADDR=y\nmm/damon/tests/.kunitconfig:10:CONFIG_DAMON_VADDR_KUNIT_TEST=y\nmm/damon/tests/.kunitconfig-11-\n--\nmm/damon/tests/core-kunit.h=403=static void damon_test_ops_registration(struct kunit *test)\n--\nmm/damon/tests/core-kunit.h-411-\nmm/damon/tests/core-kunit.h:412:\t/* DAMON_OPS_VADDR is registered only if CONFIG_DAMON_VADDR is set */\nmm/damon/tests/core-kunit.h-413-\tif (!damon_is_registered_ops(DAMON_OPS_VADDR)) {\n--\nmm/damon/tests/vaddr-kunit.h-5-\nmm/damon/tests/vaddr-kunit.h:6:#ifdef CONFIG_DAMON_VADDR_KUNIT_TEST\nmm/damon/tests/vaddr-kunit.h-7-\nmm/damon/tests/vaddr-kunit.h:8:#ifndef _DAMON_VADDR_TEST_H\nmm/damon/tests/vaddr-kunit.h:9:#define _DAMON_VADDR_TEST_H\nmm/damon/tests/vaddr-kunit.h-10-\n--\nmm/damon/tests/vaddr-kunit.h=277=kunit_test_suite(damon_test_suite);\nmm/damon/tests/vaddr-kunit.h-278-\nmm/damon/tests/vaddr-kunit.h:279:#endif /* _DAMON_VADDR_TEST_H */\nmm/damon/tests/vaddr-kunit.h-280-\nmm/damon/tests/vaddr-kunit.h:281:#endif\t/* CONFIG_DAMON_VADDR_KUNIT_TEST */\n--\nmm/damon/vaddr.c-20-\nmm/damon/vaddr.c:21:#ifdef CONFIG_DAMON_VADDR_KUNIT_TEST\nmm/damon/vaddr.c-22-#undef DAMON_MIN_REGION_SZ\n--\nsamples/damon/Kconfig=5=config SAMPLE_DAMON_WSSE\nsamples/damon/Kconfig-6-\tbool \"DAMON sample module for working set size estimation\"\nsamples/damon/Kconfig:7:\tdepends on DAMON \u0026\u0026 DAMON_VADDR\nsamples/damon/Kconfig-8-\thelp\n--\nsamples/damon/Kconfig=17=config SAMPLE_DAMON_PRCL\nsamples/damon/Kconfig-18-\tbool \"DAMON sample module for access-aware proactive reclamation\"\nsamples/damon/Kconfig:19:\tdepends on DAMON \u0026\u0026 DAMON_VADDR\nsamples/damon/Kconfig-20-\thelp\n--\ntools/testing/kunit/configs/all_tests.config=39=CONFIG_DAMON=y\ntools/testing/kunit/configs/all_tests.config:40:CONFIG_DAMON_VADDR=y\ntools/testing/kunit/configs/all_tests.config-41-CONFIG_DAMON_PADDR=y\n--\ntools/testing/selftests/damon/config=3=CONFIG_DAMON_PADDR=y\ntools/testing/selftests/damon/config:4:CONFIG_DAMON_VADDR=y\ntools/testing/selftests/damon/config-5-CONFIG_DAMON_RECLAIM=y\n"
} |
| 7/2 | 2026/07/20 03:38 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 14918 output: 19 thoughts: 253 Thoughts: **My Analysis of the DAMON Configuration and Reachability** Okay, so I'm confirming that `DAMON_VADDR` is indeed a configuration option, that's good to know. The key configurations I need to keep in mind are `DAMON`, `DAMON_SYSFS`, `DAMON_VADDR`, and also the ever-present `TRANSPARENT_HUGEPAGE`. I always need to consider THP in these scenarios. Now, let's trace the path to `split_folio_to_order`. I need to ensure it's accessible. Right, so `damos_va_split` gets called from `damon_va_apply_scheme` when the action is `DAMOS_SPLIT`. `damon_va_apply_scheme` is subsequently called by `damon_va_apply_three_regions`, which itself is called by `damon_va_apply_schemes`, then by `damon_do_apply_schemes` and finally, that’s invoked by `kdamond_fn`. And from there, it appears this entire sequence is reachable from userspace through the sysfs interface. Excellent, that gives me a clear idea of the potential attack vectors. Therefore, the functions I need to focus my attention on are: `damos_va_split`, `target_order_store`, and `target_order_show`. I'm going to double check those, specifically the `target_order` functions, to confirm their behavior. I'll find them in `mm/damon/sysfs-schemes.c`. |
| 8/2 | 2026/07/20 03:38 | tool | grepper |
0mArgs:{
"Expression": "target_order_store"
}Results: {
"Output": "mm/damon/sysfs-schemes.c=2656=static ssize_t target_order_show(struct kobject *kobj,\n--\nmm/damon/sysfs-schemes.c-2664-\nmm/damon/sysfs-schemes.c:2665:static ssize_t target_order_store(struct kobject *kobj,\nmm/damon/sysfs-schemes.c-2666-\t\tstruct kobj_attribute *attr, const char *buf, size_t count)\n"
} |
| 9/2 | 2026/07/20 03:38 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 15677 output: 20 thoughts: 24 Thoughts: Here's my summary, as if I were thinking these thoughts: **Investigating a DAMOS Virtual Address Split** Okay, time to dig into this. I need to refresh my memory on the virtual address split functionality in the DAMOS memory management code. Let's start by looking at `damos_va_split` within `mm/damon/vaddr.c`. I expect to find the core logic for how the virtual address space is segmented and handled there. I'll be looking for how the code determines the splitting points and the implications it has on memory management. This is a critical function for DAMON's operation, so understanding it completely is paramount. Let's dive in. |
| 10/2 | 2026/07/20 03:38 | tool | grepper |
0mArgs:{
"Expression": "damos_va_split"
}Results: {
"Output": "mm/damon/vaddr.c=875=static unsigned long damos_va_stat(struct damon_target *target,\n--\nmm/damon/vaddr.c-900-/*\nmm/damon/vaddr.c:901: * damos_va_split() - Split large folios in a region down to @target_order\nmm/damon/vaddr.c-902- * using the existing split_folio_to_order().\n--\nmm/damon/vaddr.c-910- */\nmm/damon/vaddr.c:911:static unsigned long damos_va_split(struct damon_target *target,\nmm/damon/vaddr.c-912-\t\tstruct damon_region *r, struct damos *s,\n--\nmm/damon/vaddr.c=1005=static unsigned long damon_va_apply_scheme(struct damon_ctx *ctx,\n--\nmm/damon/vaddr.c-1035-\tcase DAMOS_SPLIT:\nmm/damon/vaddr.c:1036:\t\treturn damos_va_split(t, r, scheme, sz_filter_passed);\nmm/damon/vaddr.c-1037-\tdefault:\n"
} |
| 11/2 | 2026/07/20 03:38 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 16192 output: 23 thoughts: 140 Thoughts: **Initial Assessment of the DAMON Patch** Okay, so this patch introduces a couple of key additions: a new sysfs file called `target_order`, and a new action, `split`. The core functionality seems to be within the `damos_va_split` function, which is responsible for iterating through VMAs and splitting folios. From a cursory glance, it appears functionally sound. This definitely warrants some fuzzing; it's the kind of code that's ripe for finding edge cases and potential vulnerabilities. I should also note the relevant configuration options that will be needed: `DAMON`, `DAMON_SYSFS`, `DAMON_VADDR`, and `TRANSPARENT_HUGEPAGE`. I'll need to keep those in mind for my testing environment setup. The most important symbols for me to focus on here are `damos_va_split`, obviously, and then the sysfs file handlers `target_order_store` and `target_order_show`. Those will provide crucial control over the new behavior. Just to be thorough, I should quickly scan the code to verify that `damos_va_split` is the only added function. I don't want to miss anything. |
| 12/2 | 2026/07/20 03:38 | tool | grepper |
0mArgs:{
"Expression": "^static.*damos_va_split"
}Results: {
"Output": "mm/damon/vaddr.c=875=static unsigned long damos_va_stat(struct damon_target *target,\n--\nmm/damon/vaddr.c-910- */\nmm/damon/vaddr.c:911:static unsigned long damos_va_split(struct damon_target *target,\nmm/damon/vaddr.c-912-\t\tstruct damon_region *r, struct damos *s,\n"
} |
| 13/2 | 2026/07/20 03:39 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 16737 output: 21 thoughts: 24 Thoughts: Okay, let's dive into this. Here's my thought process on what I'm about to do: **Checking for Related Functionality in the Kernel's sysfs Schemes** Alright, I need to investigate something in this kernel module, specifically `mm/damon/sysfs-schemes.c`. My immediate thought is, "I should probably verify if any additional functions have been added to that file." I know the codebase reasonably well, but it's always a good practice to double-check, especially after a period away, or if significant changes have been made recently. It's about ensuring I have the full picture before I start making any assumptions or going deeper into any one area. I'm looking for anything that might influence my understanding of the system's overall behavior or relate to what I'm working on right now. A quick scan will prevent surprises down the road. |
| 14/2 | 2026/07/20 03:39 | tool | grepper |
0mArgs:{
"Expression": "^static.*target_order_"
}Results: {
"Output": "mm/damon/sysfs-schemes.c=2644=static ssize_t target_nid_store(struct kobject *kobj,\n--\nmm/damon/sysfs-schemes.c-2655-\nmm/damon/sysfs-schemes.c:2656:static ssize_t target_order_show(struct kobject *kobj,\nmm/damon/sysfs-schemes.c-2657-\t\tstruct kobj_attribute *attr, char *buf)\n--\nmm/damon/sysfs-schemes.c-2664-\nmm/damon/sysfs-schemes.c:2665:static ssize_t target_order_store(struct kobject *kobj,\nmm/damon/sysfs-schemes.c-2666-\t\tstruct kobj_attribute *attr, const char *buf, size_t count)\n--\nmm/damon/sysfs-schemes.c=2701=static struct kobj_attribute damon_sysfs_scheme_target_nid_attr =\n--\nmm/damon/sysfs-schemes.c-2703-\nmm/damon/sysfs-schemes.c:2704:static struct kobj_attribute damon_sysfs_scheme_target_order_attr =\nmm/damon/sysfs-schemes.c-2705-\t\t__ATTR_RW_MODE(target_order, 0600);\n"
} |
| 15/2 | 2026/07/20 03:39 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 17341 output: 177 thoughts: 209 Thoughts: **My Assessment of the DAMON Folio Splitting Patch** Okay, so this patch is introducing some interesting functionality into DAMON, specifically the ability to split large folios down to a specified order via a new `DAMOS_SPLIT` action. I see three key functions involved: `damos_va_split`, `target_order_store`, and `target_order_show`. From a high-level perspective, I understand this means we're adding both a functional change to the memory management subsystem *and* a new sysfs interface to control it. The core logic for the split itself seems to be within `damos_va_split`, leveraging `split_folio_to_order`. Given my expertise, this immediately triggers a mental checklist: **FUZZING!** This is a prime target for fuzzing. We need to rigorously test the folio splitting logic, particularly in `damos_va_split`, and the interaction with the new sysfs interface, `target_order_store` and `target_order_show`. Edge cases are going to be critical here: what happens with very large folios, minimal target orders, or potential race conditions? The specified configurations of `DAMON`, `DAMON_SYSFS`, `DAMON_VADDR`, and `TRANSPARENT_HUGEPAGE` all make sense given the scope of the change and should be considered during testing, to establish the conditions in which this feature will be used and how they may effect the testing process. The critical symbols that I will focus on during investigation are: `damos_va_split`, `target_order_store` and `target_order_show`. I'm ready to move on to the next step, so I will now call `set-results`. |
| 16/2 | 2026/07/20 03:39 | tool | set-results |
0mArgs:{
"EnableConfigs": [
"DAMON",
"DAMON_SYSFS",
"DAMON_VADDR",
"TRANSPARENT_HUGEPAGE"
],
"FocusSymbols": [
"damos_va_split",
"target_order_store",
"target_order_show"
],
"Reasoning": "The patch introduces a new DAMON action `DAMOS_SPLIT` to split large folios down to a specified order. It adds sysfs interfaces to configure the target order and implements the splitting logic in `damos_va_split` using `split_folio_to_order`. This is a functional change to the memory management subsystem and should be fuzzed to ensure the folio splitting logic and sysfs interface handle edge cases correctly.",
"WorthFuzzing": true
}Results: {
"EnableConfigs": [
"DAMON",
"DAMON_SYSFS",
"DAMON_VADDR",
"TRANSPARENT_HUGEPAGE"
],
"FocusSymbols": [
"damos_va_split",
"target_order_store",
"target_order_show"
],
"Reasoning": "The patch introduces a new DAMON action `DAMOS_SPLIT` to split large folios down to a specified order. It adds sysfs interfaces to configure the target order and implements the splitting logic in `damos_va_split` using `split_folio_to_order`. This is a functional change to the memory management subsystem and should be fuzzed to ensure the folio splitting logic and sysfs interface handle edge cases correctly.",
"WorthFuzzing": true
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|