Message ID | 1517214673-30962-1-git-send-email-Hongbo.He@amd.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On 2018年01月29日 16:31, Roger He wrote: > separate swapped memory account from zone->used_mem because swapped > ttm pages can be flushed into SWAP disk/file under high memory pressure. > > add check conditon in ttm_mem_global_reserve to prevent triggering OOM. > because if SWAP disk/file is full, all swapped ttm page would stay in > system memory which can't be flushed into disk/file. At this time, any > memory request will trigger OOM killer. > > v2: always get total system swap size rather than getting it once > at module init time > > Signed-off-by: Roger He <Hongbo.He@amd.com> > --- > drivers/gpu/drm/ttm/ttm_memory.c | 24 ++++++++++++++++-------- > drivers/gpu/drm/ttm/ttm_tt.c | 13 +++++++++++-- > include/drm/ttm/ttm_memory.h | 2 ++ > 3 files changed, 29 insertions(+), 10 deletions(-) > > diff --git a/drivers/gpu/drm/ttm/ttm_memory.c b/drivers/gpu/drm/ttm/ttm_memory.c > index aa0c381..06024ba 100644 > --- a/drivers/gpu/drm/ttm/ttm_memory.c > +++ b/drivers/gpu/drm/ttm/ttm_memory.c > @@ -36,6 +36,7 @@ > #include <linux/mm.h> > #include <linux/module.h> > #include <linux/slab.h> > +#include <linux/swap.h> > > #define TTM_MEMORY_ALLOC_RETRIES 4 > > @@ -183,20 +184,20 @@ static bool ttm_zones_above_swap_target(struct ttm_mem_global *glob, > { > unsigned int i; > struct ttm_mem_zone *zone; > - uint64_t target; > + uint64_t target, limit; Don't need limit variable. > > for (i = 0; i < glob->num_zones; ++i) { > zone = glob->zones[i]; > > + limit = (capable(CAP_SYS_ADMIN)) ? > + zone->emer_mem : zone->max_mem; directly target = ... > + > if (from_wq) > target = zone->swap_limit; > - else if (capable(CAP_SYS_ADMIN)) > - target = zone->emer_mem; > else > - target = zone->max_mem; > + target = limit; Don't need `else` case. > > target = (extra > target) ? 0ULL : target; > - > if (zone->used_mem > target) > return true; > } > @@ -373,6 +374,7 @@ int ttm_mem_global_init(struct ttm_mem_global *glob) > return ret; > } > > + atomic64_set(&glob->swap_glob_mem, 0); > si_meminfo(&si); > > ret = ttm_mem_init_kernel_zone(glob, &si); > @@ -473,10 +475,14 @@ static int ttm_mem_global_reserve(struct ttm_mem_global *glob, > struct ttm_mem_zone *single_zone, > uint64_t amount, bool reserve) > { > - uint64_t limit; > + uint64_t swap_glob_mem, max_swap_cache; > + uint64_t limit, total_used_mem; > + struct ttm_mem_zone *zone; > int ret = -ENOMEM; > unsigned int i; > - struct ttm_mem_zone *zone; > + > + swap_glob_mem = atomic64_read(&glob->swap_glob_mem); > + max_swap_cache = (get_total_swap_pages() >> 1) << PAGE_SHIFT; > > spin_lock(&glob->lock); > for (i = 0; i < glob->num_zones; ++i) { > @@ -487,7 +493,9 @@ static int ttm_mem_global_reserve(struct ttm_mem_global *glob, > limit = (capable(CAP_SYS_ADMIN)) ? > zone->emer_mem : zone->max_mem; > > - if (zone->used_mem > limit) > + total_used_mem = zone->used_mem + swap_glob_mem; Good catch for total used mem. Regards, David Zhou > + limit += max_swap_cache; > + if (total_used_mem > limit) > goto out_unlock; > } > > diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c > index 9e4d43d..395cac0 100644 > --- a/drivers/gpu/drm/ttm/ttm_tt.c > +++ b/drivers/gpu/drm/ttm/ttm_tt.c > @@ -177,8 +177,11 @@ void ttm_tt_destroy(struct ttm_tt *ttm) > ttm_tt_unpopulate(ttm); > > if (!(ttm->page_flags & TTM_PAGE_FLAG_PERSISTENT_SWAP) && > - ttm->swap_storage) > + ttm->swap_storage) { > fput(ttm->swap_storage); > + atomic64_sub_return(ttm->num_pages << PAGE_SHIFT, > + &ttm->glob->mem_glob->swap_glob_mem); > + } > > ttm->swap_storage = NULL; > ttm->func->destroy(ttm); > @@ -318,8 +321,11 @@ int ttm_tt_swapin(struct ttm_tt *ttm) > put_page(from_page); > } > > - if (!(ttm->page_flags & TTM_PAGE_FLAG_PERSISTENT_SWAP)) > + if (!(ttm->page_flags & TTM_PAGE_FLAG_PERSISTENT_SWAP)) { > fput(swap_storage); > + atomic64_sub_return(ttm->num_pages << PAGE_SHIFT, > + &ttm->glob->mem_glob->swap_glob_mem); > + } > ttm->swap_storage = NULL; > ttm->page_flags &= ~TTM_PAGE_FLAG_SWAPPED; > > @@ -378,6 +384,9 @@ int ttm_tt_swapout(struct ttm_tt *ttm, struct file *persistent_swap_storage) > ttm->page_flags |= TTM_PAGE_FLAG_SWAPPED; > if (persistent_swap_storage) > ttm->page_flags |= TTM_PAGE_FLAG_PERSISTENT_SWAP; > + else > + atomic64_add_return(ttm->num_pages << PAGE_SHIFT, > + &ttm->glob->mem_glob->swap_glob_mem); > > return 0; > out_err: > diff --git a/include/drm/ttm/ttm_memory.h b/include/drm/ttm/ttm_memory.h > index 8936285..a273581 100644 > --- a/include/drm/ttm/ttm_memory.h > +++ b/include/drm/ttm/ttm_memory.h > @@ -49,6 +49,7 @@ > * @work: The workqueue callback for the shrink queue. > * @lock: Lock to protect the @shrink - and the memory accounting members, > * that is, essentially the whole structure with some exceptions. > + * @swap_glob_mem: total size of ttm page which has been swapped out > * @zones: Array of pointers to accounting zones. > * @num_zones: Number of populated entries in the @zones array. > * @zone_kernel: Pointer to the kernel zone. > @@ -67,6 +68,7 @@ struct ttm_mem_global { > struct workqueue_struct *swap_queue; > struct work_struct work; > spinlock_t lock; > + atomic64_t swap_glob_mem; > struct ttm_mem_zone *zones[TTM_MEM_MAX_ZONES]; > unsigned int num_zones; > struct ttm_mem_zone *zone_kernel;
diff --git a/drivers/gpu/drm/ttm/ttm_memory.c b/drivers/gpu/drm/ttm/ttm_memory.c index aa0c381..06024ba 100644 --- a/drivers/gpu/drm/ttm/ttm_memory.c +++ b/drivers/gpu/drm/ttm/ttm_memory.c @@ -36,6 +36,7 @@ #include <linux/mm.h> #include <linux/module.h> #include <linux/slab.h> +#include <linux/swap.h> #define TTM_MEMORY_ALLOC_RETRIES 4 @@ -183,20 +184,20 @@ static bool ttm_zones_above_swap_target(struct ttm_mem_global *glob, { unsigned int i; struct ttm_mem_zone *zone; - uint64_t target; + uint64_t target, limit; for (i = 0; i < glob->num_zones; ++i) { zone = glob->zones[i]; + limit = (capable(CAP_SYS_ADMIN)) ? + zone->emer_mem : zone->max_mem; + if (from_wq) target = zone->swap_limit; - else if (capable(CAP_SYS_ADMIN)) - target = zone->emer_mem; else - target = zone->max_mem; + target = limit; target = (extra > target) ? 0ULL : target; - if (zone->used_mem > target) return true; } @@ -373,6 +374,7 @@ int ttm_mem_global_init(struct ttm_mem_global *glob) return ret; } + atomic64_set(&glob->swap_glob_mem, 0); si_meminfo(&si); ret = ttm_mem_init_kernel_zone(glob, &si); @@ -473,10 +475,14 @@ static int ttm_mem_global_reserve(struct ttm_mem_global *glob, struct ttm_mem_zone *single_zone, uint64_t amount, bool reserve) { - uint64_t limit; + uint64_t swap_glob_mem, max_swap_cache; + uint64_t limit, total_used_mem; + struct ttm_mem_zone *zone; int ret = -ENOMEM; unsigned int i; - struct ttm_mem_zone *zone; + + swap_glob_mem = atomic64_read(&glob->swap_glob_mem); + max_swap_cache = (get_total_swap_pages() >> 1) << PAGE_SHIFT; spin_lock(&glob->lock); for (i = 0; i < glob->num_zones; ++i) { @@ -487,7 +493,9 @@ static int ttm_mem_global_reserve(struct ttm_mem_global *glob, limit = (capable(CAP_SYS_ADMIN)) ? zone->emer_mem : zone->max_mem; - if (zone->used_mem > limit) + total_used_mem = zone->used_mem + swap_glob_mem; + limit += max_swap_cache; + if (total_used_mem > limit) goto out_unlock; } diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c index 9e4d43d..395cac0 100644 --- a/drivers/gpu/drm/ttm/ttm_tt.c +++ b/drivers/gpu/drm/ttm/ttm_tt.c @@ -177,8 +177,11 @@ void ttm_tt_destroy(struct ttm_tt *ttm) ttm_tt_unpopulate(ttm); if (!(ttm->page_flags & TTM_PAGE_FLAG_PERSISTENT_SWAP) && - ttm->swap_storage) + ttm->swap_storage) { fput(ttm->swap_storage); + atomic64_sub_return(ttm->num_pages << PAGE_SHIFT, + &ttm->glob->mem_glob->swap_glob_mem); + } ttm->swap_storage = NULL; ttm->func->destroy(ttm); @@ -318,8 +321,11 @@ int ttm_tt_swapin(struct ttm_tt *ttm) put_page(from_page); } - if (!(ttm->page_flags & TTM_PAGE_FLAG_PERSISTENT_SWAP)) + if (!(ttm->page_flags & TTM_PAGE_FLAG_PERSISTENT_SWAP)) { fput(swap_storage); + atomic64_sub_return(ttm->num_pages << PAGE_SHIFT, + &ttm->glob->mem_glob->swap_glob_mem); + } ttm->swap_storage = NULL; ttm->page_flags &= ~TTM_PAGE_FLAG_SWAPPED; @@ -378,6 +384,9 @@ int ttm_tt_swapout(struct ttm_tt *ttm, struct file *persistent_swap_storage) ttm->page_flags |= TTM_PAGE_FLAG_SWAPPED; if (persistent_swap_storage) ttm->page_flags |= TTM_PAGE_FLAG_PERSISTENT_SWAP; + else + atomic64_add_return(ttm->num_pages << PAGE_SHIFT, + &ttm->glob->mem_glob->swap_glob_mem); return 0; out_err: diff --git a/include/drm/ttm/ttm_memory.h b/include/drm/ttm/ttm_memory.h index 8936285..a273581 100644 --- a/include/drm/ttm/ttm_memory.h +++ b/include/drm/ttm/ttm_memory.h @@ -49,6 +49,7 @@ * @work: The workqueue callback for the shrink queue. * @lock: Lock to protect the @shrink - and the memory accounting members, * that is, essentially the whole structure with some exceptions. + * @swap_glob_mem: total size of ttm page which has been swapped out * @zones: Array of pointers to accounting zones. * @num_zones: Number of populated entries in the @zones array. * @zone_kernel: Pointer to the kernel zone. @@ -67,6 +68,7 @@ struct ttm_mem_global { struct workqueue_struct *swap_queue; struct work_struct work; spinlock_t lock; + atomic64_t swap_glob_mem; struct ttm_mem_zone *zones[TTM_MEM_MAX_ZONES]; unsigned int num_zones; struct ttm_mem_zone *zone_kernel;
separate swapped memory account from zone->used_mem because swapped ttm pages can be flushed into SWAP disk/file under high memory pressure. add check conditon in ttm_mem_global_reserve to prevent triggering OOM. because if SWAP disk/file is full, all swapped ttm page would stay in system memory which can't be flushed into disk/file. At this time, any memory request will trigger OOM killer. v2: always get total system swap size rather than getting it once at module init time Signed-off-by: Roger He <Hongbo.He@amd.com> --- drivers/gpu/drm/ttm/ttm_memory.c | 24 ++++++++++++++++-------- drivers/gpu/drm/ttm/ttm_tt.c | 13 +++++++++++-- include/drm/ttm/ttm_memory.h | 2 ++ 3 files changed, 29 insertions(+), 10 deletions(-)