|
@@ -12,6 +12,7 @@
|
|
|
#include <linux/compaction.h>
|
|
|
#include <linux/mm_inline.h>
|
|
|
#include <linux/backing-dev.h>
|
|
|
+#include <linux/sysctl.h>
|
|
|
#include "internal.h"
|
|
|
|
|
|
/*
|
|
@@ -391,3 +392,64 @@ static int compact_zone(struct zone *zone, struct compact_control *cc)
|
|
|
|
|
|
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;
|
|
|
+}
|