for avoid OOM. if free swap space is less than 256MB, reject the TTM page allocation. Otherwise, swap space will be full of swapped pages and then system memory will be filled up with ttm pages. and then any memory allocation request will trigger OOM. to cover two cases: a. If total swap space > 256MB and at that time free swap space is under 256MB but available system mem > its lower limit, allow TTM allocation; b. if total swap space < 256 or no swap disk at all, check the available system mem, if it is bigger than its threshold, allow TTM allocation. Signed-off-by: Roger He <Hongbo.He at amd.com> --- drivers/gpu/drm/ttm/ttm_memory.c | 31 ++++++++++++++++++++++++++++++- include/drm/ttm/ttm_memory.h | 3 +++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/ttm/ttm_memory.c b/drivers/gpu/drm/ttm/ttm_memory.c index aa0c381..e19e727 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 @@ -374,7 +375,8 @@ int ttm_mem_global_init(struct ttm_mem_global *glob) } si_meminfo(&si); - + /* keep consistent with each zone->emer_mem */ + glob->sys_mem_limit = si.totalram >> 2; ret = ttm_mem_init_kernel_zone(glob, &si); if (unlikely(ret != 0)) goto out_no_zone; @@ -469,6 +471,30 @@ void ttm_mem_global_free(struct ttm_mem_global *glob, } EXPORT_SYMBOL(ttm_mem_global_free); + +#define FREE_SWAP_SPACE (256 << 8) +/* + * check if the free swap space is under limit 256MB. + * + * a. if free swap space is under 256MB but available system mem is + * bigger than its lower limit, allow TTM allocation; + * + * b. if no swap disk at all or less than 256MB at the beginning, check + * the available system mem, if bigger than its threshold, allow TTM + * allocation. + */ +static bool +ttm_check_over_swaplimit(struct ttm_mem_global *glob) +{ + bool ret = false; + + if (get_nr_swap_pages() < FREE_SWAP_SPACE + && si_mem_available() < glob->sys_mem_limit) + ret = true; + + return ret; +} + static int ttm_mem_global_reserve(struct ttm_mem_global *glob, struct ttm_mem_zone *single_zone, uint64_t amount, bool reserve) @@ -478,6 +504,9 @@ static int ttm_mem_global_reserve(struct ttm_mem_global *glob, unsigned int i; struct ttm_mem_zone *zone; + if (ttm_check_over_swaplimit(glob)) + return ret; + spin_lock(&glob->lock); for (i = 0; i < glob->num_zones; ++i) { zone = glob->zones[i]; diff --git a/include/drm/ttm/ttm_memory.h b/include/drm/ttm/ttm_memory.h index 8936285..ad7cf63 100644 --- a/include/drm/ttm/ttm_memory.h +++ b/include/drm/ttm/ttm_memory.h @@ -49,6 +49,8 @@ * @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. + * @sys_mem_limit: if free ram is under this threshold and free swap space is + * less than its limit, reject any TTM allocation request * @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 +69,7 @@ struct ttm_mem_global { struct workqueue_struct *swap_queue; struct work_struct work; spinlock_t lock; + uint64_t sys_mem_limit; struct ttm_mem_zone *zones[TTM_MEM_MAX_ZONES]; unsigned int num_zones; struct ttm_mem_zone *zone_kernel; -- 2.7.4