diff --git c/drivers/gpu/drm/xe/xe_shrinker.c i/drivers/gpu/drm/xe/xe_shrinker.c --- c/drivers/gpu/drm/xe/xe_shrinker.c +++ i/drivers/gpu/drm/xe/xe_shrinker.c @@ -170,27 +170,28 @@ static int xe_shrinker_walk(struct xe_shrinker *shrinker, return ret; } +static inline bool xe_shrinker_can_backup(const struct shrink_control *sc) +{ + return (sc->gfp_mask & __GFP_FS) && !sc->opportunistic_compaction; +} + static unsigned long xe_shrinker_count(struct shrinker *shrink, struct shrink_control *sc) { struct xe_shrinker *shrinker = to_xe_shrinker(shrink); unsigned long num_pages = 0; - bool can_backup = !!(sc->gfp_mask & __GFP_FS); /* - * Skip accounting backup-able pages when this is an opportunistic - * high-order pass: TTM backup work shrinks at native page granularity - * and is unlikely to produce the contiguous block the caller wants, - * so don't advertise it as reclaimable for this hint. + * Only advertise backup-able pages when the backup pass can run. TTM + * backup work shrinks at native page granularity and is unlikely to + * produce the contiguous block an opportunistic high-order caller + * wants, and it needs __GFP_FS. */ - if (!sc->opportunistic_compaction) - num_pages = ttm_backup_bytes_avail() >> PAGE_SHIFT; read_lock(&shrinker->lock); - - if (can_backup) - num_pages = min_t(unsigned long, num_pages, shrinker->shrinkable_pages); - else - num_pages = 0; + if (xe_shrinker_can_backup(sc)) + num_pages = min_t(unsigned long, + ttm_backup_bytes_avail() >> PAGE_SHIFT, + shrinker->shrinkable_pages); num_pages += shrinker->purgeable_pages; read_unlock(&shrinker->lock); @@ -240,7 +241,7 @@ static unsigned long xe_shrinker_scan(struct shrinker *shrink, struct shrink_con }; bool runtime_pm; bool purgeable; - bool can_backup = !!(sc->gfp_mask & __GFP_FS); + bool can_backup = xe_shrinker_can_backup(sc); nr_to_scan = sc->nr_to_scan; @@ -257,13 +258,15 @@ static unsigned long xe_shrinker_scan(struct shrinker *shrink, struct shrink_con sc->nr_scanned = nr_scanned; /* - * Stop after the purge pass for opportunistic high-order reclaim: - * the subsequent backup/writeback pass works at native page order - * and is unlikely to free a contiguous high-order block, so doing - * it here would just churn working sets for no compaction benefit. + * Stop after the purge pass when the backup pass may not run. The + * backup/writeback pass works at native page order and is unlikely to + * free a contiguous high-order block for an opportunistic caller, so + * doing it there would churn working sets for no compaction benefit. + * + * The per-walk runtime PM reference in __xe_shrinker_walk() is not + * affected. Only the outer backup-driven reference is. */ - if (nr_scanned >= nr_to_scan || !can_backup || - sc->opportunistic_compaction) + if (nr_scanned >= nr_to_scan || !can_backup) goto out; /* If we didn't wake before, try to do it now if needed. */