Skip to content

Commit d4bd777

Browse files
drm/ttm: rework ttm_tt page limit v4
TTM implements a rather extensive accounting of allocated memory. There are two reasons for this: 1. It tries to block userspace allocating a huge number of very small BOs without accounting for the kmalloced memory. 2. Make sure we don't over allocate and run into an OOM situation during swapout while trying to handle the memory shortage. This is only partially a good idea. First of all it is perfectly valid for an application to use all of system memory, limiting it to 50% is not really acceptable. What we need to take care of is that the application is held accountable for the memory it allocated. This is what control mechanisms like memcg and the normal Linux page accounting already do. Making sure that we don't run into an OOM situation while trying to cope with a memory shortage is still a good idea, but this is also not very well implemented since it means another opportunity of recursion from the driver back into TTM. So start to rework all of this by implementing a shrinker callback which allows for TT object to be swapped out if necessary. v2: Switch from limit to shrinker callback. v3: fix gfp mask handling, use atomic for swapable_pages, add debugfs v4: drop the extra gfp_mask checks Signed-off-by: Christian König <[email protected]> Reviewed-by: Daniel Vetter <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent 8a945ed commit d4bd777

File tree

6 files changed

+111
-15
lines changed

6 files changed

+111
-15
lines changed

drivers/gpu/drm/ttm/ttm_bo.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1219,7 +1219,7 @@ EXPORT_SYMBOL(ttm_bo_wait);
12191219
* A buffer object shrink method that tries to swap out the first
12201220
* buffer object on the bo_global::swap_lru list.
12211221
*/
1222-
int ttm_bo_swapout(struct ttm_operation_ctx *ctx)
1222+
int ttm_bo_swapout(struct ttm_operation_ctx *ctx, gfp_t gfp_flags)
12231223
{
12241224
struct ttm_global *glob = &ttm_glob;
12251225
struct ttm_buffer_object *bo;
@@ -1302,7 +1302,7 @@ int ttm_bo_swapout(struct ttm_operation_ctx *ctx)
13021302
if (bo->bdev->funcs->swap_notify)
13031303
bo->bdev->funcs->swap_notify(bo);
13041304

1305-
ret = ttm_tt_swapout(bo->bdev, bo->ttm);
1305+
ret = ttm_tt_swapout(bo->bdev, bo->ttm, gfp_flags);
13061306
out:
13071307

13081308
/**

drivers/gpu/drm/ttm/ttm_memory.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include <linux/slab.h>
3838
#include <linux/swap.h>
3939
#include <drm/ttm/ttm_pool.h>
40+
#include <drm/ttm/ttm_tt.h>
4041

4142
#include "ttm_module.h"
4243

@@ -276,9 +277,9 @@ static void ttm_shrink(struct ttm_mem_global *glob, bool from_wq,
276277

277278
while (ttm_zones_above_swap_target(glob, from_wq, extra)) {
278279
spin_unlock(&glob->lock);
279-
ret = ttm_bo_swapout(ctx);
280+
ret = ttm_bo_swapout(ctx, GFP_KERNEL);
280281
spin_lock(&glob->lock);
281-
if (unlikely(ret != 0))
282+
if (unlikely(ret < 0))
282283
break;
283284
}
284285

@@ -453,6 +454,7 @@ int ttm_mem_global_init(struct ttm_mem_global *glob)
453454
zone->name, (unsigned long long)zone->max_mem >> 10);
454455
}
455456
ttm_pool_mgr_init(glob->zone_kernel->max_mem/(2*PAGE_SIZE));
457+
ttm_tt_mgr_init();
456458
return 0;
457459
out_no_zone:
458460
ttm_mem_global_release(glob);
@@ -466,6 +468,7 @@ void ttm_mem_global_release(struct ttm_mem_global *glob)
466468

467469
/* let the page allocator first stop the shrink work. */
468470
ttm_pool_mgr_fini();
471+
ttm_tt_mgr_fini();
469472

470473
flush_workqueue(glob->swap_queue);
471474
destroy_workqueue(glob->swap_queue);

drivers/gpu/drm/ttm/ttm_tt.c

Lines changed: 97 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@
3838
#include <drm/drm_cache.h>
3939
#include <drm/ttm/ttm_bo_driver.h>
4040

41+
#include "ttm_module.h"
42+
43+
static struct shrinker mm_shrinker;
44+
static atomic_long_t swapable_pages;
45+
4146
/*
4247
* Allocates a ttm structure for the given BO.
4348
*/
@@ -223,32 +228,41 @@ int ttm_tt_swapin(struct ttm_tt *ttm)
223228
return ret;
224229
}
225230

