From c786e46d79630170b7361582fc02cd2719bbf705 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B4=9F=E9=80=94?= Date: Thu, 18 Jun 2026 13:42:53 +0800 Subject: [PATCH] mm: support light compaction Current available interfaces only support compaction at the system or node level, which trigger large-scale memory movement. Tests show that such operations can heavily impact workloads and cause noticeable performance jitter. This patch adds a fine-grained compaction control interface in the kernel, allowing compaction on a specified ZONE with a specified SIZE. It scans possible page blocks within the given range and provides corresponding feedback on the compaction result. This enables targeted memory defragmentation while minimizing the impact on overall system performance. Adapted for 6.6 kernel: added target_migrated/nr_migrated fields to struct compact_control, removed VM_BUG_ON for freepages array change. Signed-off-by: Kaihao Bai Reviewed-by: Baolin Wang --- Documentation/ABI/stable/sysfs-devices-node | 9 ++-- mm/compaction.c | 54 ++++++++++++++++++++- mm/internal.h | 2 + 3 files changed, 61 insertions(+), 4 deletions(-) diff --git a/Documentation/ABI/stable/sysfs-devices-node b/Documentation/ABI/stable/sysfs-devices-node index 402af4b2b905..cf5d8ac48053 100644 --- a/Documentation/ABI/stable/sysfs-devices-node +++ b/Documentation/ABI/stable/sysfs-devices-node @@ -81,9 +81,12 @@ What: /sys/devices/system/node/nodeX/compact Date: February 2010 Contact: Mel Gorman Description: - When this file is written to, all memory within that node - will be compacted. When it completes, memory will be freed - into blocks which have as many contiguous pages as possible + When this file is written with the format "x", all memory + within that node will be compacted. When it completes, + memory will be freed into blocks which have as many contiguous + pages as possible. When written with the format “x,xxxK/M/G”, + the node will perform compaction in fixed quantities of the + specified size. What: /sys/devices/system/node/nodeX/hugepages/hugepages-/ Date: December 2009 diff --git a/mm/compaction.c b/mm/compaction.c index 860f7bb09922..1d9a3e3a8cde 100644 --- a/mm/compaction.c +++ b/mm/compaction.c @@ -2299,6 +2299,9 @@ static enum compact_result __compact_finished(struct compact_control *cc) const int migratetype = cc->migratetype; int ret; + if (cc->target_migrated && cc->target_migrated <= cc->nr_migrated) + return COMPACT_COMPLETE; + /* Compaction run completes if the migrate and free scanner meet */ if (compact_scanners_met(cc)) { /* Let the next compaction start anew. */ @@ -2713,7 +2716,7 @@ compact_zone(struct compact_control *cc, struct capture_control *capc) MR_COMPACTION, &nr_succeeded); trace_mm_compaction_migratepages(nr_migratepages, nr_succeeded); - + cc->nr_migrated += nr_succeeded; /* All pages were either migrated or will be released */ cc->nr_migratepages = 0; if (err) { @@ -2976,6 +2979,35 @@ static void proactive_compact_node(pg_data_t *pgdat) } } +/* Compact all zones within a node */ +static void light_compact_node(int nid, unsigned int nr_pages) +{ + pg_data_t *pgdat = NODE_DATA(nid); + int zoneid; + struct zone *zone; + struct compact_control cc = { + .order = -1, + .mode = MIGRATE_SYNC_LIGHT, + .ignore_skip_hint = true, + .whole_zone = false, + .target_migrated = nr_pages, + .nr_migrated = 0, + .gfp_mask = GFP_KERNEL, + }; + + + for (zoneid = MAX_NR_ZONES - 1; zoneid >= 0; zoneid--) { + + zone = &pgdat->node_zones[zoneid]; + if (!populated_zone(zone)) + continue; + + cc.zone = zone; + + compact_zone(&cc, NULL); + } +} + /* Compact all zones within a node */ static void compact_node(int nid) { @@ -3068,9 +3100,29 @@ static ssize_t compact_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { + unsigned long bytes; + unsigned int nr_pages; int nid = dev->id; + char *p, *s, *compact_size, *compact; if (nid >= 0 && nid < nr_node_ids && node_online(nid)) { + s = kstrdup(buf, GFP_KERNEL); + if (s == NULL) + return -ENOMEM; + + s = strstrip(s); + compact = strsep(&s, ","); + compact_size = strsep(&s, ","); + if (compact_size != NULL) { + bytes = memparse(compact_size, &p); + nr_pages = bytes / PAGE_SIZE; + if (nr_pages) + light_compact_node(nid, nr_pages); + + kfree(s); + return count; + } + kfree(s); /* Flush pending updates to the LRU lists */ lru_add_drain_all(); diff --git a/mm/internal.h b/mm/internal.h index ab65898416d3..eeb1974f00da 100644 --- a/mm/internal.h +++ b/mm/internal.h @@ -757,6 +757,8 @@ struct compact_control { struct list_head migratepages; /* List of pages being migrated */ unsigned int nr_freepages; /* Number of isolated free pages */ unsigned int nr_migratepages; /* Number of pages to migrate */ + unsigned int target_migrated; + unsigned int nr_migrated; unsigned long free_pfn; /* isolate_freepages search base */ /* * Acts as an in/out parameter to page isolation for migration. -- Gitee