diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 642e8d221319..2f756ca4eb3c 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -2373,11 +2373,38 @@ static bool can_steal_fallback(unsigned int order, int start_mt) return false; } +static bool boost_eligible(struct zone *z) +{ + unsigned long high_wmark, threshold; + unsigned long reclaim_eligible, free_pages; + + high_wmark = z->_watermark[WMARK_HIGH]; + reclaim_eligible = zone_page_state_snapshot(z, NR_ZONE_INACTIVE_FILE) + + zone_page_state_snapshot(z, NR_ZONE_ACTIVE_FILE); + free_pages = zone_page_state(z, NR_FREE_PAGES) - + zone_page_state(z, NR_FREE_CMA_PAGES); + threshold = high_wmark + (2 * mult_frac(high_wmark, + watermark_boost_factor, 10000)); + + /* + * Don't boost watermark If we are already low on memory where the + * boosting can simply put the watermarks at higher levels for a + * longer duration of time and thus the other users relied on the + * watermarks are forced to choose unintended decissions. If memory + * is so low, kswapd in normal mode should help. + */ + + if (reclaim_eligible < threshold && free_pages < threshold) + return false; + + return true; +} + static inline void boost_watermark(struct zone *zone) { unsigned long max_boost; - if (!watermark_boost_factor) + if (!watermark_boost_factor || !boost_eligible(zone)) return; max_boost = mult_frac(zone->_watermark[WMARK_HIGH], @@ -3744,6 +3771,20 @@ retry: } mark = wmark_pages(zone, alloc_flags & ALLOC_WMARK_MASK); + /* + * Allow high, atomic, harder order-0 allocation requests + * to skip the ->watermark_boost for min watermark check. + * In doing so, check for: + * 1) ALLOC_WMARK_MIN - Allow to wake up kswapd in the + * slow path. + * 2) ALLOC_HIGH - Allow high priority requests. + * 3) ALLOC_HARDER - Allow (__GFP_ATOMIC && !__GFP_NOMEMALLOC), + * of the others. + */ + if (unlikely(!order && !(alloc_flags & ALLOC_WMARK_MASK) && + (alloc_flags & (ALLOC_HARDER | ALLOC_HIGH)))) { + mark = zone->_watermark[WMARK_MIN]; + } if (!zone_watermark_fast(zone, order, mark, ac_classzone_idx(ac), alloc_flags)) { int ret;