From: Gustavo Padovan <gustavo.pado...@collabora.co.uk>

Create sync_file->fence to abstract the type of fence we are using for
each sync_file. If only one fence is present we use a normal struct fence
but if there is more fences to be added to the sync_file a fence_array
is created.

This behaviour is transparent all sync_file functions, but
sync_file_set_fence() which sets the fence in the sync_file_merge(). It
is this functions that decides to use a fence or fence_array based on
num_fences.

This change cleans up sync_file a bit. We don't need to have sync_file_cb
array anymore. Instead, as we always have  one fence, only one fence
callback is registered per sync_file.

Signed-off-by: Gustavo Padovan <gustavo.padovan at collabora.co.uk>
---
 drivers/dma-buf/sync_file.c          | 129 +++++++++++++++++++++++++----------
 drivers/staging/android/sync_debug.c |   5 +-
 include/linux/sync_file.h            |  12 ++--
 3 files changed, 100 insertions(+), 46 deletions(-)

diff --git a/drivers/dma-buf/sync_file.c b/drivers/dma-buf/sync_file.c
index 9aaa608..5044ef2 100644
--- a/drivers/dma-buf/sync_file.c
+++ b/drivers/dma-buf/sync_file.c
@@ -25,14 +25,15 @@
 #include <linux/anon_inodes.h>
 #include <linux/sync_file.h>
 #include <uapi/linux/sync_file.h>
+#include <linux/fence-array.h>

 static const struct file_operations sync_file_fops;

