The atomic exchange operation in drm_syncobj_replace_fence is sufficient for the case where it races with itself. However, if you have a race between a replace_fence and dma_fence_get(syncobj->fence), you may end up with the entire replace_fence happening between the point in time where the one thread gets the syncobj->fence pointer and when it calls dma_fence_get() on it. If this happens, then the reference may be dropped before we get a chance to get a new one. The new helper uses dma_fence_get_rcu_safe to get rid of the race. This is also needed because it allows us to do a bit more than just get a reference in drm_syncobj_fence_get should we wish to do so. Signed-off-by: Jason Ekstrand <jason@xxxxxxxxxxxxxx> --- drivers/gpu/drm/drm_syncobj.c | 12 +++++++++--- include/drm/drm_syncobj.h | 6 +++++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c index 0412b0b..0190ec2 100644 --- a/drivers/gpu/drm/drm_syncobj.c +++ b/drivers/gpu/drm/drm_syncobj.c @@ -75,6 +75,12 @@ struct drm_syncobj *drm_syncobj_find(struct drm_file *file_private, } EXPORT_SYMBOL(drm_syncobj_find); +struct dma_fence *drm_syncobj_fence_get(struct drm_syncobj *syncobj) +{ + return dma_fence_get_rcu_safe(&syncobj->_fence); +} +EXPORT_SYMBOL(drm_syncobj_fence_get); + /** * drm_syncobj_replace_fence - replace fence in a sync object. * @syncobj: Sync object to replace fence in @@ -89,7 +95,7 @@ void drm_syncobj_replace_fence(struct drm_syncobj *syncobj, if (fence) dma_fence_get(fence); - old_fence = xchg(&syncobj->fence, fence); + old_fence = xchg(&syncobj->_fence, fence); dma_fence_put(old_fence); } @@ -105,7 +111,7 @@ int drm_syncobj_find_fence(struct drm_file *file_private, if (!syncobj) return -ENOENT; - *fence = dma_fence_get(syncobj->fence); + *fence = drm_syncobj_fence_get(syncobj); if (!*fence) { ret = -EINVAL; } @@ -125,7 +131,7 @@ void drm_syncobj_free(struct kref *kref) struct drm_syncobj *syncobj = container_of(kref, struct drm_syncobj, refcount); - dma_fence_put(syncobj->fence); + dma_fence_put(syncobj->_fence); kfree(syncobj); } EXPORT_SYMBOL(drm_syncobj_free); diff --git a/include/drm/drm_syncobj.h b/include/drm/drm_syncobj.h index 7d4ad77..c06a441 100644 --- a/include/drm/drm_syncobj.h +++ b/include/drm/drm_syncobj.h @@ -43,8 +43,11 @@ struct drm_syncobj { /** * @fence: * NULL or a pointer to the fence bound to this object. + * + * This pointer should not be accessed directly. Instead, use + * drm_syncobj_fence_get or drm_syncobj_replace_fence. */ - struct dma_fence *fence; + struct dma_fence *_fence; /** * @file: * a file backing for this syncobj. @@ -79,6 +82,7 @@ drm_syncobj_put(struct drm_syncobj *obj) struct drm_syncobj *drm_syncobj_find(struct drm_file *file_private, u32 handle); +struct dma_fence *drm_syncobj_fence_get(struct drm_syncobj *syncobj); void drm_syncobj_replace_fence(struct drm_syncobj *syncobj, struct dma_fence *fence); int drm_syncobj_find_fence(struct drm_file *file_private, -- 2.5.0.400.gff86faf _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel