diff options
author | Mel Gorman <mel@csn.ul.ie> | 2010-05-24 17:32:28 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-25 11:06:59 -0400 |
commit | 76ab0f530e4a01d4dc20cdc1d5e87753c579dc18 (patch) | |
tree | 8e1566df85e02f67876685c36d217fec4845f79f | |
parent | 748446bb6b5a9390b546af38ec899c868a9dbcf0 (diff) |
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: Mel Gorman <mel@csn.ul.ie>
Acked-by: Rik van Riel <riel@redhat.com>
Reviewed-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Reviewed-by: Minchan Kim <minchan.kim@gmail.com>
Reviewed-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Reviewed-by: Christoph Lameter <cl@linux-foundation.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | Documentation/sysctl/vm.txt | 10 | ||||
-rw-r--r-- | include/linux/compaction.h | 6 | ||||
-rw-r--r-- | kernel/sysctl.c | 10 | ||||
-rw-r--r-- | mm/compaction.c | 62 |
4 files changed, 88 insertions, 0 deletions
diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt index 6c7d18c53f84..56dd29b97a91 100644 --- a/Documentation/sysctl/vm.txt +++ b/Documentation/sysctl/vm.txt | |||
@@ -19,6 +19,7 @@ files can be found in mm/swap.c. | |||
19 | Currently, these files are in /proc/sys/vm: | 19 | Currently, these files are in /proc/sys/vm: |
20 | 20 | ||
21 | - block_dump | 21 | - block_dump |
22 | - compact_memory | ||
22 | - dirty_background_bytes | 23 | - dirty_background_bytes |
23 | - dirty_background_ratio | 24 | - dirty_background_ratio |
24 | - dirty_bytes | 25 | - dirty_bytes |
@@ -64,6 +65,15 @@ information on block I/O debugging is in Documentation/laptops/laptop-mode.txt. | |||
64 | 65 | ||
65 | ============================================================== | 66 | ============================================================== |
66 | 67 | ||
68 | compact_memory | ||
69 | |||
70 | Available only when CONFIG_COMPACTION is set. When 1 is written to the file, | ||
71 | all zones are compacted such that free memory is available in contiguous | ||
72 | blocks where possible. This can be important for example in the allocation of | ||
73 | huge pages although processes will also directly compact memory as required. | ||
74 | |||
75 | ============================================================== | ||
76 | |||
67 | dirty_background_bytes | 77 | dirty_background_bytes |
68 | 78 | ||
69 | Contains the amount of dirty memory at which the pdflush background writeback | 79 | Contains the amount of dirty memory at which the pdflush background writeback |
diff --git a/include/linux/compaction.h b/include/linux/compaction.h index 465ca88615ed..572388880ba8 100644 --- a/include/linux/compaction.h +++ b/include/linux/compaction.h | |||
@@ -6,4 +6,10 @@ | |||
6 | #define COMPACT_PARTIAL 1 | 6 | #define COMPACT_PARTIAL 1 |
7 | #define COMPACT_COMPLETE 2 | 7 | #define COMPACT_COMPLETE 2 |
8 | 8 | ||
9 | #ifdef CONFIG_COMPACTION | ||
10 | extern int sysctl_compact_memory; | ||
11 | extern int sysctl_compaction_handler(struct ctl_table *table, int write, | ||
12 | void __user *buffer, size_t *length, loff_t *ppos); | ||
13 | #endif /* CONFIG_COMPACTION */ | ||
14 | |||
9 | #endif /* _LINUX_COMPACTION_H */ | 15 | #endif /* _LINUX_COMPACTION_H */ |
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 4c93486b45d1..284f330d6a01 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <linux/highuid.h> | 37 | #include <linux/highuid.h> |
38 | #include <linux/writeback.h> | 38 | #include <linux/writeback.h> |
39 | #include <linux/ratelimit.h> | 39 | #include <linux/ratelimit.h> |
40 | #include <linux/compaction.h> | ||
40 | #include <linux/hugetlb.h> | 41 | #include <linux/hugetlb.h> |
41 | #include <linux/initrd.h> | 42 | #include <linux/initrd.h> |
42 | #include <linux/key.h> | 43 | #include <linux/key.h> |
@@ -1121,6 +1122,15 @@ static struct ctl_table vm_table[] = { | |||
1121 | .mode = 0644, | 1122 | .mode = 0644, |
1122 | .proc_handler = drop_caches_sysctl_handler, | 1123 | .proc_handler = drop_caches_sysctl_handler, |
1123 | }, | 1124 | }, |
1125 | #ifdef CONFIG_COMPACTION | ||
1126 | { | ||
1127 | .procname = "compact_memory", | ||
1128 | .data = &sysctl_compact_memory, | ||
1129 | .maxlen = sizeof(int), | ||
1130 | .mode = 0200, | ||
1131 | .proc_handler = sysctl_compaction_handler, | ||
1132 | }, | ||
1133 | #endif /* CONFIG_COMPACTION */ | ||
1124 | { | 1134 | { |
1125 | .procname = "min_free_kbytes", | 1135 | .procname = "min_free_kbytes", |
1126 | .data = &min_free_kbytes, | 1136 | .data = &min_free_kbytes, |
diff --git a/mm/compaction.c b/mm/compaction.c index be1ff3f7552b..77854fbc0f56 100644 --- a/mm/compaction.c +++ b/mm/compaction.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/compaction.h> | 12 | #include <linux/compaction.h> |
13 | #include <linux/mm_inline.h> | 13 | #include <linux/mm_inline.h> |
14 | #include <linux/backing-dev.h> | 14 | #include <linux/backing-dev.h> |
15 | #include <linux/sysctl.h> | ||
15 | #include "internal.h" | 16 | #include "internal.h" |
16 | 17 | ||
17 | /* | 18 | /* |
@@ -391,3 +392,64 @@ static int compact_zone(struct zone *zone, struct compact_control *cc) | |||
391 | 392 | ||
392 | return ret; | 393 | return ret; |
393 | } | 394 | } |
395 | |||
396 | /* Compact all zones within a node */ | ||
397 | static int compact_node(int nid) | ||
398 | { | ||
399 | int zoneid; | ||
400 | pg_data_t *pgdat; | ||
401 | struct zone *zone; | ||
402 | |||
403 | if (nid < 0 || nid >= nr_node_ids || !node_online(nid)) | ||
404 | return -EINVAL; | ||
405 | pgdat = NODE_DATA(nid); | ||
406 | |||
407 | /* Flush pending updates to the LRU lists */ | ||
408 | lru_add_drain_all(); | ||
409 | |||
410 | for (zoneid = 0; zoneid < MAX_NR_ZONES; zoneid++) { | ||
411 | struct compact_control cc = { | ||
412 | .nr_freepages = 0, | ||
413 | .nr_migratepages = 0, | ||
414 | }; | ||
415 | |||
416 | zone = &pgdat->node_zones[zoneid]; | ||
417 | if (!populated_zone(zone)) | ||
418 | continue; | ||
419 | |||
420 | cc.zone = zone; | ||
421 | INIT_LIST_HEAD(&cc.freepages); | ||
422 | INIT_LIST_HEAD(&cc.migratepages); | ||
423 | |||
424 | compact_zone(zone, &cc); | ||
425 | |||
426 | VM_BUG_ON(!list_empty(&cc.freepages)); | ||
427 | VM_BUG_ON(!list_empty(&cc.migratepages)); | ||
428 | } | ||
429 | |||
430 | return 0; | ||
431 | } | ||
432 | |||
433 | /* Compact all nodes in the system */ | ||
434 | static int compact_nodes(void) | ||
435 | { | ||
436 | int nid; | ||
437 | |||
438 | for_each_online_node(nid) | ||
439 | compact_node(nid); | ||
440 | |||
441 | return COMPACT_COMPLETE; | ||
442 | } | ||
443 | |||
444 | /* The written value is actually unused, all memory is compacted */ | ||
445 | int sysctl_compact_memory; | ||
446 | |||
447 | /* This is the entry point for compacting all nodes via /proc/sys/vm */ | ||
448 | int sysctl_compaction_handler(struct ctl_table *table, int write, | ||
449 | void __user *buffer, size_t *length, loff_t *ppos) | ||
450 | { | ||
451 | if (write) | ||
452 | return compact_nodes(); | ||
453 | |||
454 | return 0; | ||
455 | } | ||