-static struct sync_file *sync_file_alloc(int size)
+static struct sync_file *sync_file_alloc(void)
 {
        struct sync_file *sync_file;

-       sync_file = kzalloc(size, GFP_KERNEL);
+       sync_file = kzalloc(sizeof(*sync_file), GFP_KERNEL);
        if (!sync_file)
                return NULL;

@@ -45,6 +46,8 @@ static struct sync_file *sync_file_alloc(int size)

        init_waitqueue_head(&sync_file->wq);

+       INIT_LIST_HEAD(&sync_file->cb.node);
+
        return sync_file;

 err:
@@ -54,11 +57,9 @@ err:

 static void fence_check_cb_func(struct fence *f, struct fence_cb *cb)
 {
-       struct sync_file_cb *check;
        struct sync_file *sync_file;

-       check = container_of(cb, struct sync_file_cb, cb);
-       sync_file = check->sync_file;
+       sync_file = container_of(cb, struct sync_file, cb);

        if (atomic_dec_and_test(&sync_file->status))
                wake_up_all(&sync_file->wq);
@@ -76,21 +77,20 @@ struct sync_file *sync_file_create(struct fence *fence)
 {
        struct sync_file *sync_file;

-       sync_file = sync_file_alloc(offsetof(struct sync_file, cbs[1]));
+       sync_file = sync_file_alloc();
        if (!sync_file)
                return NULL;

+       sync_file->fence = fence;
        sync_file->num_fences = 1;
+
        atomic_set(&sync_file->status, 1);
        snprintf(sync_file->name, sizeof(sync_file->name), "%s-%s%llu-%d",
                 fence->ops->get_driver_name(fence),
                 fence->ops->get_timeline_name(fence), fence->context,
                 fence->seqno);

-       sync_file->cbs[0].fence = fence;
-       sync_file->cbs[0].sync_file = sync_file;
-       if (fence_add_callback(fence, &sync_file->cbs[0].cb,
-                              fence_check_cb_func))
+       if (fence_add_callback(fence, &sync_file->cb, fence_check_cb_func))
                atomic_dec(&sync_file->status);

        return sync_file;
@@ -121,14 +121,31 @@ err:
        return NULL;
 }

-static void sync_file_add_pt(struct sync_file *sync_file, int *i,
+static int sync_file_set_fence(struct sync_file *sync_file,
+                              struct fence **fences)
+{
+       struct fence_array *array;
+
+       if (sync_file->num_fences == 1) {
+               sync_file->fence = fences[0];
+       } else {
+               array = fence_array_create(sync_file->num_fences, fences,
+                                          fence_context_alloc(1), 1, false);
+               if (!array)
+                       return -ENOMEM;
+
+               sync_file->fence = &array->base;
+       }
+
+       return 0;
+}
+
+static void fences_add_fence(struct fence **fences, int *i,
                             struct fence *fence)
 {
-       sync_file->cbs[*i].fence = fence;
-       sync_file->cbs[*i].sync_file = sync_file;
+       fences[*i] = fence;

-       if (!fence_add_callback(fence, &sync_file->cbs[*i].cb,
-                               fence_check_cb_func)) {
+       if (!fence_is_signaled(fence)) {
                fence_get(fence);
                (*i)++;
        }
@@ -149,14 +166,31 @@ static struct sync_file *sync_file_merge(const char 
*name, struct sync_file *a,
 {
        int num_fences = a->num_fences + b->num_fences;
        struct sync_file *sync_file;
+       struct fence **fences, **a_fences, **b_fences;
        int i, i_a, i_b;
-       unsigned long size = offsetof(struct sync_file, cbs[num_fences]);

-       sync_file = sync_file_alloc(size);
+       sync_file = sync_file_alloc();
        if (!sync_file)
                return NULL;

-       atomic_set(&sync_file->status, num_fences);
+       fences = kcalloc(num_fences, sizeof(**fences), GFP_KERNEL);
+       if (!fences)
+               goto err;
+
+       atomic_set(&sync_file->status, 1);
+
+       a_fences = fence_get_fences(a->fence);
+       if (!a_fences) {
+               kfree(fences);
+               goto err;
+       }
+
+       b_fences = fence_get_fences(b->fence);
+       if (!b_fences) {
+               kfree(a_fences);
+               kfree(fences);
+               goto err;
+       }

        /*
         * Assume sync_file a and b are both ordered and have no
@@ -166,22 +200,22 @@ static struct sync_file *sync_file_merge(const char 
*name, struct sync_file *a,
         * and sync_file_create, this is a reasonable assumption.
         */
        for (i = i_a = i_b = 0; i_a < a->num_fences && i_b < b->num_fences; ) {
-               struct fence *pt_a = a->cbs[i_a].fence;
-               struct fence *pt_b = b->cbs[i_b].fence;
+               struct fence *pt_a = a_fences[i_a];
+               struct fence *pt_b = b_fences[i_b];

                if (pt_a->context < pt_b->context) {
-                       sync_file_add_pt(sync_file, &i, pt_a);
+                       fences_add_fence(fences, &i, pt_a);

                        i_a++;
                } else if (pt_a->context > pt_b->context) {
-                       sync_file_add_pt(sync_file, &i, pt_b);
+                       fences_add_fence(fences, &i, pt_b);

                        i_b++;
                } else {
                        if (pt_a->seqno - pt_b->seqno <= INT_MAX)
-                               sync_file_add_pt(sync_file, &i, pt_a);
+                               fences_add_fence(fences, &i, pt_a);
                        else
-                               sync_file_add_pt(sync_file, &i, pt_b);
+                               fences_add_fence(fences, &i, pt_b);

                        i_a++;
                        i_b++;
@@ -189,31 +223,49 @@ static struct sync_file *sync_file_merge(const char 
*name, struct sync_file *a,
        }

        for (; i_a < a->num_fences; i_a++)
-               sync_file_add_pt(sync_file, &i, a->cbs[i_a].fence);
+               fences_add_fence(fences, &i, a_fences[i_a]);

        for (; i_b < b->num_fences; i_b++)
-               sync_file_add_pt(sync_file, &i, b->cbs[i_b].fence);
+               fences_add_fence(fences, &i, b_fences[i_b]);

-       if (num_fences > i)
-               atomic_sub(num_fences - i, &sync_file->status);
+       if (num_fences > i) {
+               fences = krealloc(fences, i * sizeof(**fences),
+                                 GFP_KERNEL);
+               if (!fences)
+                       goto ab_err;
+       }
        sync_file->num_fences = i;

+       if (sync_file_set_fence(sync_file, fences) < 0) {
+               kfree(fences);
+               goto ab_err;
+       }
+
+       if (fence_add_callback(sync_file->fence, &sync_file->cb,
+                              fence_check_cb_func))
+               atomic_dec(&sync_file->status);
+
        strlcpy(sync_file->name, name, sizeof(sync_file->name));
        return sync_file;
+
+ab_err:
+       kfree(a_fences);
+       kfree(b_fences);
+
+err:
+       fput(sync_file->file);
+       return NULL;
+
 }

 static void sync_file_free(struct kref *kref)
 {
        struct sync_file *sync_file = container_of(kref, struct sync_file,
                                                     kref);
-       int i;
-
-       for (i = 0; i < sync_file->num_fences; ++i) {
-               fence_remove_callback(sync_file->cbs[i].fence,
-                                     &sync_file->cbs[i].cb);
-               fence_put(sync_file->cbs[i].fence);
-       }

+       fence_remove_callback(sync_file->fence, &sync_file->cb);
+       fence_teardown(sync_file->fence);
+       fence_put(sync_file->fence);
        kfree(sync_file);
 }

@@ -315,6 +367,7 @@ static long sync_file_ioctl_fence_info(struct sync_file 
*sync_file,
 {
        struct sync_file_info info;
        struct sync_fence_info *fence_info = NULL;
+       struct fence **fences;
        __u32 size;
        int ret, i;

@@ -341,8 +394,10 @@ static long sync_file_ioctl_fence_info(struct sync_file 
*sync_file,
        if (!fence_info)
                return -ENOMEM;

-       for (i = 0; i < sync_file->num_fences; ++i)
-               sync_fill_fence_info(sync_file->cbs[i].fence, &fence_info[i]);
+       fences = fence_get_fences(sync_file->fence);
+       for (i = 0; i < sync_file->num_fences; i++)
+               sync_fill_fence_info(fences[i], &fence_info[i]);
+       kfree(fences);

        if (copy_to_user(u64_to_user_ptr(info.sync_fence_info), fence_info,
                         size)) {
diff --git a/drivers/staging/android/sync_debug.c 
b/drivers/staging/android/sync_debug.c
index 5f57499..5fb6d3d 100644
--- a/drivers/staging/android/sync_debug.c
+++ b/drivers/staging/android/sync_debug.c
@@ -156,13 +156,16 @@ static void sync_print_obj(struct seq_file *s, struct 
sync_timeline *obj)
 static void sync_print_sync_file(struct seq_file *s,
                                  struct sync_file *sync_file)
 {
+       struct fence **fences;
        int i;

        seq_printf(s, "[%p] %s: %s\n", sync_file, sync_file->name,
                   sync_status_str(atomic_read(&sync_file->status)));

+       fences = fence_get_fences(sync_file->fence);
        for (i = 0; i < sync_file->num_fences; ++i)
-               sync_print_fence(s, sync_file->cbs[i].fence, true);
+               sync_print_fence(s, fences[i], true);
+       kfree(fences);
 }

 static int sync_debugfs_show(struct seq_file *s, void *unused)
diff --git a/include/linux/sync_file.h b/include/linux/sync_file.h
index c6ffe8b..d13885f 100644
--- a/include/linux/sync_file.h
+++ b/include/linux/sync_file.h
@@ -20,12 +20,6 @@
 #include <linux/spinlock.h>
 #include <linux/fence.h>

-struct sync_file_cb {
-       struct fence_cb cb;
-       struct fence *fence;
-       struct sync_file *sync_file;
-};
-
 /**
  * struct sync_file - sync file to export to the userspace
  * @file:              file representing this fence
@@ -35,7 +29,8 @@ struct sync_file_cb {
  * @num_fences:                number of sync_pts in the fence
  * @wq:                        wait queue for fence signaling
  * @status:            0: signaled, >0:active, <0: error
- * @cbs:               sync_pts callback information
+ * @fence:             fence with the fences in the sync_file
+ * @cb:                        fence callback information
  */
 struct sync_file {
        struct file             *file;
@@ -49,7 +44,8 @@ struct sync_file {
        wait_queue_head_t       wq;
        atomic_t                status;

-       struct sync_file_cb     cbs[];
+       struct fence            *fence;
+       struct fence_cb cb;
 };

 struct sync_file *sync_file_create(struct fence *fence);
-- 
2.5.5

Reply via email to