aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/sysctl/vm.txt10
-rw-r--r--include/linux/compaction.h6
-rw-r--r--kernel/sysctl.c10
-rw-r--r--mm/compaction.c62
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.
19Currently, these files are in /proc/sys/vm: 19Currently, 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
68compact_memory
69
70Available only when CONFIG_COMPACTION is set. When 1 is written to the file,
71all zones are compacted such that free memory is available in contiguous
72blocks where possible. This can be important for example in the allocation of
73huge pages although processes will also directly compact memory as required.
74
75==============================================================
76
67dirty_background_bytes 77dirty_background_bytes
68 78
69Contains the amount of dirty memory at which the pdflush background writeback 79Contains 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
10extern int sysctl_compact_memory;
11extern 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 */
397static 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 */
434static 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 */
445int sysctl_compact_memory;
446
447/* This is the entry point for compacting all nodes via /proc/sys/vm */
448int 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}