|
@@ -3539,16 +3539,21 @@ kswapd_try_sleep:
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * A zone is low on free memory, so wake its kswapd task to service it.
|
|
|
+ * A zone is low on free memory or too fragmented for high-order memory. If
|
|
|
+ * kswapd should reclaim (direct reclaim is deferred), wake it up for the zone's
|
|
|
+ * pgdat. It will wake up kcompactd after reclaiming memory. If kswapd reclaim
|
|
|
+ * has failed or is not needed, still wake up kcompactd if only compaction is
|
|
|
+ * needed.
|
|
|
*/
|
|
|
-void wakeup_kswapd(struct zone *zone, int order, enum zone_type classzone_idx)
|
|
|
+void wakeup_kswapd(struct zone *zone, gfp_t gfp_flags, int order,
|
|
|
+ enum zone_type classzone_idx)
|
|
|
{
|
|
|
pg_data_t *pgdat;
|
|
|
|
|
|
if (!managed_zone(zone))
|
|
|
return;
|
|
|
|
|
|
- if (!cpuset_zone_allowed(zone, GFP_KERNEL | __GFP_HARDWALL))
|
|
|
+ if (!cpuset_zone_allowed(zone, gfp_flags))
|
|
|
return;
|
|
|
pgdat = zone->zone_pgdat;
|
|
|
pgdat->kswapd_classzone_idx = kswapd_classzone_idx(pgdat,
|
|
@@ -3557,14 +3562,23 @@ void wakeup_kswapd(struct zone *zone, int order, enum zone_type classzone_idx)
|
|
|
if (!waitqueue_active(&pgdat->kswapd_wait))
|
|
|
return;
|
|
|
|
|
|
- /* Hopeless node, leave it to direct reclaim */
|
|
|
- if (pgdat->kswapd_failures >= MAX_RECLAIM_RETRIES)
|
|
|
- return;
|
|
|
-
|
|
|
- if (pgdat_balanced(pgdat, order, classzone_idx))
|
|
|
+ /* Hopeless node, leave it to direct reclaim if possible */
|
|
|
+ if (pgdat->kswapd_failures >= MAX_RECLAIM_RETRIES ||
|
|
|
+ pgdat_balanced(pgdat, order, classzone_idx)) {
|
|
|
+ /*
|
|
|
+ * There may be plenty of free memory available, but it's too
|
|
|
+ * fragmented for high-order allocations. Wake up kcompactd
|
|
|
+ * and rely on compaction_suitable() to determine if it's
|
|
|
+ * needed. If it fails, it will defer subsequent attempts to
|
|
|
+ * ratelimit its work.
|
|
|
+ */
|
|
|
+ if (!(gfp_flags & __GFP_DIRECT_RECLAIM))
|
|
|
+ wakeup_kcompactd(pgdat, order, classzone_idx);
|
|
|
return;
|
|
|
+ }
|
|
|
|
|
|
- trace_mm_vmscan_wakeup_kswapd(pgdat->node_id, classzone_idx, order);
|
|
|
+ trace_mm_vmscan_wakeup_kswapd(pgdat->node_id, classzone_idx, order,
|
|
|
+ gfp_flags);
|
|
|
wake_up_interruptible(&pgdat->kswapd_wait);
|
|
|
}
|
|
|
|