dma-buf: add reservation_object_copy_fences (v2)
authorChristian König <christian.koenig@amd.com>
Thu, 10 Aug 2017 17:01:48 +0000 (13:01 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Mon, 14 Aug 2017 17:00:49 +0000 (13:00 -0400)
Allows us to copy all the fences in a reservation object to another one.

v2: handle NULL src_list

Signed-off-by: Christian König <christian.koenig@amd.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Link: https://patchwork.freedesktop.org/patch/msgid/1502384509-10465-2-git-send-email-alexander.deucher@amd.com
drivers/dma-buf/reservation.c
include/linux/reservation.h

index 87f8f57475007b836370f1c0b28172595d8d032c..d4881f91c43b668aa868daf43bef71f3784a5d8c 100644 (file)
@@ -261,6 +261,66 @@ void reservation_object_add_excl_fence(struct reservation_object *obj,
 }
 EXPORT_SYMBOL(reservation_object_add_excl_fence);
 
+/**
+* reservation_object_copy_fences - Copy all fences from src to dst.
+* @dst: the destination reservation object
+* @src: the source reservation object
+*
+* Copy all fences from src to dst. Both src->lock as well as dst-lock must be
+* held.
+*/
+int reservation_object_copy_fences(struct reservation_object *dst,
+                                  struct reservation_object *src)
+{
+       struct reservation_object_list *src_list, *dst_list;
+       struct dma_fence *old, *new;
+       size_t size;
+       unsigned i;
+
+       src_list = reservation_object_get_list(src);
+
+       if (src_list) {
+               size = offsetof(typeof(*src_list),
+                               shared[src_list->shared_count]);
+               dst_list = kmalloc(size, GFP_KERNEL);
+               if (!dst_list)
+                       return -ENOMEM;
+
+               dst_list->shared_count = src_list->shared_count;
+               dst_list->shared_max = src_list->shared_count;
+               for (i = 0; i < src_list->shared_count; ++i)
+                       dst_list->shared[i] =
+                               dma_fence_get(src_list->shared[i]);
+       } else {
+               dst_list = NULL;
+       }
+
+       kfree(dst->staged);
+       dst->staged = NULL;
+
+       src_list = reservation_object_get_list(dst);
+
+       old = reservation_object_get_excl(dst);
+       new = reservation_object_get_excl(src);
+
+       dma_fence_get(new);
+
+       preempt_disable();
+       write_seqcount_begin(&dst->seq);
+       /* write_seqcount_begin provides the necessary memory barrier */
+       RCU_INIT_POINTER(dst->fence_excl, new);
+       RCU_INIT_POINTER(dst->fence, dst_list);
+       write_seqcount_end(&dst->seq);
+       preempt_enable();
+
+       if (src_list)
+               kfree_rcu(src_list, rcu);
+       dma_fence_put(old);
+
+       return 0;
+}
+EXPORT_SYMBOL(reservation_object_copy_fences);
+
 /**
  * reservation_object_get_fences_rcu - Get an object's shared and exclusive
  * fences without update side lock held
index 156cfd330b6675c79780418e53cd0057410556ec..21fc84d82d41572db2216c4baf07b32c45044ff8 100644 (file)
@@ -254,6 +254,9 @@ int reservation_object_get_fences_rcu(struct reservation_object *obj,
                                      unsigned *pshared_count,
                                      struct dma_fence ***pshared);
 
+int reservation_object_copy_fences(struct reservation_object *dst,
+                                  struct reservation_object *src);
+
 long reservation_object_wait_timeout_rcu(struct reservation_object *obj,
                                         bool wait_all, bool intr,
                                         unsigned long timeout);