226-
int ttm_tt_swapout(struct ttm_device *bdev, struct ttm_tt *ttm)
231+
/**
232+
* ttm_tt_swapout - swap out tt object
233+
*
234+
* @bdev: TTM device structure.
235+
* @ttm: The struct ttm_tt.
236+
* @gfp_flags: Flags to use for memory allocation.
237+
*
238+
* Swapout a TT object to a shmem_file, return number of pages swapped out or
239+
* negative error code.
240+
*/
241+
int ttm_tt_swapout(struct ttm_device *bdev, struct ttm_tt *ttm,
242+
gfp_t gfp_flags)
227243
{
244+
loff_t size = (loff_t)ttm->num_pages << PAGE_SHIFT;
228245
struct address_space *swap_space;
229246
struct file *swap_storage;
230247
struct page *from_page;
231248
struct page *to_page;
232-
gfp_t gfp_mask;
233249
int i, ret;
234250

235-
swap_storage = shmem_file_setup("ttm swap",
236-
ttm->num_pages << PAGE_SHIFT,
237-
0);
251+
swap_storage = shmem_file_setup("ttm swap", size, 0);
238252
if (IS_ERR(swap_storage)) {
239253
pr_err("Failed allocating swap storage\n");
240254
return PTR_ERR(swap_storage);
241255
}
242256

243257
swap_space = swap_storage->f_mapping;
244-
gfp_mask = mapping_gfp_mask(swap_space);
258+
gfp_flags &= mapping_gfp_mask(swap_space);
245259

246260
for (i = 0; i < ttm->num_pages; ++i) {
247261
from_page = ttm->pages[i];
248262
if (unlikely(from_page == NULL))
249263
continue;
250264

251-
to_page = shmem_read_mapping_page_gfp(swap_space, i, gfp_mask);
265+
to_page = shmem_read_mapping_page_gfp(swap_space, i, gfp_flags);
252266
if (IS_ERR(to_page)) {
253267
ret = PTR_ERR(to_page);
254268
goto out_err;
@@ -263,7 +277,7 @@ int ttm_tt_swapout(struct ttm_device *bdev, struct ttm_tt *ttm)
263277
ttm->swap_storage = swap_storage;
264278
ttm->page_flags |= TTM_PAGE_FLAG_SWAPPED;
265279

266-
return 0;
280+
return ttm->num_pages;
267281

268282
out_err:
269283
fput(swap_storage);
@@ -280,6 +294,8 @@ static void ttm_tt_add_mapping(struct ttm_device *bdev, struct ttm_tt *ttm)
280294

281295
for (i = 0; i < ttm->num_pages; ++i)
282296
ttm->pages[i]->mapping = bdev->dev_mapping;
297+
298+
atomic_long_add(ttm->num_pages, &swapable_pages);
283299
}
284300

285301
int ttm_tt_populate(struct ttm_device *bdev,
@@ -326,6 +342,8 @@ static void ttm_tt_clear_mapping(struct ttm_tt *ttm)
326342
(*page)->mapping = NULL;
327343
(*page++)->index = 0;
328344
}
345+
346+
atomic_long_sub(ttm->num_pages, &swapable_pages);
329347
}
330348

331349
void ttm_tt_unpopulate(struct ttm_device *bdev,
@@ -341,3 +359,74 @@ void ttm_tt_unpopulate(struct ttm_device *bdev,
341359
ttm_pool_free(&bdev->pool, ttm);
342360
ttm->page_flags &= ~TTM_PAGE_FLAG_PRIV_POPULATED;
343361
}
362+
363+
/* As long as pages are available make sure to release at least one */
364+
static unsigned long ttm_tt_shrinker_scan(struct shrinker *shrink,
365+
struct shrink_control *sc)
366+
{
367+
struct ttm_operation_ctx ctx = {
368+
.no_wait_gpu = false
369+
};
370+
int ret;
371+
372+
ret = ttm_bo_swapout(&ctx, GFP_NOFS);
373+
return ret < 0 ? SHRINK_EMPTY : ret;
374+
}
375+
376+
/* Return the number of pages available or SHRINK_EMPTY if we have none */
377+
static unsigned long ttm_tt_shrinker_count(struct shrinker *shrink,
378+
struct shrink_control *sc)
379+
{
380+
unsigned long num_pages;
381+
382+
num_pages = atomic_long_read(&swapable_pages);
383+
return num_pages ? num_pages : SHRINK_EMPTY;
384+
}
385+
386+
#ifdef CONFIG_DEBUG_FS
387+
388+
/* Test the shrinker functions and dump the result */
389+
static int ttm_tt_debugfs_shrink_show(struct seq_file *m, void *data)
390+
{
391+
struct shrink_control sc = { .gfp_mask = GFP_KERNEL };
392+
393+
fs_reclaim_acquire(GFP_KERNEL);
394+
seq_printf(m, "%lu/%lu\n", ttm_tt_shrinker_count(&mm_shrinker, &sc),
395+
ttm_tt_shrinker_scan(&mm_shrinker, &sc));
396+
fs_reclaim_release(GFP_KERNEL);
397+
398+
return 0;
399+
}
400+
DEFINE_SHOW_ATTRIBUTE(ttm_tt_debugfs_shrink);
401+
402+
#endif
403+
404+
405+
406+
/**
407+
* ttm_tt_mgr_init - register with the MM shrinker
408+
*
409+
* Register with the MM shrinker for swapping out BOs.
410+
*/
411+
int ttm_tt_mgr_init(void)
412+
{
413+
#ifdef CONFIG_DEBUG_FS
414+
debugfs_create_file("tt_shrink", 0400, ttm_debugfs_root, NULL,
415+
&ttm_tt_debugfs_shrink_fops);
416+
#endif
417+
418+
mm_shrinker.count_objects = ttm_tt_shrinker_count;
419+
mm_shrinker.scan_objects = ttm_tt_shrinker_scan;
420+
mm_shrinker.seeks = 1;
421+
return register_shrinker(&mm_shrinker);
422+
}
423+
424+
/**
425+
* ttm_tt_mgr_fini - unregister our MM shrinker
426+
*
427+
* Unregisters the MM shrinker.
428+
*/
429+
void ttm_tt_mgr_fini(void)
430+
{
431+
unregister_shrinker(&mm_shrinker);
432+
}

drivers/gpu/drm/vmwgfx/vmwgfx_drv.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1383,7 +1383,7 @@ static int vmw_pm_freeze(struct device *kdev)
13831383
vmw_execbuf_release_pinned_bo(dev_priv);
13841384
vmw_resource_evict_all(dev_priv);
13851385
vmw_release_device_early(dev_priv);
1386-
while (ttm_bo_swapout(&ctx) == 0);
1386+
while (ttm_bo_swapout(&ctx, GFP_KERNEL) > 0);
13871387
if (dev_priv->enable_fb)
13881388
vmw_fifo_resource_dec(dev_priv);
13891389
if (atomic_read(&dev_priv->num_fifo_resources) != 0) {

include/drm/ttm/ttm_bo_api.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -569,7 +569,7 @@ ssize_t ttm_bo_io(struct ttm_device *bdev, struct file *filp,
569569
const char __user *wbuf, char __user *rbuf,
570570
size_t count, loff_t *f_pos, bool write);
571571

572-
int ttm_bo_swapout(struct ttm_operation_ctx *ctx);
572+
int ttm_bo_swapout(struct ttm_operation_ctx *ctx, gfp_t gfp_flags);
573573

574574
/**
575575
* ttm_bo_uses_embedded_gem_object - check if the given bo uses the

include/drm/ttm/ttm_tt.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,8 @@ void ttm_tt_destroy_common(struct ttm_device *bdev, struct ttm_tt *ttm);
135135
* Swap in a previously swap out ttm_tt.
136136
*/
137137
int ttm_tt_swapin(struct ttm_tt *ttm);
138-
int ttm_tt_swapout(struct ttm_device *bdev, struct ttm_tt *ttm);
138+
int ttm_tt_swapout(struct ttm_device *bdev, struct ttm_tt *ttm,
139+
gfp_t gfp_flags);
139140

140141
/**
141142
* ttm_tt_populate - allocate pages for a ttm
@@ -155,6 +156,9 @@ int ttm_tt_populate(struct ttm_device *bdev, struct ttm_tt *ttm, struct ttm_oper
155156
*/
156157
void ttm_tt_unpopulate(struct ttm_device *bdev, struct ttm_tt *ttm);
157158

159+
int ttm_tt_mgr_init(void);
160+
void ttm_tt_mgr_fini(void);
161+
158162
#if IS_ENABLED(CONFIG_AGP)
159163
#include <linux/agp_backend.h>
160164

0 commit comments

Comments
 (0)