Commit 9c51ba1d authored by Thomas Hellstrom's avatar Thomas Hellstrom Committed by Dave Airlie

drm/ttm: Fix potential ttm_mem_evict_first races.

1) The function was previously called with a potentially empty
LRU list which would have lead to an OOPS or servere corruption.
2) In rare cases, after reservation has succeeded, another process may
already have evicted it or even pinned it. We must revalidate the
buffer status after releasing the lru lock.
Signed-off-by: default avatarThomas Hellstrom <thellstrom@vmware.com>
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent aaa20736
...@@ -685,19 +685,45 @@ static int ttm_mem_evict_first(struct ttm_bo_device *bdev, ...@@ -685,19 +685,45 @@ static int ttm_mem_evict_first(struct ttm_bo_device *bdev,
struct ttm_buffer_object *bo; struct ttm_buffer_object *bo;
int ret, put_count = 0; int ret, put_count = 0;
retry:
spin_lock(&glob->lru_lock); spin_lock(&glob->lru_lock);
if (list_empty(&man->lru)) {
spin_unlock(&glob->lru_lock);
return -EBUSY;
}
bo = list_first_entry(&man->lru, struct ttm_buffer_object, lru); bo = list_first_entry(&man->lru, struct ttm_buffer_object, lru);
kref_get(&bo->list_kref); kref_get(&bo->list_kref);
ret = ttm_bo_reserve_locked(bo, interruptible, no_wait, false, 0);
if (likely(ret == 0)) ret = ttm_bo_reserve_locked(bo, false, true, false, 0);
put_count = ttm_bo_del_from_lru(bo);
if (unlikely(ret == -EBUSY)) {
spin_unlock(&glob->lru_lock); spin_unlock(&glob->lru_lock);
if (likely(!no_wait))
ret = ttm_bo_wait_unreserved(bo, interruptible);
kref_put(&bo->list_kref, ttm_bo_release_list);
/**
* We *need* to retry after releasing the lru lock.
*/
if (unlikely(ret != 0)) if (unlikely(ret != 0))
return ret; return ret;
goto retry;
}
put_count = ttm_bo_del_from_lru(bo);
spin_unlock(&glob->lru_lock);
BUG_ON(ret != 0);
while (put_count--) while (put_count--)
kref_put(&bo->list_kref, ttm_bo_ref_bug); kref_put(&bo->list_kref, ttm_bo_ref_bug);
ret = ttm_bo_evict(bo, interruptible, no_wait); ret = ttm_bo_evict(bo, interruptible, no_wait);
ttm_bo_unreserve(bo); ttm_bo_unreserve(bo);
kref_put(&bo->list_kref, ttm_bo_release_list); kref_put(&bo->list_kref, ttm_bo_release_list);
return ret; return ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment