mm: Increment kswapd_waiters for throttled direct reclaimers

Throttled direct reclaimers will wake up kswapd and wait for kswapd to
satisfy their page allocation request, even when the failed allocation
lacks the __GFP_KSWAPD_RECLAIM flag in its gfp mask. As a result, kswapd
may think that there are no waiters and thus exit prematurely, causing
throttled direct reclaimers lacking __GFP_KSWAPD_RECLAIM to stall on
waiting for kswapd to wake them up. Incrementing the kswapd_waiters
counter when such direct reclaimers become throttled fixes the problem.

Signed-off-by: Sultan Alsawaf <sultan@kerneltoast.com>
Signed-off-by: Forenche <prahul2003@gmail.com>
This commit is contained in:
Sultan Alsawaf 2021-07-16 23:35:47 -07:00 committed by Forenche
parent 4e5a138e49
commit a4c99fe0d0
No known key found for this signature in database
GPG Key ID: 1337D655BAFE85E2

View File

@ -3003,7 +3003,7 @@ retry:
return 0;
}
static bool allow_direct_reclaim(pg_data_t *pgdat)
static bool allow_direct_reclaim(pg_data_t *pgdat, bool using_kswapd)
{
struct zone *zone;
unsigned long pfmemalloc_reserve = 0;
@ -3032,6 +3032,10 @@ static bool allow_direct_reclaim(pg_data_t *pgdat)
wmark_ok = free_pages > pfmemalloc_reserve / 2;
/* The throttled direct reclaimer is now a kswapd waiter */
if (unlikely(!using_kswapd && !wmark_ok))
atomic_long_inc(&kswapd_waiters);
/* kswapd must be awake if processes are being throttled */
if (!wmark_ok && waitqueue_active(&pgdat->kswapd_wait)) {
if (READ_ONCE(pgdat->kswapd_classzone_idx) > ZONE_NORMAL)
@ -3097,7 +3101,7 @@ static bool throttle_direct_reclaim(gfp_t gfp_mask, struct zonelist *zonelist,
/* Throttle based on the first usable node */
pgdat = zone->zone_pgdat;
if (allow_direct_reclaim(pgdat))
if (allow_direct_reclaim(pgdat, gfp_mask & __GFP_KSWAPD_RECLAIM))
goto out;
break;
}
@ -3119,16 +3123,18 @@ static bool throttle_direct_reclaim(gfp_t gfp_mask, struct zonelist *zonelist,
*/
if (!(gfp_mask & __GFP_FS)) {
wait_event_interruptible_timeout(pgdat->pfmemalloc_wait,
allow_direct_reclaim(pgdat), HZ);
allow_direct_reclaim(pgdat, true), HZ);
goto check_pending;
}
/* Throttle until kswapd wakes the process */
wait_event_killable(zone->zone_pgdat->pfmemalloc_wait,
allow_direct_reclaim(pgdat));
allow_direct_reclaim(pgdat, true));
check_pending:
if (unlikely(!(gfp_mask & __GFP_KSWAPD_RECLAIM)))
atomic_long_dec(&kswapd_waiters);
if (fatal_signal_pending(current))
return true;
@ -3503,7 +3509,7 @@ static int balance_pgdat(pg_data_t *pgdat, int order, int classzone_idx)
* able to safely make forward progress. Wake them
*/
if (waitqueue_active(&pgdat->pfmemalloc_wait) &&
allow_direct_reclaim(pgdat))
allow_direct_reclaim(pgdat, true))
wake_up_all(&pgdat->pfmemalloc_wait);
/* Check if kswapd should be suspending */