[PATCH 1/4] sync_file: add a mutex to protect fence and callback members. (v3)
Chris Wilson
chris at chris-wilson.co.uk
Mon Mar 20 08:16:36 UTC 2017
On Mon, Mar 20, 2017 at 05:03:04PM +1000, Dave Airlie wrote:
> From: Dave Airlie <airlied at redhat.com>
>
> This patch allows the underlying fence in a sync_file to be changed
> or set to NULL. This isn't currently required but for Vulkan
> semaphores we need to be able to swap and reset the fence.
>
> In order to faciliate this, it uses rcu to protect the fence,
> along with a new mutex. The mutex also protects the callback.
> It also checks for NULL when retrieving the rcu protected
> fence in case it has been reset.
>
> v1.1: fix the locking (Julia Lawall).
> v2: use rcu try one
> v3: fix poll to use proper rcu, fixup merge/fill ioctls
> to not crash on NULL fence cases.
>
> Signed-off-by: Dave Airlie <airlied at redhat.com>
> ---
> @@ -80,7 +87,9 @@ struct sync_file *sync_file_create(struct dma_fence *fence)
> if (!sync_file)
> return NULL;
>
> - sync_file->fence = dma_fence_get(fence);
> + dma_fence_get(fence);
> +
> + RCU_INIT_POINTER(sync_file->fence, fence);
>
> snprintf(sync_file->name, sizeof(sync_file->name), "%s-%s%llu-%d",
> fence->ops->get_driver_name(fence),
> @@ -124,13 +133,26 @@ struct dma_fence *sync_file_get_fence(int fd)
> if (!sync_file)
> return NULL;
>
> - fence = dma_fence_get(sync_file->fence);
> + if (!rcu_access_pointer(sync_file->fence))
> + return NULL;
Missed fput.
> +
> + rcu_read_lock();
> + fence = dma_fence_get_rcu_safe(&sync_file->fence);
> + rcu_read_unlock();
> +
> fput(sync_file->file);
>
> return fence;
> }
> EXPORT_SYMBOL(sync_file_get_fence);
>
> @@ -204,10 +234,16 @@ static struct sync_file *sync_file_merge(const char *name, struct sync_file *a,
> if (!sync_file)
> return NULL;
>
> + mutex_lock(&a->lock);
> + mutex_lock(&b->lock);
This allows userspace to trigger lockdep (just merge the same pair of
sync_files again in opposite order). if (b < a) swap(a, b); ?
> a_fences = get_fences(a, &a_num_fences);
> b_fences = get_fences(b, &b_num_fences);
> - if (a_num_fences > INT_MAX - b_num_fences)
> - return NULL;
> + if (!a_num_fences || !b_num_fences)
> + goto unlock;
> +
> + if (a_num_fences > INT_MAX - b_num_fences) {
> + goto unlock;
> + }
>
> num_fences = a_num_fences + b_num_fences;
>
> @@ -281,10 +323,15 @@ static void sync_file_free(struct kref *kref)
> {
> struct sync_file *sync_file = container_of(kref, struct sync_file,
> kref);
> + struct dma_fence *fence;
> +
Somewhere, here?, it would be useful to add a comment that the rcu
delayed free is provided by fput.
> + fence = rcu_dereference_protected(sync_file->fence, 1);
> + if (fence) {
> + if (test_bit(POLL_ENABLED, &fence->flags))
> + dma_fence_remove_callback(fence, &sync_file->cb);
> + dma_fence_put(fence);
> + }
>
> - if (test_bit(POLL_ENABLED, &sync_file->fence->flags))
> - dma_fence_remove_callback(sync_file->fence, &sync_file->cb);
> - dma_fence_put(sync_file->fence);
> kfree(sync_file);
> }
>
> @@ -299,16 +346,25 @@ static int sync_file_release(struct inode *inode, struct file *file)
> static unsigned int sync_file_poll(struct file *file, poll_table *wait)
> {
> struct sync_file *sync_file = file->private_data;
> + unsigned int ret_val = 0;
> + struct dma_fence *fence;
>
> poll_wait(file, &sync_file->wq, wait);
>
> - if (!test_and_set_bit(POLL_ENABLED, &sync_file->fence->flags)) {
> - if (dma_fence_add_callback(sync_file->fence, &sync_file->cb,
> - fence_check_cb_func) < 0)
> - wake_up_all(&sync_file->wq);
> + mutex_lock(&sync_file->lock);
> +
> + fence = sync_file_get_fence_locked(sync_file);
Why do you need the locked version here and not just the rcu variant?
> + if (fence) {
> + if (!test_and_set_bit(POLL_ENABLED, &fence->flags)) {
> + if (dma_fence_add_callback(fence, &sync_file->cb,
> + fence_check_cb_func) < 0)
> + wake_up_all(&sync_file->wq);
> + }
> + ret_val = dma_fence_is_signaled(fence) ? POLLIN : 0;
> }
> + mutex_unlock(&sync_file->lock);
So an empty sync_file is incomplete and blocks forever? Why? It's the
opposite behaviour to e.g. reservation_object so a quick explanation of
how that is used by VkSemaphore will cement the differences.
-Chris
--
Chris Wilson, Intel Open Source Technology Centre
More information about the amd-gfx
mailing list