Update to 3.4-final.
[linux-flexiantxendom0-3.2.10.git] / mm / compaction.c
index 36f0f61..74a8c82 100644 (file)
@@ -35,7 +35,7 @@ struct compact_control {
        unsigned long migrate_pfn;      /* isolate_migratepages search base */
        bool sync;                      /* Synchronous migration */
 
-       unsigned int order;             /* order a direct compactor needs */
+       int order;                      /* order a direct compactor needs */
        int migratetype;                /* MOVABLE, RECLAIMABLE etc */
        struct zone *zone;
 };
@@ -680,9 +680,6 @@ static int __compact_pgdat(pg_data_t *pgdat, struct compact_control *cc)
        int zoneid;
        struct zone *zone;
 
-       /* Flush pending updates to the LRU lists */
-       lru_add_drain_all();
-
        for (zoneid = 0; zoneid < MAX_NR_ZONES; zoneid++) {
 
                zone = &pgdat->node_zones[zoneid];
@@ -695,9 +692,19 @@ static int __compact_pgdat(pg_data_t *pgdat, struct compact_control *cc)
                INIT_LIST_HEAD(&cc->freepages);
                INIT_LIST_HEAD(&cc->migratepages);
 
-               if (cc->order < 0 || !compaction_deferred(zone))
+               if (cc->order == -1 || !compaction_deferred(zone, cc->order))
                        compact_zone(zone, cc);
 
+               if (cc->order > 0) {
+                       int ok = zone_watermark_ok(zone, cc->order,
+                                               low_wmark_pages(zone), 0, 0);
+                       if (ok && cc->order > zone->compact_order_failed)
+                               zone->compact_order_failed = cc->order + 1;
+                       /* Currently async compaction is never deferred. */
+                       else if (!ok && cc->sync)
+                               defer_compaction(zone, cc->order);
+               }
+
                VM_BUG_ON(!list_empty(&cc->freepages));
                VM_BUG_ON(!list_empty(&cc->migratepages));
        }
@@ -717,17 +724,12 @@ int compact_pgdat(pg_data_t *pgdat, int order)
 
 static int compact_node(int nid)
 {
-       pg_data_t *pgdat;
        struct compact_control cc = {
                .order = -1,
                .sync = true,
        };
 
-       if (nid < 0 || nid >= nr_node_ids || !node_online(nid))
-               return -EINVAL;
-       pgdat = NODE_DATA(nid);
-
-       return __compact_pgdat(pgdat, &cc);
+       return __compact_pgdat(NODE_DATA(nid), &cc);
 }
 
 /* Compact all nodes in the system */
@@ -735,6 +737,9 @@ static int compact_nodes(void)
 {
        int nid;
 
+       /* Flush pending updates to the LRU lists */
+       lru_add_drain_all();
+
        for_each_online_node(nid)
                compact_node(nid);
 
@@ -767,7 +772,14 @@ ssize_t sysfs_compact_node(struct device *dev,
                        struct device_attribute *attr,
                        const char *buf, size_t count)
 {
-       compact_node(dev->id);
+       int nid = dev->id;
+
+       if (nid >= 0 && nid < nr_node_ids && node_online(nid)) {
+               /* Flush pending updates to the LRU lists */
+               lru_add_drain_all();
+
+               compact_node(nid);
+       }
 
        return count;
 }