diff mbox series

[1/2] drm/ttm: fix busy memory to fail other user v7

Message ID 20190507114531.26089-1-david1.zhou@amd.com (mailing list archive)
State New, archived
Headers show
Series [1/2] drm/ttm: fix busy memory to fail other user v7 | expand

Commit Message

Chunming Zhou May 7, 2019, 11:45 a.m. UTC
heavy gpu job could occupy memory long time, which lead other user fail to get memory.

basically pick up Christian idea:

1. Reserve the BO in DC using a ww_mutex ticket (trivial).
2. If we then run into this EBUSY condition in TTM check if the BO we need memory for (or rather the ww_mutex of its reservation object) has a ticket assigned.
3. If we have a ticket we grab a reference to the first BO on the LRU, drop the LRU lock and try to grab the reservation lock with the ticket.
4. If getting the reservation lock with the ticket succeeded we check if the BO is still the first one on the LRU in question (the BO could have moved).
5. If the BO is still the first one on the LRU in question we try to evict it as we would evict any other BO.
6. If any of the "If's" above fail we just back off and return -EBUSY.

v2: fix some minor check
v3: address Christian v2 comments.
v4: fix some missing
v5: handle first_bo unlock and bo_get/put
v6: abstract unified iterate function, and handle all possible usecase not only pinned bo.
v7: pass request bo->resv to ttm_bo_evict_first

Change-Id: I21423fb922f885465f13833c41df1e134364a8e7
Signed-off-by: Chunming Zhou <david1.zhou@amd.com>
---
 drivers/gpu/drm/ttm/ttm_bo.c | 111 +++++++++++++++++++++++++++++------
 1 file changed, 94 insertions(+), 17 deletions(-)

Comments

Christian König May 7, 2019, 11:51 a.m. UTC | #1
Am 07.05.19 um 13:45 schrieb Chunming Zhou:
> heavy gpu job could occupy memory long time, which lead other user fail to get memory.
>
> basically pick up Christian idea:
>
> 1. Reserve the BO in DC using a ww_mutex ticket (trivial).
> 2. If we then run into this EBUSY condition in TTM check if the BO we need memory for (or rather the ww_mutex of its reservation object) has a ticket assigned.
> 3. If we have a ticket we grab a reference to the first BO on the LRU, drop the LRU lock and try to grab the reservation lock with the ticket.
> 4. If getting the reservation lock with the ticket succeeded we check if the BO is still the first one on the LRU in question (the BO could have moved).
> 5. If the BO is still the first one on the LRU in question we try to evict it as we would evict any other BO.
> 6. If any of the "If's" above fail we just back off and return -EBUSY.
>
> v2: fix some minor check
> v3: address Christian v2 comments.
> v4: fix some missing
> v5: handle first_bo unlock and bo_get/put
> v6: abstract unified iterate function, and handle all possible usecase not only pinned bo.
> v7: pass request bo->resv to ttm_bo_evict_first
>
> Change-Id: I21423fb922f885465f13833c41df1e134364a8e7
> Signed-off-by: Chunming Zhou <david1.zhou@amd.com>

Reviewed-by: Christian König <christian.koenig@amd.com>

Please leave me a note when this hits amd-staging-drm-next, cause I need 
to test why it didn't helped with Mareks problem.

Christian.

