diff mbox

[1/2] drm/ttm: add swap_glob_mem in ttm_mem_global

Message ID 1517214673-30962-1-git-send-email-Hongbo.He@amd.com (mailing list archive)
State New, archived
Headers show

Commit Message

He, Hongbo Jan. 29, 2018, 8:31 a.m. UTC
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(-)

Comments

Chunming Zhou Jan. 31, 2018, 7:43 a.m. UTC | #1
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 mbox

Patch

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;