drm/sched: Fix drm_sched_fence_free() so it can be passed an uninitialized fence
drm_sched_job_cleanup() will pass an uninitialized fence to
drm_sched_fence_free(), which will cause to_drm_sched_fence() to return
a NULL fence object, causing a NULL pointer deref when this NULL object
is passed to kmem_cache_free().
Let's create a new drm_sched_fence_free() function that takes a
drm_sched_fence pointer and suffix the old function with _rcu. While at
it, complain if drm_sched_fence_free() is passed an initialized fence
or if drm_sched_fence_free_rcu() is passed an uninitialized fence.
Fixes: dbe48d030b
("drm/sched: Split drm_sched_job_init")
Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: https://patchwork.freedesktop.org/patch/msgid/20210903120554.444101-1-boris.brezillon@collabora.com
This commit is contained in:
Родитель
5bd785a814
Коммит
d4c16733e7
|
@ -69,18 +69,27 @@ static const char *drm_sched_fence_get_timeline_name(struct dma_fence *f)
|
||||||
return (const char *)fence->sched->name;
|
return (const char *)fence->sched->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static void drm_sched_fence_free_rcu(struct rcu_head *rcu)
|
||||||
* drm_sched_fence_free - free up the fence memory
|
|
||||||
*
|
|
||||||
* @rcu: RCU callback head
|
|
||||||
*
|
|
||||||
* Free up the fence memory after the RCU grace period.
|
|
||||||
*/
|
|
||||||
void drm_sched_fence_free(struct rcu_head *rcu)
|
|
||||||
{
|
{
|
||||||
struct dma_fence *f = container_of(rcu, struct dma_fence, rcu);
|
struct dma_fence *f = container_of(rcu, struct dma_fence, rcu);
|
||||||
struct drm_sched_fence *fence = to_drm_sched_fence(f);
|
struct drm_sched_fence *fence = to_drm_sched_fence(f);
|
||||||
|
|
||||||
|
if (!WARN_ON_ONCE(!fence))
|
||||||
|
kmem_cache_free(sched_fence_slab, fence);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* drm_sched_fence_free - free up an uninitialized fence
|
||||||
|
*
|
||||||
|
* @fence: fence to free
|
||||||
|
*
|
||||||
|
* Free up the fence memory. Should only be used if drm_sched_fence_init()
|
||||||
|
* has not been called yet.
|
||||||
|
*/
|
||||||
|
void drm_sched_fence_free(struct drm_sched_fence *fence)
|
||||||
|
{
|
||||||
|
/* This function should not be called if the fence has been initialized. */
|
||||||
|
if (!WARN_ON_ONCE(fence->sched))
|
||||||
kmem_cache_free(sched_fence_slab, fence);
|
kmem_cache_free(sched_fence_slab, fence);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,7 +106,7 @@ static void drm_sched_fence_release_scheduled(struct dma_fence *f)
|
||||||
struct drm_sched_fence *fence = to_drm_sched_fence(f);
|
struct drm_sched_fence *fence = to_drm_sched_fence(f);
|
||||||
|
|
||||||
dma_fence_put(fence->parent);
|
dma_fence_put(fence->parent);
|
||||||
call_rcu(&fence->finished.rcu, drm_sched_fence_free);
|
call_rcu(&fence->finished.rcu, drm_sched_fence_free_rcu);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -750,7 +750,7 @@ void drm_sched_job_cleanup(struct drm_sched_job *job)
|
||||||
dma_fence_put(&job->s_fence->finished);
|
dma_fence_put(&job->s_fence->finished);
|
||||||
} else {
|
} else {
|
||||||
/* aborted job before committing to run it */
|
/* aborted job before committing to run it */
|
||||||
drm_sched_fence_free(&job->s_fence->finished.rcu);
|
drm_sched_fence_free(job->s_fence);
|
||||||
}
|
}
|
||||||
|
|
||||||
job->s_fence = NULL;
|
job->s_fence = NULL;
|
||||||
|
|
|
@ -509,7 +509,7 @@ struct drm_sched_fence *drm_sched_fence_alloc(
|
||||||
struct drm_sched_entity *s_entity, void *owner);
|
struct drm_sched_entity *s_entity, void *owner);
|
||||||
void drm_sched_fence_init(struct drm_sched_fence *fence,
|
void drm_sched_fence_init(struct drm_sched_fence *fence,
|
||||||
struct drm_sched_entity *entity);
|
struct drm_sched_entity *entity);
|
||||||
void drm_sched_fence_free(struct rcu_head *rcu);
|
void drm_sched_fence_free(struct drm_sched_fence *fence);
|
||||||
|
|
||||||
void drm_sched_fence_scheduled(struct drm_sched_fence *fence);
|
void drm_sched_fence_scheduled(struct drm_sched_fence *fence);
|
||||||
void drm_sched_fence_finished(struct drm_sched_fence *fence);
|
void drm_sched_fence_finished(struct drm_sched_fence *fence);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче