Commit 76ab0f53 authored by Mel Gorman's avatar Mel Gorman Committed by Linus Torvalds

mm: compaction: add /proc trigger for memory compaction

Add a proc file /proc/sys/vm/compact_memory.  When an arbitrary value is
written to the file, all zones are compacted.  The expected user of such a
trigger is a job scheduler that prepares the system before the target
application runs.
Signed-off-by: default avatarMel Gorman <mel@csn.ul.ie>
Acked-by: default avatarRik van Riel <riel@redhat.com>
Reviewed-by: default avatarKAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Reviewed-by: default avatarMinchan Kim <minchan.kim@gmail.com>
Reviewed-by: default avatarKOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Reviewed-by: default avatarChristoph Lameter <cl@linux-foundation.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 748446bb
...@@ -19,6 +19,7 @@ files can be found in mm/swap.c. ...@@ -19,6 +19,7 @@ files can be found in mm/swap.c.
Currently, these files are in /proc/sys/vm: Currently, these files are in /proc/sys/vm:
- block_dump - block_dump
- compact_memory
- dirty_background_bytes - dirty_background_bytes
- dirty_background_ratio - dirty_background_ratio
- dirty_bytes - dirty_bytes
...@@ -64,6 +65,15 @@ information on block I/O debugging is in Documentation/laptops/laptop-mode.txt. ...@@ -64,6 +65,15 @@ information on block I/O debugging is in Documentation/laptops/laptop-mode.txt.
============================================================== ==============================================================
compact_memory
Available only when CONFIG_COMPACTION is set. When 1 is written to the file,
all zones are compacted such that free memory is available in contiguous
blocks where possible. This can be important for example in the allocation of
huge pages although processes will also directly compact memory as required.
==============================================================
dirty_background_bytes dirty_background_bytes
Contains the amount of dirty memory at which the pdflush background writeback Contains the amount of dirty memory at which the pdflush background writeback
......
...@@ -6,4 +6,10 @@ ...@@ -6,4 +6,10 @@
#define COMPACT_PARTIAL 1 #define COMPACT_PARTIAL 1
#define COMPACT_COMPLETE 2 #define COMPACT_COMPLETE 2
#ifdef CONFIG_COMPACTION
extern int sysctl_compact_memory;
extern int sysctl_compaction_handler(struct ctl_table *table, int write,
void __user *buffer, size_t *length, loff_t *ppos);
#endif /* CONFIG_COMPACTION */
#endif /* _LINUX_COMPACTION_H */ #endif /* _LINUX_COMPACTION_H */
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include <linux/highuid.h> #include <linux/highuid.h>
#include <linux/writeback.h> #include <linux/writeback.h>
#include <linux/ratelimit.h> #include <linux/ratelimit.h>
#include <linux/compaction.h>
#include <linux/hugetlb.h> #include <linux/hugetlb.h>
#include <linux/initrd.h> #include <linux/initrd.h>
#include <linux/key.h> #include <linux/key.h>
...@@ -1121,6 +1122,15 @@ static struct ctl_table vm_table[] = { ...@@ -1121,6 +1122,15 @@ static struct ctl_table vm_table[] = {
.mode = 0644, .mode = 0644,
.proc_handler = drop_caches_sysctl_handler, .proc_handler = drop_caches_sysctl_handler,
}, },
#ifdef CONFIG_COMPACTION
{
.procname = "compact_memory",
.data = &sysctl_compact_memory,
.maxlen = sizeof(int),
.mode = 0200,
.proc_handler = sysctl_compaction_handler,
},
#endif /* CONFIG_COMPACTION */
{ {
.procname = "min_free_kbytes", .procname = "min_free_kbytes",
.data = &min_free_kbytes, .data = &min_free_kbytes,
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/compaction.h> #include <linux/compaction.h>
#include <linux/mm_inline.h> #include <linux/mm_inline.h>
#include <linux/backing-dev.h> #include <linux/backing-dev.h>
#include <linux/sysctl.h>
#include "internal.h" #include "internal.h"
/* /*
...@@ -391,3 +392,64 @@ static int compact_zone(struct zone *zone, struct compact_control *cc) ...@@ -391,3 +392,64 @@ static int compact_zone(struct zone *zone, struct compact_control *cc)
return ret; return ret;
} }
/* Compact all zones within a node */
static int compact_node(int nid)
{
int zoneid;
pg_data_t *pgdat;
struct zone *zone;
if (nid < 0 || nid >= nr_node_ids || !node_online(nid))
return -EINVAL;
pgdat = NODE_DATA(nid);
/* Flush pending updates to the LRU lists */
lru_add_drain_all();
for (zoneid = 0; zoneid < MAX_NR_ZONES; zoneid++) {
struct compact_control cc = {
.nr_freepages = 0,
.nr_migratepages = 0,
};
zone = &pgdat->node_zones[zoneid];
if (!populated_zone(zone))
continue;
cc.zone = zone;
INIT_LIST_HEAD(&cc.freepages);
INIT_LIST_HEAD(&cc.migratepages);
compact_zone(zone, &cc);
VM_BUG_ON(!list_empty(&cc.freepages));
VM_BUG_ON(!list_empty(&cc.migratepages));
}
return 0;
}
/* Compact all nodes in the system */
static int compact_nodes(void)
{
int nid;
for_each_online_node(nid)
compact_node(nid);
return COMPACT_COMPLETE;
}
/* The written value is actually unused, all memory is compacted */
int sysctl_compact_memory;
/* This is the entry point for compacting all nodes via /proc/sys/vm */
int sysctl_compaction_handler(struct ctl_table *table, int write,
void __user *buffer, size_t *length, loff_t *ppos)
{
if (write)
return compact_nodes();
return 0;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment