[PATCH 1/3] drm/syncobj: protect timeline syncobjs
Lionel Landwerlin
lionel.g.landwerlin at intel.com
Mon Aug 26 09:04:46 UTC 2019
Binary/legacy signal operations on a syncobj work by replacing the
dma_fence held within the syncobj. Whe dealing with timeline
semaphores we would like to avoid this as this would effectivelly lead
to looser synchronization (by discarding the dma_fence_chain mechanism
waiting on all previous dma_fence to signal before signal itself).
This change adds a flags that can be used at creation of the syncobj
to mean that the syncobj will hold a timeline of dma_fence (using
dma_fence_chain). When flagged as such, the dma_fence held by the
syncobj should not be replaced but instead we should always adding to
the timeline.
Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin at intel.com>
---
drivers/gpu/drm/drm_syncobj.c | 30 +++++++++++++++++++++++++++++-
include/drm/drm_syncobj.h | 8 ++++++++
include/uapi/drm/drm.h | 1 +
3 files changed, 38 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c
index 72d083acd388..69d43c791a42 100644
--- a/drivers/gpu/drm/drm_syncobj.c
+++ b/drivers/gpu/drm/drm_syncobj.c
@@ -476,6 +476,8 @@ int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags,
if (flags & DRM_SYNCOBJ_CREATE_SIGNALED)
drm_syncobj_assign_null_handle(syncobj);
+ if (flags & DRM_SYNCOBJ_CREATE_TIMELINE)
+ syncobj->is_timeline = true;
if (fence)
drm_syncobj_replace_fence(syncobj, fence);
@@ -661,6 +663,10 @@ static int drm_syncobj_import_sync_file_fence(struct drm_file *file_private,
dma_fence_put(fence);
return -ENOENT;
}
+ if (syncobj->is_timeline) {
+ dma_fence_put(fence);
+ return -EINVAL;
+ }
drm_syncobj_replace_fence(syncobj, fence);
dma_fence_put(fence);
@@ -749,7 +755,13 @@ drm_syncobj_create_ioctl(struct drm_device *dev, void *data,
return -EOPNOTSUPP;
/* no valid flags yet */
- if (args->flags & ~DRM_SYNCOBJ_CREATE_SIGNALED)
+ if (args->flags & ~(DRM_SYNCOBJ_CREATE_SIGNALED |
+ DRM_SYNCOBJ_CREATE_TIMELINE))
+ return -EINVAL;
+
+ /* Creating a signaled timeline makes no sense. */
+ if ((args->flags & DRM_SYNCOBJ_CREATE_SIGNALED) &&
+ (args->flags & DRM_SYNCOBJ_CREATE_TIMELINE))
return -EINVAL;
return drm_syncobj_create_as_handle(file_private,
@@ -862,6 +874,10 @@ drm_syncobj_transfer_to_binary(struct drm_file *file_private,
binary_syncobj = drm_syncobj_find(file_private, args->dst_handle);
if (!binary_syncobj)
return -ENOENT;
+ if (binary_syncobj->is_timeline) {
+ ret = -EINVAL;
+ goto err;
+ }
ret = drm_syncobj_find_fence(file_private, args->src_handle,
args->src_point, args->flags, &fence);
if (ret)
@@ -1137,6 +1153,7 @@ static int drm_syncobj_array_wait(struct drm_device *dev,
static int drm_syncobj_array_find(struct drm_file *file_private,
void __user *user_handles,
uint32_t count_handles,
+ bool no_timeline,
struct drm_syncobj ***syncobjs_out)
{
uint32_t i, *handles;
@@ -1165,6 +1182,10 @@ static int drm_syncobj_array_find(struct drm_file *file_private,
ret = -ENOENT;
goto err_put_syncobjs;
}
+ if (no_timeline && syncobjs[i]->is_timeline) {
+ ret = -EINVAL;
+ goto err_put_syncobjs;
+ }
}
kfree(handles);
@@ -1211,6 +1232,7 @@ drm_syncobj_wait_ioctl(struct drm_device *dev, void *data,
ret = drm_syncobj_array_find(file_private,
u64_to_user_ptr(args->handles),
args->count_handles,
+ false,
&syncobjs);
if (ret < 0)
return ret;
@@ -1245,6 +1267,7 @@ drm_syncobj_timeline_wait_ioctl(struct drm_device *dev, void *data,
ret = drm_syncobj_array_find(file_private,
u64_to_user_ptr(args->handles),
args->count_handles,
+ false,
&syncobjs);
if (ret < 0)
return ret;
@@ -1279,6 +1302,7 @@ drm_syncobj_reset_ioctl(struct drm_device *dev, void *data,
ret = drm_syncobj_array_find(file_private,
u64_to_user_ptr(args->handles),
args->count_handles,
+ false,
&syncobjs);
if (ret < 0)
return ret;
@@ -1314,6 +1338,7 @@ drm_syncobj_signal_ioctl(struct drm_device *dev, void *data,
ret = drm_syncobj_array_find(file_private,
u64_to_user_ptr(args->handles),
args->count_handles,
+ true,
&syncobjs);
if (ret < 0)
return ret;
@@ -1349,6 +1374,7 @@ drm_syncobj_timeline_signal_ioctl(struct drm_device *dev, void *data,
ret = drm_syncobj_array_find(file_private,
u64_to_user_ptr(args->handles),
args->count_handles,
+ false,
&syncobjs);
if (ret < 0)
return ret;
@@ -1420,6 +1446,7 @@ int drm_syncobj_query_ioctl(struct drm_device *dev, void *data,
ret = drm_syncobj_array_find(file_private,
u64_to_user_ptr(args->handles),
args->count_handles,
+ false,
&syncobjs);
if (ret < 0)
return ret;
@@ -1484,6 +1511,7 @@ int drm_syncobj_binary_ioctl(struct drm_device *dev, void *data,
ret = drm_syncobj_array_find(file_private,
u64_to_user_ptr(args->handles),
args->count_handles,
+ false,
&syncobjs);
if (ret < 0)
return ret;
diff --git a/include/drm/drm_syncobj.h b/include/drm/drm_syncobj.h
index aa76cb3f9107..f96a95fbe025 100644
--- a/include/drm/drm_syncobj.h
+++ b/include/drm/drm_syncobj.h
@@ -70,6 +70,14 @@ struct drm_syncobj {
* seqno will be put into the syncobj.
*/
atomic64_t binary_payload;
+ /**
+ * @is_timeline: Whether the syncobj holds a timeline.
+ *
+ * Holding a timeline adds some restriction to prevent userspace from
+ * accidentally "losing" the timeline. This could happen for example
+ * by replacing &fence.
+ */
+ bool is_timeline;
};
void drm_syncobj_free(struct kref *kref);
diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h
index 78a0a413b788..b3c46b2993be 100644
--- a/include/uapi/drm/drm.h
+++ b/include/uapi/drm/drm.h
@@ -719,6 +719,7 @@ struct drm_prime_handle {
struct drm_syncobj_create {
__u32 handle;
#define DRM_SYNCOBJ_CREATE_SIGNALED (1 << 0)
+#define DRM_SYNCOBJ_CREATE_TIMELINE (1 << 1)
__u32 flags;
};
--
2.23.0
More information about the dri-devel
mailing list