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 @@ -174,10 +174,17 @@ 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; + unsigned long num_pages = 0; bool can_backup = !!(sc->gfp_mask & __GFP_FS); - num_pages = ttm_backup_bytes_avail() >> PAGE_SHIFT; + /* + * 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. + */ + if (!sc->opportunistic_compaction) + num_pages = ttm_backup_bytes_avail() >> PAGE_SHIFT; read_lock(&shrinker->lock); if (can_backup) @@ -249,7 +256,14 @@ static unsigned long xe_shrinker_scan(struct shrinker *shrink, struct shrink_con nr_to_scan, &nr_scanned, &freed); sc->nr_scanned = nr_scanned; - if (nr_scanned >= nr_to_scan || !can_backup) + /* + * 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. + */ + if (nr_scanned >= nr_to_scan || !can_backup || + sc->opportunistic_compaction) goto out; /* If we didn't wake before, try to do it now if needed. */