diff --git a/Documentation/ABI/stable/sysfs-devices-node b/Documentation/ABI/stable/sysfs-devices-node index 402af4b2b905f3e273ec9be14218ba8350d31295..cf5d8ac4805312f3dd83eb7567998d04fb627558 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 860f7bb099225dfa5814cf435e021aabb761fe92..1d9a3e3a8cde525ba9d7963de3695f947ecf69da 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 ab65898416d32f6eb1fa86fb03daecd5044fa946..eeb1974f00dac690bdc2bb6b4adff25e095a04bb 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.