> ---
>   drivers/gpu/drm/ttm/ttm_bo.c | 111 +++++++++++++++++++++++++++++------
>   1 file changed, 94 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
> index 8502b3ed2d88..f5e6328e4a57 100644
> --- a/drivers/gpu/drm/ttm/ttm_bo.c
> +++ b/drivers/gpu/drm/ttm/ttm_bo.c
> @@ -766,11 +766,13 @@ EXPORT_SYMBOL(ttm_bo_eviction_valuable);
>    * b. Otherwise, trylock it.
>    */
>   static bool ttm_bo_evict_swapout_allowable(struct ttm_buffer_object *bo,
> -			struct ttm_operation_ctx *ctx, bool *locked)
> +			struct ttm_operation_ctx *ctx, bool *locked, bool *busy)
>   {
>   	bool ret = false;
>   
>   	*locked = false;
> +	if (busy)
> +		*busy = false;
>   	if (bo->resv == ctx->resv) {
>   		reservation_object_assert_held(bo->resv);
>   		if (ctx->flags & TTM_OPT_FLAG_ALLOW_RES_EVICT
> @@ -779,35 +781,46 @@ static bool ttm_bo_evict_swapout_allowable(struct ttm_buffer_object *bo,
>   	} else {
>   		*locked = reservation_object_trylock(bo->resv);
>   		ret = *locked;
> +		if (!ret && busy)
> +			*busy = true;
>   	}
>   
>   	return ret;
>   }
>   
> -static int ttm_mem_evict_first(struct ttm_bo_device *bdev,
> -			       uint32_t mem_type,
> -			       const struct ttm_place *place,
> -			       struct ttm_operation_ctx *ctx)
> +static struct ttm_buffer_object*
> +ttm_mem_find_evitable_bo(struct ttm_bo_device *bdev,
> +			 struct ttm_mem_type_manager *man,
> +			 const struct ttm_place *place,
> +			 struct ttm_operation_ctx *ctx,
> +			 struct ttm_buffer_object **first_bo,
> +			 bool *locked)
>   {
> -	struct ttm_bo_global *glob = bdev->glob;
> -	struct ttm_mem_type_manager *man = &bdev->man[mem_type];
>   	struct ttm_buffer_object *bo = NULL;
> -	bool locked = false;
> -	unsigned i;
> -	int ret;
> +	int i;
>   
> -	spin_lock(&glob->lru_lock);
> +	if (first_bo)
> +		*first_bo = NULL;
>   	for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
>   		list_for_each_entry(bo, &man->lru[i], lru) {
> -			if (!ttm_bo_evict_swapout_allowable(bo, ctx, &locked))
> +			bool busy = false;
> +
> +			if (!ttm_bo_evict_swapout_allowable(bo, ctx, locked,
> +							    &busy)) {
> +				if (first_bo && !(*first_bo) && busy) {
> +					ttm_bo_get(bo);
> +					*first_bo = bo;
> +				}
>   				continue;
> +			}
>   
>   			if (place && !bdev->driver->eviction_valuable(bo,
>   								      place)) {
> -				if (locked)
> +				if (*locked)
>   					reservation_object_unlock(bo->resv);
>   				continue;
>   			}
> +
>   			break;
>   		}
>   
> @@ -818,9 +831,67 @@ static int ttm_mem_evict_first(struct ttm_bo_device *bdev,
>   		bo = NULL;
>   	}
>   
> +	return bo;
> +}
> +
> +static int ttm_mem_evict_first(struct ttm_bo_device *bdev,
> +			       uint32_t mem_type,
> +			       const struct ttm_place *place,
> +			       struct ttm_operation_ctx *ctx,
> +			       struct reservation_object *request_resv)
> +{
> +	struct ttm_bo_global *glob = bdev->glob;
> +	struct ttm_mem_type_manager *man = &bdev->man[mem_type];
> +	struct ttm_buffer_object *bo = NULL, *first_bo = NULL;
> +	bool locked = false;
> +	int ret;
> +
> +	spin_lock(&glob->lru_lock);
> +	bo = ttm_mem_find_evitable_bo(bdev, man, place, ctx, &first_bo,
> +				      &locked);
>   	if (!bo) {
> +		struct ttm_operation_ctx busy_ctx;
> +
>   		spin_unlock(&glob->lru_lock);
> -		return -EBUSY;
> +		/* check if other user occupy memory too long time */
> +		if (!first_bo || !request_resv || !request_resv->lock.ctx) {
> +			if (first_bo)
> +				ttm_bo_put(first_bo);
> +			return -EBUSY;
> +		}
> +		if (first_bo->resv == request_resv) {
> +			ttm_bo_put(first_bo);
> +			return -EBUSY;
> +		}
> +		if (ctx->interruptible)
> +			ret = ww_mutex_lock_interruptible(&first_bo->resv->lock,
> +							  request_resv->lock.ctx);
> +		else
> +			ret = ww_mutex_lock(&first_bo->resv->lock, request_resv->lock.ctx);
> +		if (ret) {
> +			ttm_bo_put(first_bo);
> +			return ret;
> +		}
> +		spin_lock(&glob->lru_lock);
> +		/* previous busy resv lock is held by above, idle now,
> +		 * so let them evictable.
> +		 */
> +		busy_ctx.interruptible = ctx->interruptible;
> +		busy_ctx.no_wait_gpu   = ctx->no_wait_gpu;
> +		busy_ctx.resv	       = first_bo->resv;
> +		busy_ctx.flags	       = TTM_OPT_FLAG_ALLOW_RES_EVICT;
> +
> +		bo = ttm_mem_find_evitable_bo(bdev, man, place, &busy_ctx, NULL,
> +					      &locked);
> +		if (bo && (bo->resv == first_bo->resv))
> +			locked = true;
> +		else if (bo)
> +			ww_mutex_unlock(&first_bo->resv->lock);
> +		if (!bo) {
> +			spin_unlock(&glob->lru_lock);
> +			ttm_bo_put(first_bo);
> +			return -EBUSY;
> +		}
>   	}
>   
>   	kref_get(&bo->list_kref);
> @@ -829,11 +900,15 @@ static int ttm_mem_evict_first(struct ttm_bo_device *bdev,
>   		ret = ttm_bo_cleanup_refs(bo, ctx->interruptible,
>   					  ctx->no_wait_gpu, locked);
>   		kref_put(&bo->list_kref, ttm_bo_release_list);
> +		if (first_bo)
> +			ttm_bo_put(first_bo);
>   		return ret;
>   	}
>   
>   	ttm_bo_del_from_lru(bo);
>   	spin_unlock(&glob->lru_lock);
> +	if (first_bo)
> +		ttm_bo_put(first_bo);
>   
>   	ret = ttm_bo_evict(bo, ctx);
>   	if (locked) {
> @@ -907,7 +982,7 @@ static int ttm_bo_mem_force_space(struct ttm_buffer_object *bo,
>   			return ret;
>   		if (mem->mm_node)
>   			break;
> -		ret = ttm_mem_evict_first(bdev, mem_type, place, ctx);
> +		ret = ttm_mem_evict_first(bdev, mem_type, place, ctx, bo->resv);
>   		if (unlikely(ret != 0))
>   			return ret;
>   	} while (1);
> @@ -1413,7 +1488,8 @@ static int ttm_bo_force_list_clean(struct ttm_bo_device *bdev,
>   	for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
>   		while (!list_empty(&man->lru[i])) {
>   			spin_unlock(&glob->lru_lock);
> -			ret = ttm_mem_evict_first(bdev, mem_type, NULL, &ctx);
> +			ret = ttm_mem_evict_first(bdev, mem_type, NULL, &ctx,
> +						  NULL);
>   			if (ret)
>   				return ret;
>   			spin_lock(&glob->lru_lock);
> @@ -1784,7 +1860,8 @@ int ttm_bo_swapout(struct ttm_bo_global *glob, struct ttm_operation_ctx *ctx)
>   	spin_lock(&glob->lru_lock);
>   	for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
>   		list_for_each_entry(bo, &glob->swap_lru[i], swap) {
> -			if (ttm_bo_evict_swapout_allowable(bo, ctx, &locked)) {
> +			if (ttm_bo_evict_swapout_allowable(bo, ctx, &locked,
> +							   NULL)) {
>   				ret = 0;
>   				break;
>   			}
Christian König May 9, 2019, 2:28 p.m. UTC | #2
I've foudn one more problem with this.

With lockdep enabled I get a warning because ttm_eu_reserve_buffers() 
has called ww_acquire_done() on the ticket (which essentially means we 
are done, no more locking with that ticket).

The simplest solution is probably to just remove the call to 
ww_acquire_done() from ttm_eu_reserve_buffers().

Christian.

Am 07.05.19 um 13:45 schrieb Chunming Zhou:
> heavy gpu job could occupy memory long time, which lead other user fail to get memory.
>
> basically pick up Christian idea:
>
> 1. Reserve the BO in DC using a ww_mutex ticket (trivial).
> 2. If we then run into this EBUSY condition in TTM check if the BO we need memory for (or rather the ww_mutex of its reservation object) has a ticket assigned.
> 3. If we have a ticket we grab a reference to the first BO on the LRU, drop the LRU lock and try to grab the reservation lock with the ticket.
> 4. If getting the reservation lock with the ticket succeeded we check if the BO is still the first one on the LRU in question (the BO could have moved).
> 5. If the BO is still the first one on the LRU in question we try to evict it as we would evict any other BO.
> 6. If any of the "If's" above fail we just back off and return -EBUSY.
>
> v2: fix some minor check
> v3: address Christian v2 comments.
> v4: fix some missing
> v5: handle first_bo unlock and bo_get/put
> v6: abstract unified iterate function, and handle all possible usecase not only pinned bo.
> v7: pass request bo->resv to ttm_bo_evict_first
>
> Change-Id: I21423fb922f885465f13833c41df1e134364a8e7
> Signed-off-by: Chunming Zhou <david1.zhou@amd.com>
> ---
>   drivers/gpu/drm/ttm/ttm_bo.c | 111 +++++++++++++++++++++++++++++------
>   1 file changed, 94 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
> index 8502b3ed2d88..f5e6328e4a57 100644
> --- a/drivers/gpu/drm/ttm/ttm_bo.c
> +++ b/drivers/gpu/drm/ttm/ttm_bo.c
> @@ -766,11 +766,13 @@ EXPORT_SYMBOL(ttm_bo_eviction_valuable);
>    * b. Otherwise, trylock it.
>    */
>   static bool ttm_bo_evict_swapout_allowable(struct ttm_buffer_object *bo,
> -			struct ttm_operation_ctx *ctx, bool *locked)
> +			struct ttm_operation_ctx *ctx, bool *locked, bool *busy)
>   {
>   	bool ret = false;
>   
>   	*locked = false;
> +	if (busy)
> +		*busy = false;
>   	if (bo->resv == ctx->resv) {
>   		reservation_object_assert_held(bo->resv);
>   		if (ctx->flags & TTM_OPT_FLAG_ALLOW_RES_EVICT
> @@ -779,35 +781,46 @@ static bool ttm_bo_evict_swapout_allowable(struct ttm_buffer_object *bo,
>   	} else {
>   		*locked = reservation_object_trylock(bo->resv);
>   		ret = *locked;
> +		if (!ret && busy)
> +			*busy = true;
>   	}
>   
>   	return ret;
>   }
>   
> -static int ttm_mem_evict_first(struct ttm_bo_device *bdev,
> -			       uint32_t mem_type,
> -			       const struct ttm_place *place,
> -			       struct ttm_operation_ctx *ctx)
> +static struct ttm_buffer_object*
> +ttm_mem_find_evitable_bo(struct ttm_bo_device *bdev,
> +			 struct ttm_mem_type_manager *man,
> +			 const struct ttm_place *place,
> +			 struct ttm_operation_ctx *ctx,
> +			 struct ttm_buffer_object **first_bo,
> +			 bool *locked)
>   {
> -	struct ttm_bo_global *glob = bdev->glob;
> -	struct ttm_mem_type_manager *man = &bdev->man[mem_type];
>   	struct ttm_buffer_object *bo = NULL;
> -	bool locked = false;
> -	unsigned i;
> -	int ret;
> +	int i;
>   
> -	spin_lock(&glob->lru_lock);
> +	if (first_bo)
> +		*first_bo = NULL;
>   	for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
>   		list_for_each_entry(bo, &man->lru[i], lru) {
> -			if (!ttm_bo_evict_swapout_allowable(bo, ctx, &locked))
> +			bool busy = false;
> +
> +			if (!ttm_bo_evict_swapout_allowable(bo, ctx, locked,
> +							    &busy)) {
> +				if (first_bo && !(*first_bo) && busy) {
> +					ttm_bo_get(bo);
> +					*first_bo = bo;
> +				}
>   				continue;
> +			}
>   
>   			if (place && !bdev->driver->eviction_valuable(bo,
>   								      place)) {
> -				if (locked)
> +				if (*locked)
>   					reservation_object_unlock(bo->resv);
>   				continue;
>   			}
> +
>   			break;
>   		}
>   
> @@ -818,9 +831,67 @@ static int ttm_mem_evict_first(struct ttm_bo_device *bdev,
>   		bo = NULL;
>   	}
>   
> +	return bo;
> +}
> +
> +static int ttm_mem_evict_first(struct ttm_bo_device *bdev,
> +			       uint32_t mem_type,
> +			       const struct ttm_place *place,
> +			       struct ttm_operation_ctx *ctx,
> +			       struct reservation_object *request_resv)
> +{
> +	struct ttm_bo_global *glob = bdev->glob;
> +	struct ttm_mem_type_manager *man = &bdev->man[mem_type];
> +	struct ttm_buffer_object *bo = NULL, *first_bo = NULL;
> +	bool locked = false;
> +	int ret;
> +
> +	spin_lock(&glob->lru_lock);
> +	bo = ttm_mem_find_evitable_bo(bdev, man, place, ctx, &first_bo,
> +				      &locked);
>   	if (!bo) {
> +		struct ttm_operation_ctx busy_ctx;
> +
>   		spin_unlock(&glob->lru_lock);
> -		return -EBUSY;
> +		/* check if other user occupy memory too long time */
> +		if (!first_bo || !request_resv || !request_resv->lock.ctx) {
> +			if (first_bo)
> +				ttm_bo_put(first_bo);
> +			return -EBUSY;
> +		}
> +		if (first_bo->resv == request_resv) {
> +			ttm_bo_put(first_bo);
> +			return -EBUSY;
> +		}
> +		if (ctx->interruptible)
> +			ret = ww_mutex_lock_interruptible(&first_bo->resv->lock,
> +							  request_resv->lock.ctx);
> +		else
> +			ret = ww_mutex_lock(&first_bo->resv->lock, request_resv->lock.ctx);
> +		if (ret) {
> +			ttm_bo_put(first_bo);
> +			return ret;
> +		}
> +		spin_lock(&glob->lru_lock);
> +		/* previous busy resv lock is held by above, idle now,
> +		 * so let them evictable.
> +		 */
> +		busy_ctx.interruptible = ctx->interruptible;
> +		busy_ctx.no_wait_gpu   = ctx->no_wait_gpu;
> +		busy_ctx.resv	       = first_bo->resv;
> +		busy_ctx.flags	       = TTM_OPT_FLAG_ALLOW_RES_EVICT;
> +
> +		bo = ttm_mem_find_evitable_bo(bdev, man, place, &busy_ctx, NULL,
> +					      &locked);
> +		if (bo && (bo->resv == first_bo->resv))
> +			locked = true;
> +		else if (bo)
> +			ww_mutex_unlock(&first_bo->resv->lock);
> +		if (!bo) {
> +			spin_unlock(&glob->lru_lock);
> +			ttm_bo_put(first_bo);
> +			return -EBUSY;
> +		}
>   	}
>   
>   	kref_get(&bo->list_kref);
> @@ -829,11 +900,15 @@ static int ttm_mem_evict_first(struct ttm_bo_device *bdev,
>   		ret = ttm_bo_cleanup_refs(bo, ctx->interruptible,
>   					  ctx->no_wait_gpu, locked);
>   		kref_put(&bo->list_kref, ttm_bo_release_list);
> +		if (first_bo)
> +			ttm_bo_put(first_bo);
>   		return ret;
>   	}
>   
>   	ttm_bo_del_from_lru(bo);
>   	spin_unlock(&glob->lru_lock);
> +	if (first_bo)
> +		ttm_bo_put(first_bo);
>   
>   	ret = ttm_bo_evict(bo, ctx);
>   	if (locked) {
> @@ -907,7 +982,7 @@ static int ttm_bo_mem_force_space(struct ttm_buffer_object *bo,
>   			return ret;
>   		if (mem->mm_node)
>   			break;
> -		ret = ttm_mem_evict_first(bdev, mem_type, place, ctx);
> +		ret = ttm_mem_evict_first(bdev, mem_type, place, ctx, bo->resv);
>   		if (unlikely(ret != 0))
>   			return ret;
>   	} while (1);
> @@ -1413,7 +1488,8 @@ static int ttm_bo_force_list_clean(struct ttm_bo_device *bdev,
>   	for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
>   		while (!list_empty(&man->lru[i])) {
>   			spin_unlock(&glob->lru_lock);
> -			ret = ttm_mem_evict_first(bdev, mem_type, NULL, &ctx);
> +			ret = ttm_mem_evict_first(bdev, mem_type, NULL, &ctx,
> +						  NULL);
>   			if (ret)
>   				return ret;
>   			spin_lock(&glob->lru_lock);
> @@ -1784,7 +1860,8 @@ int ttm_bo_swapout(struct ttm_bo_global *glob, struct ttm_operation_ctx *ctx)
>   	spin_lock(&glob->lru_lock);
>   	for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
>   		list_for_each_entry(bo, &glob->swap_lru[i], swap) {
> -			if (ttm_bo_evict_swapout_allowable(bo, ctx, &locked)) {
> +			if (ttm_bo_evict_swapout_allowable(bo, ctx, &locked,
> +							   NULL)) {
>   				ret = 0;
>   				break;
>   			}
Chunming Zhou May 9, 2019, 2:46 p.m. UTC | #3
I know that before, it will issue warning only when debug option is enabled. Removing that is ok to me.
I only help Prike draft your idea, and Prike is trying this patch on his side. The latest feedback he gave me is first_bo is always null, code doesn't run into busy path, which is very confusing me, and he said  he is debugging  that.

-David


-------- Original Message --------
Subject: Re: [PATCH 1/2] drm/ttm: fix busy memory to fail other user v7
From: "Koenig, Christian"
To: "Zhou, David(ChunMing)" ,"Liang, Prike" ,dri-devel@lists.freedesktop.org
CC:

I've foudn one more problem with this.

With lockdep enabled I get a warning because ttm_eu_reserve_buffers()
has called ww_acquire_done() on the ticket (which essentially means we
are done, no more locking with that ticket).

The simplest solution is probably to just remove the call to
ww_acquire_done() from ttm_eu_reserve_buffers().

Christian.

Am 07.05.19 um 13:45 schrieb Chunming Zhou:
> heavy gpu job could occupy memory long time, which lead other user fail to get memory.
>
> basically pick up Christian idea:
>
> 1. Reserve the BO in DC using a ww_mutex ticket (trivial).
> 2. If we then run into this EBUSY condition in TTM check if the BO we need memory for (or rather the ww_mutex of its reservation object) has a ticket assigned.
> 3. If we have a ticket we grab a reference to the first BO on the LRU, drop the LRU lock and try to grab the reservation lock with the ticket.
> 4. If getting the reservation lock with the ticket succeeded we check if the BO is still the first one on the LRU in question (the BO could have moved).
> 5. If the BO is still the first one on the LRU in question we try to evict it as we would evict any other BO.
> 6. If any of the "If's" above fail we just back off and return -EBUSY.
>
> v2: fix some minor check
> v3: address Christian v2 comments.
> v4: fix some missing
> v5: handle first_bo unlock and bo_get/put
> v6: abstract unified iterate function, and handle all possible usecase not only pinned bo.
> v7: pass request bo->resv to ttm_bo_evict_first
>
> Change-Id: I21423fb922f885465f13833c41df1e134364a8e7
> Signed-off-by: Chunming Zhou <david1.zhou@amd.com>
> ---
>   drivers/gpu/drm/ttm/ttm_bo.c | 111 +++++++++++++++++++++++++++++------
>   1 file changed, 94 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
> index 8502b3ed2d88..f5e6328e4a57 100644
> --- a/drivers/gpu/drm/ttm/ttm_bo.c
> +++ b/drivers/gpu/drm/ttm/ttm_bo.c
> @@ -766,11 +766,13 @@ EXPORT_SYMBOL(ttm_bo_eviction_valuable);
>    * b. Otherwise, trylock it.
>    */
>   static bool ttm_bo_evict_swapout_allowable(struct ttm_buffer_object *bo,
> -                     struct ttm_operation_ctx *ctx, bool *locked)
> +                     struct ttm_operation_ctx *ctx, bool *locked, bool *busy)
>   {
>        bool ret = false;
>
>        *locked = false;
> +     if (busy)
> +             *busy = false;
>        if (bo->resv == ctx->resv) {
>                reservation_object_assert_held(bo->resv);
>                if (ctx->flags & TTM_OPT_FLAG_ALLOW_RES_EVICT
> @@ -779,35 +781,46 @@ static bool ttm_bo_evict_swapout_allowable(struct ttm_buffer_object *bo,
>        } else {
>                *locked = reservation_object_trylock(bo->resv);
>                ret = *locked;
> +             if (!ret && busy)
> +                     *busy = true;
>        }
>
>        return ret;
>   }
>
> -static int ttm_mem_evict_first(struct ttm_bo_device *bdev,
> -                            uint32_t mem_type,
> -                            const struct ttm_place *place,
> -                            struct ttm_operation_ctx *ctx)
> +static struct ttm_buffer_object*
> +ttm_mem_find_evitable_bo(struct ttm_bo_device *bdev,
> +                      struct ttm_mem_type_manager *man,
> +                      const struct ttm_place *place,
> +                      struct ttm_operation_ctx *ctx,
> +                      struct ttm_buffer_object **first_bo,
> +                      bool *locked)
>   {
> -     struct ttm_bo_global *glob = bdev->glob;
> -     struct ttm_mem_type_manager *man = &bdev->man[mem_type];
>        struct ttm_buffer_object *bo = NULL;
> -     bool locked = false;
> -     unsigned i;
> -     int ret;
> +     int i;
>
> -     spin_lock(&glob->lru_lock);
> +     if (first_bo)
> +             *first_bo = NULL;
>        for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
>                list_for_each_entry(bo, &man->lru[i], lru) {
> -                     if (!ttm_bo_evict_swapout_allowable(bo, ctx, &locked))
> +                     bool busy = false;
> +
> +                     if (!ttm_bo_evict_swapout_allowable(bo, ctx, locked,
> +                                                         &busy)) {
> +                             if (first_bo && !(*first_bo) && busy) {
> +                                     ttm_bo_get(bo);
> +                                     *first_bo = bo;
> +                             }
>                                continue;
> +                     }
>
>                        if (place && !bdev->driver->eviction_valuable(bo,
>                                                                      place)) {
> -                             if (locked)
> +                             if (*locked)
>                                        reservation_object_unlock(bo->resv);
>                                continue;
>                        }
> +
>                        break;
>                }
>
> @@ -818,9 +831,67 @@ static int ttm_mem_evict_first(struct ttm_bo_device *bdev,
>                bo = NULL;
>        }
>
> +     return bo;
> +}
> +
> +static int ttm_mem_evict_first(struct ttm_bo_device *bdev,
> +                            uint32_t mem_type,
> +                            const struct ttm_place *place,
> +                            struct ttm_operation_ctx *ctx,
> +                            struct reservation_object *request_resv)
> +{
> +     struct ttm_bo_global *glob = bdev->glob;
> +     struct ttm_mem_type_manager *man = &bdev->man[mem_type];
> +     struct ttm_buffer_object *bo = NULL, *first_bo = NULL;
> +     bool locked = false;
> +     int ret;
> +
> +     spin_lock(&glob->lru_lock);
> +     bo = ttm_mem_find_evitable_bo(bdev, man, place, ctx, &first_bo,
> +                                   &locked);
>        if (!bo) {
> +             struct ttm_operation_ctx busy_ctx;
> +
>                spin_unlock(&glob->lru_lock);
> -             return -EBUSY;
> +             /* check if other user occupy memory too long time */
> +             if (!first_bo || !request_resv || !request_resv->lock.ctx) {
> +                     if (first_bo)
> +                             ttm_bo_put(first_bo);
> +                     return -EBUSY;
> +             }
> +             if (first_bo->resv == request_resv) {
> +                     ttm_bo_put(first_bo);
> +                     return -EBUSY;
> +             }
> +             if (ctx->interruptible)
> +                     ret = ww_mutex_lock_interruptible(&first_bo->resv->lock,
> +                                                       request_resv->lock.ctx);
> +             else
> +                     ret = ww_mutex_lock(&first_bo->resv->lock, request_resv->lock.ctx);
> +             if (ret) {
> +                     ttm_bo_put(first_bo);
> +                     return ret;
> +             }
> +             spin_lock(&glob->lru_lock);
> +             /* previous busy resv lock is held by above, idle now,
> +              * so let them evictable.
> +              */
> +             busy_ctx.interruptible = ctx->interruptible;
> +             busy_ctx.no_wait_gpu   = ctx->no_wait_gpu;
> +             busy_ctx.resv          = first_bo->resv;
> +             busy_ctx.flags         = TTM_OPT_FLAG_ALLOW_RES_EVICT;
> +
> +             bo = ttm_mem_find_evitable_bo(bdev, man, place, &busy_ctx, NULL,
> +                                           &locked);
> +             if (bo && (bo->resv == first_bo->resv))
> +                     locked = true;
> +             else if (bo)
> +                     ww_mutex_unlock(&first_bo->resv->lock);
> +             if (!bo) {
> +                     spin_unlock(&glob->lru_lock);
> +                     ttm_bo_put(first_bo);
> +                     return -EBUSY;
> +             }
>        }
>
>        kref_get(&bo->list_kref);
> @@ -829,11 +900,15 @@ static int ttm_mem_evict_first(struct ttm_bo_device *bdev,
>                ret = ttm_bo_cleanup_refs(bo, ctx->interruptible,
>                                          ctx->no_wait_gpu, locked);
>                kref_put(&bo->list_kref, ttm_bo_release_list);
> +             if (first_bo)
> +                     ttm_bo_put(first_bo);
>                return ret;
>        }
>
>        ttm_bo_del_from_lru(bo);
>        spin_unlock(&glob->lru_lock);
> +     if (first_bo)
> +             ttm_bo_put(first_bo);
>
>        ret = ttm_bo_evict(bo, ctx);
>        if (locked) {
> @@ -907,7 +982,7 @@ static int ttm_bo_mem_force_space(struct ttm_buffer_object *bo,
>                        return ret;
>                if (mem->mm_node)
>                        break;
> -             ret = ttm_mem_evict_first(bdev, mem_type, place, ctx);
> +             ret = ttm_mem_evict_first(bdev, mem_type, place, ctx, bo->resv);
>                if (unlikely(ret != 0))
>                        return ret;
>        } while (1);
> @@ -1413,7 +1488,8 @@ static int ttm_bo_force_list_clean(struct ttm_bo_device *bdev,
>        for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
>                while (!list_empty(&man->lru[i])) {
>                        spin_unlock(&glob->lru_lock);
> -                     ret = ttm_mem_evict_first(bdev, mem_type, NULL, &ctx);
> +                     ret = ttm_mem_evict_first(bdev, mem_type, NULL, &ctx,
> +                                               NULL);
>                        if (ret)
>                                return ret;
>                        spin_lock(&glob->lru_lock);
> @@ -1784,7 +1860,8 @@ int ttm_bo_swapout(struct ttm_bo_global *glob, struct ttm_operation_ctx *ctx)
>        spin_lock(&glob->lru_lock);
>        for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
>                list_for_each_entry(bo, &glob->swap_lru[i], swap) {
> -                     if (ttm_bo_evict_swapout_allowable(bo, ctx, &locked)) {
> +                     if (ttm_bo_evict_swapout_allowable(bo, ctx, &locked,
> +                                                        NULL)) {
>                                ret = 0;
>                                break;
>                        }
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
<meta name="Generator" content="Microsoft Exchange Server">
<!-- converted from text --><style><!-- .EmailQuote { margin-left: 1pt; padding-left: 4pt; border-left: #800000 2px solid; } --></style>
</head>
<body>
<div>I know that before, it will issue warning only when debug option is enabled. Removing that is ok to me.<br>
I only help Prike draft your idea, and Prike is trying this patch on his side. The latest feedback he gave me is first_bo is always null, code doesn't run into busy path, which is very confusing me, and he said&nbsp; he is debugging&nbsp; that.<br>
<br>
-David<br>
<br>
<br>
-------- Original Message --------<br>
Subject: Re: [PATCH 1/2] drm/ttm: fix busy memory to fail other user v7<br>
From: &quot;Koenig, Christian&quot; <br>
To: &quot;Zhou, David(ChunMing)&quot; ,&quot;Liang, Prike&quot; ,dri-devel@lists.freedesktop.org<br>
CC: <br>
<br>
</div>
<font size="2"><span style="font-size:11pt;">
<div class="PlainText">I've foudn one more problem with this.<br>
<br>
With lockdep enabled I get a warning because ttm_eu_reserve_buffers() <br>
has called ww_acquire_done() on the ticket (which essentially means we <br>
are done, no more locking with that ticket).<br>
<br>
The simplest solution is probably to just remove the call to <br>
ww_acquire_done() from ttm_eu_reserve_buffers().<br>
<br>
Christian.<br>
<br>
Am 07.05.19 um 13:45 schrieb Chunming Zhou:<br>
&gt; heavy gpu job could occupy memory long time, which lead other user fail to get memory.<br>
&gt;<br>
&gt; basically pick up Christian idea:<br>
&gt;<br>
&gt; 1. Reserve the BO in DC using a ww_mutex ticket (trivial).<br>
&gt; 2. If we then run into this EBUSY condition in TTM check if the BO we need memory for (or rather the ww_mutex of its reservation object) has a ticket assigned.<br>
&gt; 3. If we have a ticket we grab a reference to the first BO on the LRU, drop the LRU lock and try to grab the reservation lock with the ticket.<br>
&gt; 4. If getting the reservation lock with the ticket succeeded we check if the BO is still the first one on the LRU in question (the BO could have moved).<br>
&gt; 5. If the BO is still the first one on the LRU in question we try to evict it as we would evict any other BO.<br>
&gt; 6. If any of the &quot;If's&quot; above fail we just back off and return -EBUSY.<br>
&gt;<br>
&gt; v2: fix some minor check<br>
&gt; v3: address Christian v2 comments.<br>
&gt; v4: fix some missing<br>
&gt; v5: handle first_bo unlock and bo_get/put<br>
&gt; v6: abstract unified iterate function, and handle all possible usecase not only pinned bo.<br>
&gt; v7: pass request bo-&gt;resv to ttm_bo_evict_first<br>
&gt;<br>
&gt; Change-Id: I21423fb922f885465f13833c41df1e134364a8e7<br>
&gt; Signed-off-by: Chunming Zhou &lt;david1.zhou@amd.com&gt;<br>
&gt; ---<br>
&gt;&nbsp;&nbsp; drivers/gpu/drm/ttm/ttm_bo.c | 111 &#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;------<br>
&gt;&nbsp;&nbsp; 1 file changed, 94 insertions(&#43;), 17 deletions(-)<br>
&gt;<br>
&gt; diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c<br>
&gt; index 8502b3ed2d88..f5e6328e4a57 100644<br>
&gt; --- a/drivers/gpu/drm/ttm/ttm_bo.c<br>
&gt; &#43;&#43;&#43; b/drivers/gpu/drm/ttm/ttm_bo.c<br>
&gt; @@ -766,11 &#43;766,13 @@ EXPORT_SYMBOL(ttm_bo_eviction_valuable);<br>
&gt;&nbsp;&nbsp;&nbsp; * b. Otherwise, trylock it.<br>
&gt;&nbsp;&nbsp;&nbsp; */<br>
&gt;&nbsp;&nbsp; static bool ttm_bo_evict_swapout_allowable(struct ttm_buffer_object *bo,<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct ttm_operation_ctx *ctx, bool *locked)<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct ttm_operation_ctx *ctx, bool *locked, bool *busy)<br>
&gt;&nbsp;&nbsp; {<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bool ret = false;<br>
&gt;&nbsp;&nbsp; <br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *locked = false;<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; if (busy)<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *busy = false;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (bo-&gt;resv == ctx-&gt;resv) {<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; reservation_object_assert_held(bo-&gt;resv);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ctx-&gt;flags &amp; TTM_OPT_FLAG_ALLOW_RES_EVICT<br>
&gt; @@ -779,35 &#43;781,46 @@ static bool ttm_bo_evict_swapout_allowable(struct ttm_buffer_object *bo,<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *locked = reservation_object_trylock(bo-&gt;resv);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret = *locked;<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!ret &amp;&amp; busy)<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *busy = true;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&gt;&nbsp;&nbsp; <br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ret;<br>
&gt;&nbsp;&nbsp; }<br>
&gt;&nbsp;&nbsp; <br>
&gt; -static int ttm_mem_evict_first(struct ttm_bo_device *bdev,<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t mem_type,<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; const struct ttm_place *place,<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct ttm_operation_ctx *ctx)<br>
&gt; &#43;static struct ttm_buffer_object*<br>
&gt; &#43;ttm_mem_find_evitable_bo(struct ttm_bo_device *bdev,<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct ttm_mem_type_manager *man,<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; const struct ttm_place *place,<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct ttm_operation_ctx *ctx,<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct ttm_buffer_object **first_bo,<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bool *locked)<br>
&gt;&nbsp;&nbsp; {<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp; struct ttm_bo_global *glob = bdev-&gt;glob;<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp; struct ttm_mem_type_manager *man = &amp;bdev-&gt;man[mem_type];<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct ttm_buffer_object *bo = NULL;<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp; bool locked = false;<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp; unsigned i;<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp; int ret;<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; int i;<br>
&gt;&nbsp;&nbsp; <br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp; spin_lock(&amp;glob-&gt;lru_lock);<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; if (first_bo)<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *first_bo = NULL;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (i = 0; i &lt; TTM_MAX_BO_PRIORITY; &#43;&#43;i) {<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list_for_each_entry(bo, &amp;man-&gt;lru[i], lru) {<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!ttm_bo_evict_swapout_allowable(bo, ctx, &amp;locked))<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bool busy = false;<br>
&gt; &#43;<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!ttm_bo_evict_swapout_allowable(bo, ctx, locked,<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;busy)) {<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (first_bo &amp;&amp; !(*first_bo) &amp;&amp; busy) {<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ttm_bo_get(bo);<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *first_bo = bo;<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; continue;<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&gt;&nbsp;&nbsp; <br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (place &amp;&amp; !bdev-&gt;driver-&gt;eviction_valuable(bo,<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; place)) {<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (locked)<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (*locked)<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; reservation_object_unlock(bo-&gt;resv);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; continue;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&gt; &#43;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&gt;&nbsp;&nbsp; <br>
&gt; @@ -818,9 &#43;831,67 @@ static int ttm_mem_evict_first(struct ttm_bo_device *bdev,<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bo = NULL;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&gt;&nbsp;&nbsp; <br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; return bo;<br>
&gt; &#43;}<br>
&gt; &#43;<br>
&gt; &#43;static int ttm_mem_evict_first(struct ttm_bo_device *bdev,<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t mem_type,<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; const struct ttm_place *place,<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct ttm_operation_ctx *ctx,<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct reservation_object *request_resv)<br>
&gt; &#43;{<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; struct ttm_bo_global *glob = bdev-&gt;glob;<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; struct ttm_mem_type_manager *man = &amp;bdev-&gt;man[mem_type];<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; struct ttm_buffer_object *bo = NULL, *first_bo = NULL;<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; bool locked = false;<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; int ret;<br>
&gt; &#43;<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; spin_lock(&amp;glob-&gt;lru_lock);<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; bo = ttm_mem_find_evitable_bo(bdev, man, place, ctx, &amp;first_bo,<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;locked);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!bo) {<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct ttm_operation_ctx busy_ctx;<br>
&gt; &#43;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; spin_unlock(&amp;glob-&gt;lru_lock);<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -EBUSY;<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* check if other user occupy memory too long time */<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!first_bo || !request_resv || !request_resv-&gt;lock.ctx) {<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (first_bo)<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ttm_bo_put(first_bo);<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -EBUSY;<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (first_bo-&gt;resv == request_resv) {<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ttm_bo_put(first_bo);<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -EBUSY;<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ctx-&gt;interruptible)<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret = ww_mutex_lock_interruptible(&amp;first_bo-&gt;resv-&gt;lock,<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; request_resv-&gt;lock.ctx);<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret = ww_mutex_lock(&amp;first_bo-&gt;resv-&gt;lock, request_resv-&gt;lock.ctx);<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ret) {<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ttm_bo_put(first_bo);<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ret;<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; spin_lock(&amp;glob-&gt;lru_lock);<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* previous busy resv lock is held by above, idle now,<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * so let them evictable.<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; busy_ctx.interruptible = ctx-&gt;interruptible;<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; busy_ctx.no_wait_gpu&nbsp;&nbsp; = ctx-&gt;no_wait_gpu;<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; busy_ctx.resv&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = first_bo-&gt;resv;<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; busy_ctx.flags&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = TTM_OPT_FLAG_ALLOW_RES_EVICT;<br>
&gt; &#43;<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bo = ttm_mem_find_evitable_bo(bdev, man, place, &amp;busy_ctx, NULL,<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;locked);<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (bo &amp;&amp; (bo-&gt;resv == first_bo-&gt;resv))<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; locked = true;<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if (bo)<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ww_mutex_unlock(&amp;first_bo-&gt;resv-&gt;lock);<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!bo) {<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; spin_unlock(&amp;glob-&gt;lru_lock);<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ttm_bo_put(first_bo);<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -EBUSY;<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&gt;&nbsp;&nbsp; <br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; kref_get(&amp;bo-&gt;list_kref);<br>
&gt; @@ -829,11 &#43;900,15 @@ static int ttm_mem_evict_first(struct ttm_bo_device *bdev,<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret = ttm_bo_cleanup_refs(bo, ctx-&gt;interruptible,<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ctx-&gt;no_wait_gpu, locked);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; kref_put(&amp;bo-&gt;list_kref, ttm_bo_release_list);<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (first_bo)<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ttm_bo_put(first_bo);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ret;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&gt;&nbsp;&nbsp; <br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ttm_bo_del_from_lru(bo);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; spin_unlock(&amp;glob-&gt;lru_lock);<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; if (first_bo)<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ttm_bo_put(first_bo);<br>
&gt;&nbsp;&nbsp; <br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret = ttm_bo_evict(bo, ctx);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (locked) {<br>
&gt; @@ -907,7 &#43;982,7 @@ static int ttm_bo_mem_force_space(struct ttm_buffer_object *bo,<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ret;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (mem-&gt;mm_node)<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret = ttm_mem_evict_first(bdev, mem_type, place, ctx);<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret = ttm_mem_evict_first(bdev, mem_type, place, ctx, bo-&gt;resv);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (unlikely(ret != 0))<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ret;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } while (1);<br>
&gt; @@ -1413,7 &#43;1488,8 @@ static int ttm_bo_force_list_clean(struct ttm_bo_device *bdev,<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (i = 0; i &lt; TTM_MAX_BO_PRIORITY; &#43;&#43;i) {<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (!list_empty(&amp;man-&gt;lru[i])) {<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; spin_unlock(&amp;glob-&gt;lru_lock);<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret = ttm_mem_evict_first(bdev, mem_type, NULL, &amp;ctx);<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret = ttm_mem_evict_first(bdev, mem_type, NULL, &amp;ctx,<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NULL);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ret)<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ret;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; spin_lock(&amp;glob-&gt;lru_lock);<br>
&gt; @@ -1784,7 &#43;1860,8 @@ int ttm_bo_swapout(struct ttm_bo_global *glob, struct ttm_operation_ctx *ctx)<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; spin_lock(&amp;glob-&gt;lru_lock);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (i = 0; i &lt; TTM_MAX_BO_PRIORITY; &#43;&#43;i) {<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list_for_each_entry(bo, &amp;glob-&gt;swap_lru[i], swap) {<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ttm_bo_evict_swapout_allowable(bo, ctx, &amp;locked)) {<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ttm_bo_evict_swapout_allowable(bo, ctx, &amp;locked,<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NULL)) {<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret = 0;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
<br>
</div>
</span></font>
</body>
</html>
Christian König May 9, 2019, 2:59 p.m. UTC | #4
Oh, I know where this is coming from.

The problem is that we remove the BOs from the LRU during CS and so we 
can't wait for the CS to finish up.

Already working on this problem for Marek's similar issue,
Christian.

Am 09.05.19 um 16:46 schrieb Zhou, David(ChunMing):
> I know that before, it will issue warning only when debug option is 
> enabled. Removing that is ok to me.
> I only help Prike draft your idea, and Prike is trying this patch on 
> his side. The latest feedback he gave me is first_bo is always null, 
> code doesn't run into busy path, which is very confusing me, and he 
> said  he is debugging  that.
>
> -David
>
>
> -------- Original Message --------
> Subject: Re: [PATCH 1/2] drm/ttm: fix busy memory to fail other user v7
> From: "Koenig, Christian"
> To: "Zhou, David(ChunMing)" ,"Liang, Prike" 
> ,dri-devel@lists.freedesktop.org
> CC:
>
> I've foudn one more problem with this.
>
> With lockdep enabled I get a warning because ttm_eu_reserve_buffers()
> has called ww_acquire_done() on the ticket (which essentially means we
> are done, no more locking with that ticket).
>
> The simplest solution is probably to just remove the call to
> ww_acquire_done() from ttm_eu_reserve_buffers().
>
> Christian.
>
> Am 07.05.19 um 13:45 schrieb Chunming Zhou:
> > heavy gpu job could occupy memory long time, which lead other user 
> fail to get memory.
> >
> > basically pick up Christian idea:
> >
> > 1. Reserve the BO in DC using a ww_mutex ticket (trivial).
> > 2. If we then run into this EBUSY condition in TTM check if the BO 
> we need memory for (or rather the ww_mutex of its reservation object) 
> has a ticket assigned.
> > 3. If we have a ticket we grab a reference to the first BO on the 
> LRU, drop the LRU lock and try to grab the reservation lock with the 
> ticket.
> > 4. If getting the reservation lock with the ticket succeeded we 
> check if the BO is still the first one on the LRU in question (the BO 
> could have moved).
> > 5. If the BO is still the first one on the LRU in question we try to 
> evict it as we would evict any other BO.
> > 6. If any of the "If's" above fail we just back off and return -EBUSY.
> >
> > v2: fix some minor check
> > v3: address Christian v2 comments.
> > v4: fix some missing
> > v5: handle first_bo unlock and bo_get/put
> > v6: abstract unified iterate function, and handle all possible 
> usecase not only pinned bo.
> > v7: pass request bo->resv to ttm_bo_evict_first
> >
> > Change-Id: I21423fb922f885465f13833c41df1e134364a8e7
> > Signed-off-by: Chunming Zhou <david1.zhou@amd.com>
> > ---
> >   drivers/gpu/drm/ttm/ttm_bo.c | 111 +++++++++++++++++++++++++++++------
> >   1 file changed, 94 insertions(+), 17 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
> > index 8502b3ed2d88..f5e6328e4a57 100644
> > --- a/drivers/gpu/drm/ttm/ttm_bo.c
> > +++ b/drivers/gpu/drm/ttm/ttm_bo.c
> > @@ -766,11 +766,13 @@ EXPORT_SYMBOL(ttm_bo_eviction_valuable);
> >    * b. Otherwise, trylock it.
> >    */
> >   static bool ttm_bo_evict_swapout_allowable(struct 
> ttm_buffer_object *bo,
> > -                     struct ttm_operation_ctx *ctx, bool *locked)
> > +                     struct ttm_operation_ctx *ctx, bool *locked, 
> bool *busy)
> >   {
> >        bool ret = false;
> >
> >        *locked = false;
> > +     if (busy)
> > +             *busy = false;
> >        if (bo->resv == ctx->resv) {
> > reservation_object_assert_held(bo->resv);
> >                if (ctx->flags & TTM_OPT_FLAG_ALLOW_RES_EVICT
> > @@ -779,35 +781,46 @@ static bool 
> ttm_bo_evict_swapout_allowable(struct ttm_buffer_object *bo,
> >        } else {
> >                *locked = reservation_object_trylock(bo->resv);
> >                ret = *locked;
> > +             if (!ret && busy)
> > +                     *busy = true;
> >        }
> >
> >        return ret;
> >   }
> >
> > -static int ttm_mem_evict_first(struct ttm_bo_device *bdev,
> > -                            uint32_t mem_type,
> > -                            const struct ttm_place *place,
> > -                            struct ttm_operation_ctx *ctx)
> > +static struct ttm_buffer_object*
> > +ttm_mem_find_evitable_bo(struct ttm_bo_device *bdev,
> > +                      struct ttm_mem_type_manager *man,
> > +                      const struct ttm_place *place,
> > +                      struct ttm_operation_ctx *ctx,
> > +                      struct ttm_buffer_object **first_bo,
> > +                      bool *locked)
> >   {
> > -     struct ttm_bo_global *glob = bdev->glob;
> > -     struct ttm_mem_type_manager *man = &bdev->man[mem_type];
> >        struct ttm_buffer_object *bo = NULL;
> > -     bool locked = false;
> > -     unsigned i;
> > -     int ret;
> > +     int i;
> >
> > -     spin_lock(&glob->lru_lock);
> > +     if (first_bo)
> > +             *first_bo = NULL;
> >        for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
> >                list_for_each_entry(bo, &man->lru[i], lru) {
> > -                     if (!ttm_bo_evict_swapout_allowable(bo, ctx, 
> &locked))
> > +                     bool busy = false;
> > +
> > +                     if (!ttm_bo_evict_swapout_allowable(bo, ctx, 
> locked,
> > + &busy)) {
> > +                             if (first_bo && !(*first_bo) && busy) {
> > +                                     ttm_bo_get(bo);
> > +                                     *first_bo = bo;
> > +                             }
> >                                continue;
> > +                     }
> >
> >                        if (place && !bdev->driver->eviction_valuable(bo,
> >                                                                     place)) {
> > -                             if (locked)
> > +                             if (*locked)
> > reservation_object_unlock(bo->resv);
> >                                continue;
> >                        }
> > +
> >                        break;
> >                }
> >
> > @@ -818,9 +831,67 @@ static int ttm_mem_evict_first(struct 
> ttm_bo_device *bdev,
> >                bo = NULL;
> >        }
> >
> > +     return bo;
> > +}
> > +
> > +static int ttm_mem_evict_first(struct ttm_bo_device *bdev,
> > +                            uint32_t mem_type,
> > +                            const struct ttm_place *place,
> > +                            struct ttm_operation_ctx *ctx,
> > +                            struct reservation_object *request_resv)
> > +{
> > +     struct ttm_bo_global *glob = bdev->glob;
> > +     struct ttm_mem_type_manager *man = &bdev->man[mem_type];
> > +     struct ttm_buffer_object *bo = NULL, *first_bo = NULL;
> > +     bool locked = false;
> > +     int ret;
> > +
> > +     spin_lock(&glob->lru_lock);
> > +     bo = ttm_mem_find_evitable_bo(bdev, man, place, ctx, &first_bo,
> > +                                   &locked);
> >        if (!bo) {
> > +             struct ttm_operation_ctx busy_ctx;
> > +
> >                spin_unlock(&glob->lru_lock);
> > -             return -EBUSY;
> > +             /* check if other user occupy memory too long time */
> > +             if (!first_bo || !request_resv || 
> !request_resv->lock.ctx) {
> > +                     if (first_bo)
> > +                             ttm_bo_put(first_bo);
> > +                     return -EBUSY;
> > +             }
> > +             if (first_bo->resv == request_resv) {
> > +                     ttm_bo_put(first_bo);
> > +                     return -EBUSY;
> > +             }
> > +             if (ctx->interruptible)
> > +                     ret = 
> ww_mutex_lock_interruptible(&first_bo->resv->lock,
> > + request_resv->lock.ctx);
> > +             else
> > +                     ret = ww_mutex_lock(&first_bo->resv->lock, 
> request_resv->lock.ctx);
> > +             if (ret) {
> > +                     ttm_bo_put(first_bo);
> > +                     return ret;
> > +             }
> > +             spin_lock(&glob->lru_lock);
> > +             /* previous busy resv lock is held by above, idle now,
> > +              * so let them evictable.
> > +              */
> > +             busy_ctx.interruptible = ctx->interruptible;
> > +             busy_ctx.no_wait_gpu   = ctx->no_wait_gpu;
> > +             busy_ctx.resv          = first_bo->resv;
> > +             busy_ctx.flags         = TTM_OPT_FLAG_ALLOW_RES_EVICT;
> > +
> > +             bo = ttm_mem_find_evitable_bo(bdev, man, place, 
> &busy_ctx, NULL,
> > + &locked);
> > +             if (bo && (bo->resv == first_bo->resv))
> > +                     locked = true;
> > +             else if (bo)
> > + ww_mutex_unlock(&first_bo->resv->lock);
> > +             if (!bo) {
> > + spin_unlock(&glob->lru_lock);
> > +                     ttm_bo_put(first_bo);
> > +                     return -EBUSY;
> > +             }
> >        }
> >
> >        kref_get(&bo->list_kref);
> > @@ -829,11 +900,15 @@ static int ttm_mem_evict_first(struct 
> ttm_bo_device *bdev,
> >                ret = ttm_bo_cleanup_refs(bo, ctx->interruptible,
> > ctx->no_wait_gpu, locked);
> >                kref_put(&bo->list_kref, ttm_bo_release_list);
> > +             if (first_bo)
> > +                     ttm_bo_put(first_bo);
> >                return ret;
> >        }
> >
> >        ttm_bo_del_from_lru(bo);
> >        spin_unlock(&glob->lru_lock);
> > +     if (first_bo)
> > +             ttm_bo_put(first_bo);
> >
> >        ret = ttm_bo_evict(bo, ctx);
> >        if (locked) {
> > @@ -907,7 +982,7 @@ static int ttm_bo_mem_force_space(struct 
> ttm_buffer_object *bo,
> >                        return ret;
> >                if (mem->mm_node)
> >                        break;
> > -             ret = ttm_mem_evict_first(bdev, mem_type, place, ctx);
> > +             ret = ttm_mem_evict_first(bdev, mem_type, place, ctx, 
> bo->resv);
> >                if (unlikely(ret != 0))
> >                        return ret;
> >        } while (1);
> > @@ -1413,7 +1488,8 @@ static int ttm_bo_force_list_clean(struct 
> ttm_bo_device *bdev,
> >        for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
> >                while (!list_empty(&man->lru[i])) {
> > spin_unlock(&glob->lru_lock);
> > -                     ret = ttm_mem_evict_first(bdev, mem_type, 
> NULL, &ctx);
> > +                     ret = ttm_mem_evict_first(bdev, mem_type, 
> NULL, &ctx,
> > +                                               NULL);
> >                        if (ret)
> >                                return ret;
> > spin_lock(&glob->lru_lock);
> > @@ -1784,7 +1860,8 @@ int ttm_bo_swapout(struct ttm_bo_global *glob, 
> struct ttm_operation_ctx *ctx)
> >        spin_lock(&glob->lru_lock);
> >        for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
> >                list_for_each_entry(bo, &glob->swap_lru[i], swap) {
> > -                     if (ttm_bo_evict_swapout_allowable(bo, ctx, 
> &locked)) {
> > +                     if (ttm_bo_evict_swapout_allowable(bo, ctx, 
> &locked,
> > + NULL)) {
> >                                ret = 0;
> >                                break;
> >                        }
>
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html;
      charset=windows-1252">
  </head>
  <body text="#000000" bgcolor="#FFFFFF">
    <div class="moz-cite-prefix">Oh, I know where this is coming from.<br>
      <br>
      The problem is that we remove the BOs from the LRU during CS and
      so we can't wait for the CS to finish up.<br>
      <br>
      Already working on this problem for Marek's similar issue,<br>
      Christian.<br>
      <br>
      Am 09.05.19 um 16:46 schrieb Zhou, David(ChunMing):<br>
    </div>
    <blockquote type="cite"
cite="mid:-yd30ko-7yy2hg-rmre4orxyza7-xndome2qdx81-wtzk8a-eccw2rc52fs2-grqgt7bajdlk-5lgjxo-xu3otx-5m9i78-2xa184-z2lana96yogmoisk45t18dyy9462b5f86c1cg5hlpw-xorlqm-lev8gs.1557413178321@email.android.com">
      <meta http-equiv="Content-Type" content="text/html;
        charset=windows-1252">
      <meta name="Generator" content="Microsoft Exchange Server">
      <!-- converted from text -->
      <style><!-- .EmailQuote { margin-left: 1pt; padding-left: 4pt; border-left: #800000 2px solid; } --></style>
      <div>I know that before, it will issue warning only when debug
        option is enabled. Removing that is ok to me.<br>
        I only help Prike draft your idea, and Prike is trying this
        patch on his side. The latest feedback he gave me is first_bo is
        always null, code doesn't run into busy path, which is very
        confusing me, and he said  he is debugging  that.<br>
        <br>
        -David<br>
        <br>
        <br>
        -------- Original Message --------<br>
        Subject: Re: [PATCH 1/2] drm/ttm: fix busy memory to fail other
        user v7<br>
        From: "Koenig, Christian" <br>
        To: "Zhou, David(ChunMing)" ,"Liang, Prike"
        ,<a class="moz-txt-link-abbreviated" href="mailto:dri-devel@lists.freedesktop.org">dri-devel@lists.freedesktop.org</a><br>
        CC: <br>
        <br>
      </div>
      <font size="2"><span style="font-size:11pt;">
          <div class="PlainText">I've foudn one more problem with this.<br>
            <br>
            With lockdep enabled I get a warning because
            ttm_eu_reserve_buffers() <br>
            has called ww_acquire_done() on the ticket (which
            essentially means we <br>
            are done, no more locking with that ticket).<br>
            <br>
            The simplest solution is probably to just remove the call to
            <br>
            ww_acquire_done() from ttm_eu_reserve_buffers().<br>
            <br>
            Christian.<br>
            <br>
            Am 07.05.19 um 13:45 schrieb Chunming Zhou:<br>
            &gt; heavy gpu job could occupy memory long time, which lead
            other user fail to get memory.<br>
            &gt;<br>
            &gt; basically pick up Christian idea:<br>
            &gt;<br>
            &gt; 1. Reserve the BO in DC using a ww_mutex ticket
            (trivial).<br>
            &gt; 2. If we then run into this EBUSY condition in TTM
            check if the BO we need memory for (or rather the ww_mutex
            of its reservation object) has a ticket assigned.<br>
            &gt; 3. If we have a ticket we grab a reference to the first
            BO on the LRU, drop the LRU lock and try to grab the
            reservation lock with the ticket.<br>
            &gt; 4. If getting the reservation lock with the ticket
            succeeded we check if the BO is still the first one on the
            LRU in question (the BO could have moved).<br>
            &gt; 5. If the BO is still the first one on the LRU in
            question we try to evict it as we would evict any other BO.<br>
            &gt; 6. If any of the "If's" above fail we just back off and
            return -EBUSY.<br>
            &gt;<br>
            &gt; v2: fix some minor check<br>
            &gt; v3: address Christian v2 comments.<br>
            &gt; v4: fix some missing<br>
            &gt; v5: handle first_bo unlock and bo_get/put<br>
            &gt; v6: abstract unified iterate function, and handle all
            possible usecase not only pinned bo.<br>
            &gt; v7: pass request bo-&gt;resv to ttm_bo_evict_first<br>
            &gt;<br>
            &gt; Change-Id: I21423fb922f885465f13833c41df1e134364a8e7<br>
            &gt; Signed-off-by: Chunming Zhou
            <a class="moz-txt-link-rfc2396E" href="mailto:david1.zhou@amd.com">&lt;david1.zhou@amd.com&gt;</a><br>
            &gt; ---<br>
            &gt;   drivers/gpu/drm/ttm/ttm_bo.c | 111
            +++++++++++++++++++++++++++++------<br>
            &gt;   1 file changed, 94 insertions(+), 17 deletions(-)<br>
            &gt;<br>
            &gt; diff --git a/drivers/gpu/drm/ttm/ttm_bo.c
            b/drivers/gpu/drm/ttm/ttm_bo.c<br>
            &gt; index 8502b3ed2d88..f5e6328e4a57 100644<br>
            &gt; --- a/drivers/gpu/drm/ttm/ttm_bo.c<br>
            &gt; +++ b/drivers/gpu/drm/ttm/ttm_bo.c<br>
            &gt; @@ -766,11 +766,13 @@
            EXPORT_SYMBOL(ttm_bo_eviction_valuable);<br>
            &gt;    * b. Otherwise, trylock it.<br>
            &gt;    */<br>
            &gt;   static bool ttm_bo_evict_swapout_allowable(struct
            ttm_buffer_object *bo,<br>
            &gt; -                     struct ttm_operation_ctx *ctx,
            bool *locked)<br>
            &gt; +                     struct ttm_operation_ctx *ctx,
            bool *locked, bool *busy)<br>
            &gt;   {<br>
            &gt;        bool ret = false;<br>
            &gt;   <br>
            &gt;        *locked = false;<br>
            &gt; +     if (busy)<br>
            &gt; +             *busy = false;<br>
            &gt;        if (bo-&gt;resv == ctx-&gt;resv) {<br>
            &gt;               
            reservation_object_assert_held(bo-&gt;resv);<br>
            &gt;                if (ctx-&gt;flags &amp;
            TTM_OPT_FLAG_ALLOW_RES_EVICT<br>
            &gt; @@ -779,35 +781,46 @@ static bool
            ttm_bo_evict_swapout_allowable(struct ttm_buffer_object *bo,<br>
            &gt;        } else {<br>
            &gt;                *locked =
            reservation_object_trylock(bo-&gt;resv);<br>
            &gt;                ret = *locked;<br>
            &gt; +             if (!ret &amp;&amp; busy)<br>
            &gt; +                     *busy = true;<br>
            &gt;        }<br>
            &gt;   <br>
            &gt;        return ret;<br>
            &gt;   }<br>
            &gt;   <br>
            &gt; -static int ttm_mem_evict_first(struct ttm_bo_device
            *bdev,<br>
            &gt; -                            uint32_t mem_type,<br>
            &gt; -                            const struct ttm_place
            *place,<br>
            &gt; -                            struct ttm_operation_ctx
            *ctx)<br>
            &gt; +static struct ttm_buffer_object*<br>
            &gt; +ttm_mem_find_evitable_bo(struct ttm_bo_device *bdev,<br>
            &gt; +                      struct ttm_mem_type_manager
            *man,<br>
            &gt; +                      const struct ttm_place *place,<br>
            &gt; +                      struct ttm_operation_ctx *ctx,<br>
            &gt; +                      struct ttm_buffer_object
            **first_bo,<br>
            &gt; +                      bool *locked)<br>
            &gt;   {<br>
            &gt; -     struct ttm_bo_global *glob = bdev-&gt;glob;<br>
            &gt; -     struct ttm_mem_type_manager *man =
            &amp;bdev-&gt;man[mem_type];<br>
            &gt;        struct ttm_buffer_object *bo = NULL;<br>
            &gt; -     bool locked = false;<br>
            &gt; -     unsigned i;<br>
            &gt; -     int ret;<br>
            &gt; +     int i;<br>
            &gt;   <br>
            &gt; -     spin_lock(&amp;glob-&gt;lru_lock);<br>
            &gt; +     if (first_bo)<br>
            &gt; +             *first_bo = NULL;<br>
            &gt;        for (i = 0; i &lt; TTM_MAX_BO_PRIORITY; ++i) {<br>
            &gt;                list_for_each_entry(bo,
            &amp;man-&gt;lru[i], lru) {<br>
            &gt; -                     if
            (!ttm_bo_evict_swapout_allowable(bo, ctx, &amp;locked))<br>
            &gt; +                     bool busy = false;<br>
            &gt; +<br>
            &gt; +                     if
            (!ttm_bo_evict_swapout_allowable(bo, ctx, locked,<br>
            &gt;
            +                                                        
            &amp;busy)) {<br>
            &gt; +                             if (first_bo &amp;&amp;
            !(*first_bo) &amp;&amp; busy) {<br>
            &gt; +                                     ttm_bo_get(bo);<br>
            &gt; +                                     *first_bo = bo;<br>
            &gt; +                             }<br>
            &gt;                                continue;<br>
            &gt; +                     }<br>
            &gt;   <br>
            &gt;                        if (place &amp;&amp;
            !bdev-&gt;driver-&gt;eviction_valuable(bo,<br>
&gt;                                                                     
            place)) {<br>
            &gt; -                             if (locked)<br>
            &gt; +                             if (*locked)<br>
            &gt;                                       
            reservation_object_unlock(bo-&gt;resv);<br>
            &gt;                                continue;<br>
            &gt;                        }<br>
            &gt; +<br>
            &gt;                        break;<br>
            &gt;                }<br>
            &gt;   <br>
            &gt; @@ -818,9 +831,67 @@ static int
            ttm_mem_evict_first(struct ttm_bo_device *bdev,<br>
            &gt;                bo = NULL;<br>
            &gt;        }<br>
            &gt;   <br>
            &gt; +     return bo;<br>
            &gt; +}<br>
            &gt; +<br>
            &gt; +static int ttm_mem_evict_first(struct ttm_bo_device
            *bdev,<br>
            &gt; +                            uint32_t mem_type,<br>
            &gt; +                            const struct ttm_place
            *place,<br>
            &gt; +                            struct ttm_operation_ctx
            *ctx,<br>
            &gt; +                            struct reservation_object
            *request_resv)<br>
            &gt; +{<br>
            &gt; +     struct ttm_bo_global *glob = bdev-&gt;glob;<br>
            &gt; +     struct ttm_mem_type_manager *man =
            &amp;bdev-&gt;man[mem_type];<br>
            &gt; +     struct ttm_buffer_object *bo = NULL, *first_bo =
            NULL;<br>
            &gt; +     bool locked = false;<br>
            &gt; +     int ret;<br>
            &gt; +<br>
            &gt; +     spin_lock(&amp;glob-&gt;lru_lock);<br>
            &gt; +     bo = ttm_mem_find_evitable_bo(bdev, man, place,
            ctx, &amp;first_bo,<br>
            &gt; +                                   &amp;locked);<br>
            &gt;        if (!bo) {<br>
            &gt; +             struct ttm_operation_ctx busy_ctx;<br>
            &gt; +<br>
            &gt;                spin_unlock(&amp;glob-&gt;lru_lock);<br>
            &gt; -             return -EBUSY;<br>
            &gt; +             /* check if other user occupy memory too
            long time */<br>
            &gt; +             if (!first_bo || !request_resv ||
            !request_resv-&gt;lock.ctx) {<br>
            &gt; +                     if (first_bo)<br>
            &gt; +                             ttm_bo_put(first_bo);<br>
            &gt; +                     return -EBUSY;<br>
            &gt; +             }<br>
            &gt; +             if (first_bo-&gt;resv == request_resv) {<br>
            &gt; +                     ttm_bo_put(first_bo);<br>
            &gt; +                     return -EBUSY;<br>
            &gt; +             }<br>
            &gt; +             if (ctx-&gt;interruptible)<br>
            &gt; +                     ret =
            ww_mutex_lock_interruptible(&amp;first_bo-&gt;resv-&gt;lock,<br>
            &gt; +                                                      
            request_resv-&gt;lock.ctx);<br>
            &gt; +             else<br>
            &gt; +                     ret =
            ww_mutex_lock(&amp;first_bo-&gt;resv-&gt;lock,
            request_resv-&gt;lock.ctx);<br>
            &gt; +             if (ret) {<br>
            &gt; +                     ttm_bo_put(first_bo);<br>
            &gt; +                     return ret;<br>
            &gt; +             }<br>
            &gt; +             spin_lock(&amp;glob-&gt;lru_lock);<br>
            &gt; +             /* previous busy resv lock is held by
            above, idle now,<br>
            &gt; +              * so let them evictable.<br>
            &gt; +              */<br>
            &gt; +             busy_ctx.interruptible =
            ctx-&gt;interruptible;<br>
            &gt; +             busy_ctx.no_wait_gpu   =
            ctx-&gt;no_wait_gpu;<br>
            &gt; +             busy_ctx.resv          =
            first_bo-&gt;resv;<br>
            &gt; +             busy_ctx.flags         =
            TTM_OPT_FLAG_ALLOW_RES_EVICT;<br>
            &gt; +<br>
            &gt; +             bo = ttm_mem_find_evitable_bo(bdev, man,
            place, &amp;busy_ctx, NULL,<br>
            &gt; +                                          
            &amp;locked);<br>
            &gt; +             if (bo &amp;&amp; (bo-&gt;resv ==
            first_bo-&gt;resv))<br>
            &gt; +                     locked = true;<br>
            &gt; +             else if (bo)<br>
            &gt; +                    
            ww_mutex_unlock(&amp;first_bo-&gt;resv-&gt;lock);<br>
            &gt; +             if (!bo) {<br>
            &gt; +                    
            spin_unlock(&amp;glob-&gt;lru_lock);<br>
            &gt; +                     ttm_bo_put(first_bo);<br>
            &gt; +                     return -EBUSY;<br>
            &gt; +             }<br>
            &gt;        }<br>
            &gt;   <br>
            &gt;        kref_get(&amp;bo-&gt;list_kref);<br>
            &gt; @@ -829,11 +900,15 @@ static int
            ttm_mem_evict_first(struct ttm_bo_device *bdev,<br>
            &gt;                ret = ttm_bo_cleanup_refs(bo,
            ctx-&gt;interruptible,<br>
            &gt;                                         
            ctx-&gt;no_wait_gpu, locked);<br>
            &gt;                kref_put(&amp;bo-&gt;list_kref,
            ttm_bo_release_list);<br>
            &gt; +             if (first_bo)<br>
            &gt; +                     ttm_bo_put(first_bo);<br>
            &gt;                return ret;<br>
            &gt;        }<br>
            &gt;   <br>
            &gt;        ttm_bo_del_from_lru(bo);<br>
            &gt;        spin_unlock(&amp;glob-&gt;lru_lock);<br>
            &gt; +     if (first_bo)<br>
            &gt; +             ttm_bo_put(first_bo);<br>
            &gt;   <br>
            &gt;        ret = ttm_bo_evict(bo, ctx);<br>
            &gt;        if (locked) {<br>
            &gt; @@ -907,7 +982,7 @@ static int
            ttm_bo_mem_force_space(struct ttm_buffer_object *bo,<br>
            &gt;                        return ret;<br>
            &gt;                if (mem-&gt;mm_node)<br>
            &gt;                        break;<br>
            &gt; -             ret = ttm_mem_evict_first(bdev, mem_type,
            place, ctx);<br>
            &gt; +             ret = ttm_mem_evict_first(bdev, mem_type,
            place, ctx, bo-&gt;resv);<br>
            &gt;                if (unlikely(ret != 0))<br>
            &gt;                        return ret;<br>
            &gt;        } while (1);<br>
            &gt; @@ -1413,7 +1488,8 @@ static int
            ttm_bo_force_list_clean(struct ttm_bo_device *bdev,<br>
            &gt;        for (i = 0; i &lt; TTM_MAX_BO_PRIORITY; ++i) {<br>
            &gt;                while (!list_empty(&amp;man-&gt;lru[i]))
            {<br>
            &gt;                       
            spin_unlock(&amp;glob-&gt;lru_lock);<br>
            &gt; -                     ret = ttm_mem_evict_first(bdev,
            mem_type, NULL, &amp;ctx);<br>
            &gt; +                     ret = ttm_mem_evict_first(bdev,
            mem_type, NULL, &amp;ctx,<br>
            &gt; +                                               NULL);<br>
            &gt;                        if (ret)<br>
            &gt;                                return ret;<br>
            &gt;                       
            spin_lock(&amp;glob-&gt;lru_lock);<br>
            &gt; @@ -1784,7 +1860,8 @@ int ttm_bo_swapout(struct
            ttm_bo_global *glob, struct ttm_operation_ctx *ctx)<br>
            &gt;        spin_lock(&amp;glob-&gt;lru_lock);<br>
            &gt;        for (i = 0; i &lt; TTM_MAX_BO_PRIORITY; ++i) {<br>
            &gt;                list_for_each_entry(bo,
            &amp;glob-&gt;swap_lru[i], swap) {<br>
            &gt; -                     if
            (ttm_bo_evict_swapout_allowable(bo, ctx, &amp;locked)) {<br>
            &gt; +                     if
            (ttm_bo_evict_swapout_allowable(bo, ctx, &amp;locked,<br>
            &gt;
            +                                                       
            NULL)) {<br>
            &gt;                                ret = 0;<br>
            &gt;                                break;<br>
            &gt;                        }<br>
            <br>
          </div>
        </span></font>
      <br>
      <fieldset class="mimeAttachmentHeader"></fieldset>
      <pre class="moz-quote-pre" wrap="">_______________________________________________
dri-devel mailing list
<a class="moz-txt-link-abbreviated" href="mailto:dri-devel@lists.freedesktop.org">dri-devel@lists.freedesktop.org</a>
<a class="moz-txt-link-freetext" href="https://lists.freedesktop.org/mailman/listinfo/dri-devel">https://lists.freedesktop.org/mailman/listinfo/dri-devel</a></pre>
    </blockquote>
    <br>
  </body>
</html>
Liang, Prike May 10, 2019, 5:39 a.m. UTC | #5
Thanks Christian proposal and David draft the solution implement .

The pinned Bos failed not observed from prepare_fb ,but Abaqus job can't  finished through the whole night .
Regards the NULL fist BO EBUSY error case , which  comes from amdgpu_cs_bo_validate perform period as the below call stack show . Now the NULL first BO debug error message popup out endlessly during Abaqus running ,that's seems the function @amdgpu_cs_validate run into invoked amdgpu_cs_bo_validate dead loop.

lxj ttm_mem_evict_first first_bo=          (null),request_resv=ffff929d47b33218,request_resv->lock.ctx=ffff929b8d6bfbd8
[ 2703.091731] CPU: 3 PID: 10739 Comm: standard Kdump: loaded Tainted: G           OE  ------------   3.10.0-957.el7.x86_64 #1
[ 2703.103046] Hardware name: MSI MS-7984/Z170 KRAIT GAMING (MS-7984), BIOS B.80 05/11/2016
[ 2703.111181] Call Trace:
[ 2703.113745]  [<ffffffff81961dc1>] dump_stack+0x19/0x1b
[ 2703.118979]  [<ffffffffc055cd19>] ttm_mem_evict_first+0x3a9/0x400 [amdttm]
[ 2703.125974]  [<ffffffffc055d05b>] amdttm_bo_mem_space+0x2eb/0x4a0 [amdttm]
[ 2703.132967]  [<ffffffffc055d6e4>] amdttm_bo_validate+0xc4/0x140 [amdttm]
[ 2703.139827]  [<ffffffffc059fed5>] amdgpu_cs_bo_validate+0xa5/0x220 [amdgpu]
[ 2703.146879]  [<ffffffffc05a0097>] amdgpu_cs_validate+0x47/0x2e0 [amdgpu]
[ 2703.153776]  [<ffffffffc05b41a2>] ? amdgpu_vm_del_from_lru_notify+0x12/0x80 [amdgpu]
[ 2703.161707]  [<ffffffffc05a0050>] ? amdgpu_cs_bo_validate+0x220/0x220 [amdgpu]
[ 2703.169018]  [<ffffffffc05b4452>] amdgpu_vm_validate_pt_bos+0x92/0x140 [amdgpu]
[ 2703.176512]  [<ffffffffc05a23e5>] amdgpu_cs_ioctl+0x18a5/0x1d40 [amdgpu]
[ 2703.183372]  [<ffffffffc05a0b40>] ? amdgpu_cs_find_mapping+0x120/0x120 [amdgpu]
[ 2703.190815]  [<ffffffffc042df2c>] drm_ioctl_kernel+0x6c/0xb0 [drm]
[ 2703.197109]  [<ffffffffc042e647>] drm_ioctl+0x1e7/0x420 [drm]
[ 2703.202995]  [<ffffffffc05a0b40>] ? amdgpu_cs_find_mapping+0x120/0x120 [amdgpu]
[ 2703.210471]  [<ffffffffc058004b>] amdgpu_drm_ioctl+0x4b/0x80 [amdgpu]
[ 2703.217019]  [<ffffffff81456210>] do_vfs_ioctl+0x3a0/0x5a0
[ 2703.222596]  [<ffffffff8196744a>] ? __schedule+0x13a/0x890
[ 2703.228172]  [<ffffffff814564b1>] SyS_ioctl+0xa1/0xc0
[ 2703.233308]  [<ffffffff81974ddb>] system_call_fastpath+0x22/0x27

Thanks,
Prike
From: Christian König <ckoenig.leichtzumerken@gmail.com>
Sent: Thursday, May 09, 2019 10:59 PM
To: Zhou, David(ChunMing) <David1.Zhou@amd.com>; Koenig, Christian <Christian.Koenig@amd.com>; Liang, Prike <Prike.Liang@amd.com>; dri-devel@lists.freedesktop.org
Subject: Re: [PATCH 1/2] drm/ttm: fix busy memory to fail other user v7

[CAUTION: External Email]
Oh, I know where this is coming from.

The problem is that we remove the BOs from the LRU during CS and so we can't wait for the CS to finish up.

Already working on this problem for Marek's similar issue,
Christian.

Am 09.05.19 um 16:46 schrieb Zhou, David(ChunMing):
I know that before, it will issue warning only when debug option is enabled. Removing that is ok to me.
I only help Prike draft your idea, and Prike is trying this patch on his side. The latest feedback he gave me is first_bo is always null, code doesn't run into busy path, which is very confusing me, and he said  he is debugging  that.

-David


-------- Original Message --------
Subject: Re: [PATCH 1/2] drm/ttm: fix busy memory to fail other user v7
From: "Koenig, Christian"
To: "Zhou, David(ChunMing)" ,"Liang, Prike" ,dri-devel@lists.freedesktop.org<mailto:dri-devel@lists.freedesktop.org>
CC:
I've foudn one more problem with this.

With lockdep enabled I get a warning because ttm_eu_reserve_buffers()
has called ww_acquire_done() on the ticket (which essentially means we
are done, no more locking with that ticket).

The simplest solution is probably to just remove the call to
ww_acquire_done() from ttm_eu_reserve_buffers().

Christian.

Am 07.05.19 um 13:45 schrieb Chunming Zhou:
> heavy gpu job could occupy memory long time, which lead other user fail to get memory.
>
> basically pick up Christian idea:
>
> 1. Reserve the BO in DC using a ww_mutex ticket (trivial).
> 2. If we then run into this EBUSY condition in TTM check if the BO we need memory for (or rather the ww_mutex of its reservation object) has a ticket assigned.
> 3. If we have a ticket we grab a reference to the first BO on the LRU, drop the LRU lock and try to grab the reservation lock with the ticket.
> 4. If getting the reservation lock with the ticket succeeded we check if the BO is still the first one on the LRU in question (the BO could have moved).
> 5. If the BO is still the first one on the LRU in question we try to evict it as we would evict any other BO.
> 6. If any of the "If's" above fail we just back off and return -EBUSY.
>
> v2: fix some minor check
> v3: address Christian v2 comments.
> v4: fix some missing
> v5: handle first_bo unlock and bo_get/put
> v6: abstract unified iterate function, and handle all possible usecase not only pinned bo.
> v7: pass request bo->resv to ttm_bo_evict_first
>
> Change-Id: I21423fb922f885465f13833c41df1e134364a8e7
> Signed-off-by: Chunming Zhou <david1.zhou@amd.com><mailto:david1.zhou@amd.com>
> ---
>   drivers/gpu/drm/ttm/ttm_bo.c | 111 +++++++++++++++++++++++++++++------
>   1 file changed, 94 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
> index 8502b3ed2d88..f5e6328e4a57 100644
> --- a/drivers/gpu/drm/ttm/ttm_bo.c
> +++ b/drivers/gpu/drm/ttm/ttm_bo.c
> @@ -766,11 +766,13 @@ EXPORT_SYMBOL(ttm_bo_eviction_valuable);
>    * b. Otherwise, trylock it.
>    */
>   static bool ttm_bo_evict_swapout_allowable(struct ttm_buffer_object *bo,
> -                     struct ttm_operation_ctx *ctx, bool *locked)
> +                     struct ttm_operation_ctx *ctx, bool *locked, bool *busy)
>   {
>        bool ret = false;
>
>        *locked = false;
> +     if (busy)
> +             *busy = false;
>        if (bo->resv == ctx->resv) {
>                reservation_object_assert_held(bo->resv);
>                if (ctx->flags & TTM_OPT_FLAG_ALLOW_RES_EVICT
> @@ -779,35 +781,46 @@ static bool ttm_bo_evict_swapout_allowable(struct ttm_buffer_object *bo,
>        } else {
>                *locked = reservation_object_trylock(bo->resv);
>                ret = *locked;
> +             if (!ret && busy)
> +                     *busy = true;
>        }
>
>        return ret;
>   }
>
> -static int ttm_mem_evict_first(struct ttm_bo_device *bdev,
> -                            uint32_t mem_type,
> -                            const struct ttm_place *place,
> -                            struct ttm_operation_ctx *ctx)
> +static struct ttm_buffer_object*
> +ttm_mem_find_evitable_bo(struct ttm_bo_device *bdev,
> +                      struct ttm_mem_type_manager *man,
> +                      const struct ttm_place *place,
> +                      struct ttm_operation_ctx *ctx,
> +                      struct ttm_buffer_object **first_bo,
> +                      bool *locked)
>   {
> -     struct ttm_bo_global *glob = bdev->glob;
> -     struct ttm_mem_type_manager *man = &bdev->man[mem_type];
>        struct ttm_buffer_object *bo = NULL;
> -     bool locked = false;
> -     unsigned i;
> -     int ret;
> +     int i;
>
> -     spin_lock(&glob->lru_lock);
> +     if (first_bo)
> +             *first_bo = NULL;
>        for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
>                list_for_each_entry(bo, &man->lru[i], lru) {
> -                     if (!ttm_bo_evict_swapout_allowable(bo, ctx, &locked))
> +                     bool busy = false;
> +
> +                     if (!ttm_bo_evict_swapout_allowable(bo, ctx, locked,
> +                                                         &busy)) {
> +                             if (first_bo && !(*first_bo) && busy) {
> +                                     ttm_bo_get(bo);
> +                                     *first_bo = bo;
> +                             }
>                                continue;
> +                     }
>
>                        if (place && !bdev->driver->eviction_valuable(bo,
>                                                                      place)) {
> -                             if (locked)
> +                             if (*locked)
>                                        reservation_object_unlock(bo->resv);
>                                continue;
>                        }
> +
>                        break;
>                }
>
> @@ -818,9 +831,67 @@ static int ttm_mem_evict_first(struct ttm_bo_device *bdev,
>                bo = NULL;
>        }
>
> +     return bo;
> +}
> +
> +static int ttm_mem_evict_first(struct ttm_bo_device *bdev,
> +                            uint32_t mem_type,
> +                            const struct ttm_place *place,
> +                            struct ttm_operation_ctx *ctx,
> +                            struct reservation_object *request_resv)
> +{
> +     struct ttm_bo_global *glob = bdev->glob;
> +     struct ttm_mem_type_manager *man = &bdev->man[mem_type];
> +     struct ttm_buffer_object *bo = NULL, *first_bo = NULL;
> +     bool locked = false;
> +     int ret;
> +
> +     spin_lock(&glob->lru_lock);
> +     bo = ttm_mem_find_evitable_bo(bdev, man, place, ctx, &first_bo,
> +                                   &locked);
>        if (!bo) {
> +             struct ttm_operation_ctx busy_ctx;
> +
>                spin_unlock(&glob->lru_lock);
> -             return -EBUSY;
> +             /* check if other user occupy memory too long time */
> +             if (!first_bo || !request_resv || !request_resv->lock.ctx) {
> +                     if (first_bo)
> +                             ttm_bo_put(first_bo);
> +                     return -EBUSY;
> +             }
> +             if (first_bo->resv == request_resv) {
> +                     ttm_bo_put(first_bo);
> +                     return -EBUSY;
> +             }
> +             if (ctx->interruptible)
> +                     ret = ww_mutex_lock_interruptible(&first_bo->resv->lock,
> +                                                       request_resv->lock.ctx);
> +             else
> +                     ret = ww_mutex_lock(&first_bo->resv->lock, request_resv->lock.ctx);
> +             if (ret) {
> +                     ttm_bo_put(first_bo);
> +                     return ret;
> +             }
> +             spin_lock(&glob->lru_lock);
> +             /* previous busy resv lock is held by above, idle now,
> +              * so let them evictable.
> +              */
> +             busy_ctx.interruptible = ctx->interruptible;
> +             busy_ctx.no_wait_gpu   = ctx->no_wait_gpu;
> +             busy_ctx.resv          = first_bo->resv;
> +             busy_ctx.flags         = TTM_OPT_FLAG_ALLOW_RES_EVICT;
> +
> +             bo = ttm_mem_find_evitable_bo(bdev, man, place, &busy_ctx, NULL,
> +                                           &locked);
> +             if (bo && (bo->resv == first_bo->resv))
> +                     locked = true;
> +             else if (bo)
> +                     ww_mutex_unlock(&first_bo->resv->lock);
> +             if (!bo) {
> +                     spin_unlock(&glob->lru_lock);
> +                     ttm_bo_put(first_bo);
> +                     return -EBUSY;
> +             }
>        }
>
>        kref_get(&bo->list_kref);
> @@ -829,11 +900,15 @@ static int ttm_mem_evict_first(struct ttm_bo_device *bdev,
>                ret = ttm_bo_cleanup_refs(bo, ctx->interruptible,
>                                          ctx->no_wait_gpu, locked);
>                kref_put(&bo->list_kref, ttm_bo_release_list);
> +             if (first_bo)
> +                     ttm_bo_put(first_bo);
>                return ret;
>        }
>
>        ttm_bo_del_from_lru(bo);
>        spin_unlock(&glob->lru_lock);
> +     if (first_bo)
> +             ttm_bo_put(first_bo);
>
>        ret = ttm_bo_evict(bo, ctx);
>        if (locked) {
> @@ -907,7 +982,7 @@ static int ttm_bo_mem_force_space(struct ttm_buffer_object *bo,
>                        return ret;
>                if (mem->mm_node)
>                        break;
> -             ret = ttm_mem_evict_first(bdev, mem_type, place, ctx);
> +             ret = ttm_mem_evict_first(bdev, mem_type, place, ctx, bo->resv);
>                if (unlikely(ret != 0))
>                        return ret;
>        } while (1);
> @@ -1413,7 +1488,8 @@ static int ttm_bo_force_list_clean(struct ttm_bo_device *bdev,
>        for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
>                while (!list_empty(&man->lru[i])) {
>                        spin_unlock(&glob->lru_lock);
> -                     ret = ttm_mem_evict_first(bdev, mem_type, NULL, &ctx);
> +                     ret = ttm_mem_evict_first(bdev, mem_type, NULL, &ctx,
> +                                               NULL);
>                        if (ret)
>                                return ret;
>                        spin_lock(&glob->lru_lock);
> @@ -1784,7 +1860,8 @@ int ttm_bo_swapout(struct ttm_bo_global *glob, struct ttm_operation_ctx *ctx)
>        spin_lock(&glob->lru_lock);
>        for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
>                list_for_each_entry(bo, &glob->swap_lru[i], swap) {
> -                     if (ttm_bo_evict_swapout_allowable(bo, ctx, &locked)) {
> +                     if (ttm_bo_evict_swapout_allowable(bo, ctx, &locked,
> +                                                        NULL)) {
>                                ret = 0;
>                                break;
>                        }
Liang, Prike May 13, 2019, 3 a.m. UTC | #6
I have verified this solution again and the Abaqus case finished after about 27 hours running .
But not sure whether retrieve the first busy BO and then retry evict the LRU BOs result in
Abaqus poor performance .

Anyway this can fix the age-old issue .Does any other concern before push the following patch to the drm-next branch .

drm/amd/display: use ttm_eu_reserve_buffers instead of amdgpu_bo_reserve
drm/ttm: fix busy memory to fail other user v7

Thanks,
Prike
From: Liang, Prike
Sent: Friday, May 10, 2019 1:40 PM
To: Koenig, Christian <Christian.Koenig@amd.com>; Zhou, David(ChunMing) <David1.Zhou@amd.com>; dri-devel@lists.freedesktop.org
Subject: RE: [PATCH 1/2] drm/ttm: fix busy memory to fail other user v7

Thanks Christian proposal and David draft the solution implement .

The pinned Bos failed not observed from prepare_fb ,but Abaqus job can't  finished through the whole night .
Regards the NULL fist BO EBUSY error case , which  comes from amdgpu_cs_bo_validate perform period as the below call stack show . Now the NULL first BO debug error message popup out endlessly during Abaqus running ,that's seems the function @amdgpu_cs_validate run into invoked amdgpu_cs_bo_validate dead loop.

lxj ttm_mem_evict_first first_bo=          (null),request_resv=ffff929d47b33218,request_resv->lock.ctx=ffff929b8d6bfbd8
[ 2703.091731] CPU: 3 PID: 10739 Comm: standard Kdump: loaded Tainted: G           OE  ------------   3.10.0-957.el7.x86_64 #1
[ 2703.103046] Hardware name: MSI MS-7984/Z170 KRAIT GAMING (MS-7984), BIOS B.80 05/11/2016
[ 2703.111181] Call Trace:
[ 2703.113745]  [<ffffffff81961dc1>] dump_stack+0x19/0x1b
[ 2703.118979]  [<ffffffffc055cd19>] ttm_mem_evict_first+0x3a9/0x400 [amdttm]
[ 2703.125974]  [<ffffffffc055d05b>] amdttm_bo_mem_space+0x2eb/0x4a0 [amdttm]
[ 2703.132967]  [<ffffffffc055d6e4>] amdttm_bo_validate+0xc4/0x140 [amdttm]
[ 2703.139827]  [<ffffffffc059fed5>] amdgpu_cs_bo_validate+0xa5/0x220 [amdgpu]
[ 2703.146879]  [<ffffffffc05a0097>] amdgpu_cs_validate+0x47/0x2e0 [amdgpu]
[ 2703.153776]  [<ffffffffc05b41a2>] ? amdgpu_vm_del_from_lru_notify+0x12/0x80 [amdgpu]
[ 2703.161707]  [<ffffffffc05a0050>] ? amdgpu_cs_bo_validate+0x220/0x220 [amdgpu]
[ 2703.169018]  [<ffffffffc05b4452>] amdgpu_vm_validate_pt_bos+0x92/0x140 [amdgpu]
[ 2703.176512]  [<ffffffffc05a23e5>] amdgpu_cs_ioctl+0x18a5/0x1d40 [amdgpu]
[ 2703.183372]  [<ffffffffc05a0b40>] ? amdgpu_cs_find_mapping+0x120/0x120 [amdgpu]
[ 2703.190815]  [<ffffffffc042df2c>] drm_ioctl_kernel+0x6c/0xb0 [drm]
[ 2703.197109]  [<ffffffffc042e647>] drm_ioctl+0x1e7/0x420 [drm]
[ 2703.202995]  [<ffffffffc05a0b40>] ? amdgpu_cs_find_mapping+0x120/0x120 [amdgpu]
[ 2703.210471]  [<ffffffffc058004b>] amdgpu_drm_ioctl+0x4b/0x80 [amdgpu]
[ 2703.217019]  [<ffffffff81456210>] do_vfs_ioctl+0x3a0/0x5a0
[ 2703.222596]  [<ffffffff8196744a>] ? __schedule+0x13a/0x890
[ 2703.228172]  [<ffffffff814564b1>] SyS_ioctl+0xa1/0xc0
[ 2703.233308]  [<ffffffff81974ddb>] system_call_fastpath+0x22/0x27

Thanks,
Prike
From: Christian König <ckoenig.leichtzumerken@gmail.com<mailto:ckoenig.leichtzumerken@gmail.com>>
Sent: Thursday, May 09, 2019 10:59 PM
To: Zhou, David(ChunMing) <David1.Zhou@amd.com<mailto:David1.Zhou@amd.com>>; Koenig, Christian <Christian.Koenig@amd.com<mailto:Christian.Koenig@amd.com>>; Liang, Prike <Prike.Liang@amd.com<mailto:Prike.Liang@amd.com>>; dri-devel@lists.freedesktop.org<mailto:dri-devel@lists.freedesktop.org>
Subject: Re: [PATCH 1/2] drm/ttm: fix busy memory to fail other user v7

[CAUTION: External Email]
Oh, I know where this is coming from.

The problem is that we remove the BOs from the LRU during CS and so we can't wait for the CS to finish up.

Already working on this problem for Marek's similar issue,
Christian.

Am 09.05.19 um 16:46 schrieb Zhou, David(ChunMing):
I know that before, it will issue warning only when debug option is enabled. Removing that is ok to me.
I only help Prike draft your idea, and Prike is trying this patch on his side. The latest feedback he gave me is first_bo is always null, code doesn't run into busy path, which is very confusing me, and he said  he is debugging  that.

-David


-------- Original Message --------
Subject: Re: [PATCH 1/2] drm/ttm: fix busy memory to fail other user v7
From: "Koenig, Christian"
To: "Zhou, David(ChunMing)" ,"Liang, Prike" ,dri-devel@lists.freedesktop.org<mailto:dri-devel@lists.freedesktop.org>
CC:
I've foudn one more problem with this.

With lockdep enabled I get a warning because ttm_eu_reserve_buffers()
has called ww_acquire_done() on the ticket (which essentially means we
are done, no more locking with that ticket).

The simplest solution is probably to just remove the call to
ww_acquire_done() from ttm_eu_reserve_buffers().

Christian.

Am 07.05.19 um 13:45 schrieb Chunming Zhou:
> heavy gpu job could occupy memory long time, which lead other user fail to get memory.
>
> basically pick up Christian idea:
>
> 1. Reserve the BO in DC using a ww_mutex ticket (trivial).
> 2. If we then run into this EBUSY condition in TTM check if the BO we need memory for (or rather the ww_mutex of its reservation object) has a ticket assigned.
> 3. If we have a ticket we grab a reference to the first BO on the LRU, drop the LRU lock and try to grab the reservation lock with the ticket.
> 4. If getting the reservation lock with the ticket succeeded we check if the BO is still the first one on the LRU in question (the BO could have moved).
> 5. If the BO is still the first one on the LRU in question we try to evict it as we would evict any other BO.
> 6. If any of the "If's" above fail we just back off and return -EBUSY.
>
> v2: fix some minor check
> v3: address Christian v2 comments.
> v4: fix some missing
> v5: handle first_bo unlock and bo_get/put
> v6: abstract unified iterate function, and handle all possible usecase not only pinned bo.
> v7: pass request bo->resv to ttm_bo_evict_first
>
> Change-Id: I21423fb922f885465f13833c41df1e134364a8e7
> Signed-off-by: Chunming Zhou <david1.zhou@amd.com><mailto:david1.zhou@amd.com>
> ---
>   drivers/gpu/drm/ttm/ttm_bo.c | 111 +++++++++++++++++++++++++++++------
>   1 file changed, 94 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
> index 8502b3ed2d88..f5e6328e4a57 100644
> --- a/drivers/gpu/drm/ttm/ttm_bo.c
> +++ b/drivers/gpu/drm/ttm/ttm_bo.c
> @@ -766,11 +766,13 @@ EXPORT_SYMBOL(ttm_bo_eviction_valuable);
>    * b. Otherwise, trylock it.
>    */
>   static bool ttm_bo_evict_swapout_allowable(struct ttm_buffer_object *bo,
> -                     struct ttm_operation_ctx *ctx, bool *locked)
> +                     struct ttm_operation_ctx *ctx, bool *locked, bool *busy)
>   {
>        bool ret = false;
>
>        *locked = false;
> +     if (busy)
> +             *busy = false;
>        if (bo->resv == ctx->resv) {
>                reservation_object_assert_held(bo->resv);
>                if (ctx->flags & TTM_OPT_FLAG_ALLOW_RES_EVICT
> @@ -779,35 +781,46 @@ static bool ttm_bo_evict_swapout_allowable(struct ttm_buffer_object *bo,
>        } else {
>                *locked = reservation_object_trylock(bo->resv);
>                ret = *locked;
> +             if (!ret && busy)
> +                     *busy = true;
>        }
>
>        return ret;
>   }
>
> -static int ttm_mem_evict_first(struct ttm_bo_device *bdev,
> -                            uint32_t mem_type,
> -                            const struct ttm_place *place,
> -                            struct ttm_operation_ctx *ctx)
> +static struct ttm_buffer_object*
> +ttm_mem_find_evitable_bo(struct ttm_bo_device *bdev,
> +                      struct ttm_mem_type_manager *man,
> +                      const struct ttm_place *place,
> +                      struct ttm_operation_ctx *ctx,
> +                      struct ttm_buffer_object **first_bo,
> +                      bool *locked)
>   {
> -     struct ttm_bo_global *glob = bdev->glob;
> -     struct ttm_mem_type_manager *man = &bdev->man[mem_type];
>        struct ttm_buffer_object *bo = NULL;
> -     bool locked = false;
> -     unsigned i;
> -     int ret;
> +     int i;
>
> -     spin_lock(&glob->lru_lock);
> +     if (first_bo)
> +             *first_bo = NULL;
>        for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
>                list_for_each_entry(bo, &man->lru[i], lru) {
> -                     if (!ttm_bo_evict_swapout_allowable(bo, ctx, &locked))
> +                     bool busy = false;
> +
> +                     if (!ttm_bo_evict_swapout_allowable(bo, ctx, locked,
> +                                                         &busy)) {
> +                             if (first_bo && !(*first_bo) && busy) {
> +                                     ttm_bo_get(bo);
> +                                     *first_bo = bo;
> +                             }
>                                continue;
> +                     }
>
>                        if (place && !bdev->driver->eviction_valuable(bo,
>                                                                      place)) {
> -                             if (locked)
> +                             if (*locked)
>                                        reservation_object_unlock(bo->resv);
>                                continue;
>                        }
> +
>                        break;
>                }
>
> @@ -818,9 +831,67 @@ static int ttm_mem_evict_first(struct ttm_bo_device *bdev,
>                bo = NULL;
>        }
>
> +     return bo;
> +}
> +
> +static int ttm_mem_evict_first(struct ttm_bo_device *bdev,
> +                            uint32_t mem_type,
> +                            const struct ttm_place *place,
> +                            struct ttm_operation_ctx *ctx,
> +                            struct reservation_object *request_resv)
> +{
> +     struct ttm_bo_global *glob = bdev->glob;
> +     struct ttm_mem_type_manager *man = &bdev->man[mem_type];
> +     struct ttm_buffer_object *bo = NULL, *first_bo = NULL;
> +     bool locked = false;
> +     int ret;
> +
> +     spin_lock(&glob->lru_lock);
> +     bo = ttm_mem_find_evitable_bo(bdev, man, place, ctx, &first_bo,
> +                                   &locked);
>        if (!bo) {
> +             struct ttm_operation_ctx busy_ctx;
> +
>                spin_unlock(&glob->lru_lock);
> -             return -EBUSY;
> +             /* check if other user occupy memory too long time */
> +             if (!first_bo || !request_resv || !request_resv->lock.ctx) {
> +                     if (first_bo)
> +                             ttm_bo_put(first_bo);
> +                     return -EBUSY;
> +             }
> +             if (first_bo->resv == request_resv) {
> +                     ttm_bo_put(first_bo);
> +                     return -EBUSY;
> +             }
> +             if (ctx->interruptible)
> +                     ret = ww_mutex_lock_interruptible(&first_bo->resv->lock,
> +                                                       request_resv->lock.ctx);
> +             else
> +                     ret = ww_mutex_lock(&first_bo->resv->lock, request_resv->lock.ctx);
> +             if (ret) {
> +                     ttm_bo_put(first_bo);
> +                     return ret;
> +             }
> +             spin_lock(&glob->lru_lock);
> +             /* previous busy resv lock is held by above, idle now,
> +              * so let them evictable.
> +              */
> +             busy_ctx.interruptible = ctx->interruptible;
> +             busy_ctx.no_wait_gpu   = ctx->no_wait_gpu;
> +             busy_ctx.resv          = first_bo->resv;
> +             busy_ctx.flags         = TTM_OPT_FLAG_ALLOW_RES_EVICT;
> +
> +             bo = ttm_mem_find_evitable_bo(bdev, man, place, &busy_ctx, NULL,
> +                                           &locked);
> +             if (bo && (bo->resv == first_bo->resv))
> +                     locked = true;
> +             else if (bo)
> +                     ww_mutex_unlock(&first_bo->resv->lock);
> +             if (!bo) {
> +                     spin_unlock(&glob->lru_lock);
> +                     ttm_bo_put(first_bo);
> +                     return -EBUSY;
> +             }
>        }
>
>        kref_get(&bo->list_kref);
> @@ -829,11 +900,15 @@ static int ttm_mem_evict_first(struct ttm_bo_device *bdev,
>                ret = ttm_bo_cleanup_refs(bo, ctx->interruptible,
>                                          ctx->no_wait_gpu, locked);
>                kref_put(&bo->list_kref, ttm_bo_release_list);
> +             if (first_bo)
> +                     ttm_bo_put(first_bo);
>                return ret;
>        }
>
>        ttm_bo_del_from_lru(bo);
>        spin_unlock(&glob->lru_lock);
> +     if (first_bo)
> +             ttm_bo_put(first_bo);
>
>        ret = ttm_bo_evict(bo, ctx);
>        if (locked) {
> @@ -907,7 +982,7 @@ static int ttm_bo_mem_force_space(struct ttm_buffer_object *bo,
>                        return ret;
>                if (mem->mm_node)
>                        break;
> -             ret = ttm_mem_evict_first(bdev, mem_type, place, ctx);
> +             ret = ttm_mem_evict_first(bdev, mem_type, place, ctx, bo->resv);
>                if (unlikely(ret != 0))
>                        return ret;
>        } while (1);
> @@ -1413,7 +1488,8 @@ static int ttm_bo_force_list_clean(struct ttm_bo_device *bdev,
>        for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
>                while (!list_empty(&man->lru[i])) {
>                        spin_unlock(&glob->lru_lock);
> -                     ret = ttm_mem_evict_first(bdev, mem_type, NULL, &ctx);
> +                     ret = ttm_mem_evict_first(bdev, mem_type, NULL, &ctx,
> +                                               NULL);
>                        if (ret)
>                                return ret;
>                        spin_lock(&glob->lru_lock);
> @@ -1784,7 +1860,8 @@ int ttm_bo_swapout(struct ttm_bo_global *glob, struct ttm_operation_ctx *ctx)
>        spin_lock(&glob->lru_lock);
>        for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
>                list_for_each_entry(bo, &glob->swap_lru[i], swap) {
> -                     if (ttm_bo_evict_swapout_allowable(bo, ctx, &locked)) {
> +                     if (ttm_bo_evict_swapout_allowable(bo, ctx, &locked,
> +                                                        NULL)) {
>                                ret = 0;
>                                break;
>                        }
diff mbox series

Patch

diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index 8502b3ed2d88..f5e6328e4a57 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -766,11 +766,13 @@  EXPORT_SYMBOL(ttm_bo_eviction_valuable);
  * b. Otherwise, trylock it.
  */
 static bool ttm_bo_evict_swapout_allowable(struct ttm_buffer_object *bo,
-			struct ttm_operation_ctx *ctx, bool *locked)
+			struct ttm_operation_ctx *ctx, bool *locked, bool *busy)
 {
 	bool ret = false;
 
 	*locked = false;
+	if (busy)
+		*busy = false;
 	if (bo->resv == ctx->resv) {
 		reservation_object_assert_held(bo->resv);
 		if (ctx->flags & TTM_OPT_FLAG_ALLOW_RES_EVICT
@@ -779,35 +781,46 @@  static bool ttm_bo_evict_swapout_allowable(struct ttm_buffer_object *bo,
 	} else {
 		*locked = reservation_object_trylock(bo->resv);
 		ret = *locked;
+		if (!ret && busy)
+			*busy = true;
 	}
 
 	return ret;
 }
 
-static int ttm_mem_evict_first(struct ttm_bo_device *bdev,
-			       uint32_t mem_type,
-			       const struct ttm_place *place,
-			       struct ttm_operation_ctx *ctx)
+static struct ttm_buffer_object*
+ttm_mem_find_evitable_bo(struct ttm_bo_device *bdev,
+			 struct ttm_mem_type_manager *man,
+			 const struct ttm_place *place,
+			 struct ttm_operation_ctx *ctx,
+			 struct ttm_buffer_object **first_bo,
+			 bool *locked)
 {
-	struct ttm_bo_global *glob = bdev->glob;
-	struct ttm_mem_type_manager *man = &bdev->man[mem_type];
 	struct ttm_buffer_object *bo = NULL;
-	bool locked = false;
-	unsigned i;
-	int ret;
+	int i;
 
-	spin_lock(&glob->lru_lock);
+	if (first_bo)
+		*first_bo = NULL;
 	for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
 		list_for_each_entry(bo, &man->lru[i], lru) {
-			if (!ttm_bo_evict_swapout_allowable(bo, ctx, &locked))
+			bool busy = false;
+
+			if (!ttm_bo_evict_swapout_allowable(bo, ctx, locked,
+							    &busy)) {
+				if (first_bo && !(*first_bo) && busy) {
+					ttm_bo_get(bo);
+					*first_bo = bo;
+				}
 				continue;
+			}
 
 			if (place && !bdev->driver->eviction_valuable(bo,
 								      place)) {
-				if (locked)
+				if (*locked)
 					reservation_object_unlock(bo->resv);
 				continue;
 			}
+
 			break;
 		}
 
@@ -818,9 +831,67 @@  static int ttm_mem_evict_first(struct ttm_bo_device *bdev,
 		bo = NULL;
 	}
 
+	return bo;
+}
+
+static int ttm_mem_evict_first(struct ttm_bo_device *bdev,
+			       uint32_t mem_type,
+			       const struct ttm_place *place,
+			       struct ttm_operation_ctx *ctx,
+			       struct reservation_object *request_resv)
+{
+	struct ttm_bo_global *glob = bdev->glob;
+	struct ttm_mem_type_manager *man = &bdev->man[mem_type];
+	struct ttm_buffer_object *bo = NULL, *first_bo = NULL;
+	bool locked = false;
+	int ret;
+
+	spin_lock(&glob->lru_lock);
+	bo = ttm_mem_find_evitable_bo(bdev, man, place, ctx, &first_bo,
+				      &locked);
 	if (!bo) {
+		struct ttm_operation_ctx busy_ctx;
+
 		spin_unlock(&glob->lru_lock);
-		return -EBUSY;
+		/* check if other user occupy memory too long time */
+		if (!first_bo || !request_resv || !request_resv->lock.ctx) {
+			if (first_bo)
+				ttm_bo_put(first_bo);
+			return -EBUSY;
+		}
+		if (first_bo->resv == request_resv) {
+			ttm_bo_put(first_bo);
+			return -EBUSY;
+		}
+		if (ctx->interruptible)
+			ret = ww_mutex_lock_interruptible(&first_bo->resv->lock,
+							  request_resv->lock.ctx);
+		else
+			ret = ww_mutex_lock(&first_bo->resv->lock, request_resv->lock.ctx);
+		if (ret) {
+			ttm_bo_put(first_bo);
+			return ret;
+		}
+		spin_lock(&glob->lru_lock);
+		/* previous busy resv lock is held by above, idle now,
+		 * so let them evictable.
+		 */
+		busy_ctx.interruptible = ctx->interruptible;
+		busy_ctx.no_wait_gpu   = ctx->no_wait_gpu;
+		busy_ctx.resv	       = first_bo->resv;
+		busy_ctx.flags	       = TTM_OPT_FLAG_ALLOW_RES_EVICT;
+
+		bo = ttm_mem_find_evitable_bo(bdev, man, place, &busy_ctx, NULL,
+					      &locked);
+		if (bo && (bo->resv == first_bo->resv))
+			locked = true;
+		else if (bo)
+			ww_mutex_unlock(&first_bo->resv->lock);
+		if (!bo) {
+			spin_unlock(&glob->lru_lock);
+			ttm_bo_put(first_bo);
+			return -EBUSY;
+		}
 	}
 
 	kref_get(&bo->list_kref);
@@ -829,11 +900,15 @@  static int ttm_mem_evict_first(struct ttm_bo_device *bdev,
 		ret = ttm_bo_cleanup_refs(bo, ctx->interruptible,
 					  ctx->no_wait_gpu, locked);
 		kref_put(&bo->list_kref, ttm_bo_release_list);
+		if (first_bo)
+			ttm_bo_put(first_bo);
 		return ret;
 	}
 
 	ttm_bo_del_from_lru(bo);
 	spin_unlock(&glob->lru_lock);
+	if (first_bo)
+		ttm_bo_put(first_bo);
 
 	ret = ttm_bo_evict(bo, ctx);
 	if (locked) {
@@ -907,7 +982,7 @@  static int ttm_bo_mem_force_space(struct ttm_buffer_object *bo,
 			return ret;
 		if (mem->mm_node)
 			break;
-		ret = ttm_mem_evict_first(bdev, mem_type, place, ctx);
+		ret = ttm_mem_evict_first(bdev, mem_type, place, ctx, bo->resv);
 		if (unlikely(ret != 0))
 			return ret;
 	} while (1);
@@ -1413,7 +1488,8 @@  static int ttm_bo_force_list_clean(struct ttm_bo_device *bdev,
 	for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
 		while (!list_empty(&man->lru[i])) {
 			spin_unlock(&glob->lru_lock);
-			ret = ttm_mem_evict_first(bdev, mem_type, NULL, &ctx);
+			ret = ttm_mem_evict_first(bdev, mem_type, NULL, &ctx,
+						  NULL);
 			if (ret)
 				return ret;
 			spin_lock(&glob->lru_lock);
@@ -1784,7 +1860,8 @@  int ttm_bo_swapout(struct ttm_bo_global *glob, struct ttm_operation_ctx *ctx)
 	spin_lock(&glob->lru_lock);
 	for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
 		list_for_each_entry(bo, &glob->swap_lru[i], swap) {
-			if (ttm_bo_evict_swapout_allowable(bo, ctx, &locked)) {
+			if (ttm_bo_evict_swapout_allowable(bo, ctx, &locked,
+							   NULL)) {
 				ret = 0;
 				break;
 			}