[RFC 5/5] dma-buf/sync_file: rework fence storage in struct file

From: Gustavo Padovan
Date: Thu Jun 23 2016 - 11:30:38 EST


From: Gustavo Padovan <gustavo.padovan@xxxxxxxxxxxxxxx>

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@xxxxxxxxxxxxxxx>
---
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