diff options
Diffstat (limited to 'mm/compaction.c')
| -rw-r--r-- | mm/compaction.c | 77 | 
1 files changed, 53 insertions, 24 deletions
| diff --git a/mm/compaction.c b/mm/compaction.c index d9ebebe1a2aa..74a8c825ff28 100644 --- a/mm/compaction.c +++ b/mm/compaction.c @@ -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;  }; @@ -675,49 +675,71 @@ unsigned long try_to_compact_pages(struct zonelist *zonelist,  /* Compact all zones within a node */ -static int compact_node(int nid) +static int __compact_pgdat(pg_data_t *pgdat, struct compact_control *cc)  {  	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, -			.order = -1, -			.sync = true, -		};  		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); +		cc->nr_freepages = 0; +		cc->nr_migratepages = 0; +		cc->zone = zone; +		INIT_LIST_HEAD(&cc->freepages); +		INIT_LIST_HEAD(&cc->migratepages); + +		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)); +		VM_BUG_ON(!list_empty(&cc->freepages)); +		VM_BUG_ON(!list_empty(&cc->migratepages));  	}  	return 0;  } +int compact_pgdat(pg_data_t *pgdat, int order) +{ +	struct compact_control cc = { +		.order = order, +		.sync = false, +	}; + +	return __compact_pgdat(pgdat, &cc); +} + +static int compact_node(int nid) +{ +	struct compact_control cc = { +		.order = -1, +		.sync = true, +	}; + +	return __compact_pgdat(NODE_DATA(nid), &cc); +} +  /* Compact all nodes in the system */  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); @@ -750,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;  } | 
