--- sys/dev/drm/ttm/ttm_memory.c.orig +++ sys/dev/drm/ttm/ttm_memory.c @@ -38,10 +38,31 @@ #include #define TTM_MEMORY_ALLOC_RETRIES 4 +/* + * Recursion guard for ttm_shrink(). + * + * ttm_shrink() -> ttm_bo_swapout() may have to move a buffer object to + * system memory, which lazily populates its ttm pages through + * ttm_mem_global_alloc_page() -> ttm_mem_global_alloc_zone(), which + * calls ttm_shrink() again while the zone is still over its limit. + * Nothing bounds this recursion except the number of swappable buffer + * objects on ttm_bo_global::swap_lru, which any unprivileged /dev/dri + * client controls, so the kernel stack (16 KiB) can be exhausted. + * + * Allow a small fixed nesting depth so eviction still functions, but + * cap it far below what the stack can hold (4 levels x ~2 KiB). + * + * (Upstream ultimately removed the accounting shrinker entirely in + * commit b12dacf5fa64 "drm/ttm: nuke memory accounting shrinker".) + */ +#define TTM_SHRINK_MAX_NESTING 4 +static atomic_t ttm_shrink_nesting; + struct ttm_mem_zone { struct kobject kobj; struct ttm_mem_global *glob; @@ -211,10 +232,20 @@ static struct kobj_type ttm_mem_glob_kobj_type = { static void ttm_shrink(struct ttm_mem_global *glob, bool from_wq, uint64_t extra, struct ttm_operation_ctx *ctx) { int ret; + if (atomic_inc_return(&ttm_shrink_nesting) > TTM_SHRINK_MAX_NESTING) { + atomic_dec(&ttm_shrink_nesting); + return; + } + lockmgr(&glob->lock, LK_EXCLUSIVE); while (ttm_zones_above_swap_target(glob, from_wq, extra)) { lockmgr(&glob->lock, LK_RELEASE); ret = ttm_bo_swapout(glob->bo_glob, ctx); lockmgr(&glob->lock, LK_EXCLUSIVE); if (unlikely(ret != 0)) break; } lockmgr(&glob->lock, LK_RELEASE); + atomic_dec(&ttm_shrink_nesting); }