[PATCH v2 01/11] dma-buf/sync_file: de-stage sync_file

From: Gustavo Padovan
Date: Wed Jan 27 2016 - 08:31:02 EST


From: Gustavo Padovan <gustavo.padovan@xxxxxxxxxxxxxxx>

sync_file is useful to connect one or more fences to the file. The file is
used by userspace to track fences.

Signed-off-by: Gustavo Padovan <gustavo.padovan@xxxxxxxxxxxxxxx>
---
drivers/Kconfig | 2 +
drivers/dma-buf/Kconfig | 11 +
drivers/dma-buf/Makefile | 1 +
drivers/dma-buf/sync_file.c | 440 +++++++++++++++++++++
drivers/staging/android/Kconfig | 1 +
drivers/staging/android/sync.c | 419 --------------------
drivers/staging/android/sync.h | 105 +----
drivers/staging/android/sync_debug.c | 1 +
drivers/staging/android/trace/sync.h | 44 ---
include/linux/sync_file.h | 123 ++++++
include/trace/events/sync_file.h | 57 +++
.../android/uapi => include/uapi/linux}/sync.h | 12 +-
12 files changed, 644 insertions(+), 572 deletions(-)
create mode 100644 drivers/dma-buf/Kconfig
create mode 100644 drivers/dma-buf/sync_file.c
create mode 100644 include/linux/sync_file.h
create mode 100644 include/trace/events/sync_file.h
rename {drivers/staging/android/uapi => include/uapi/linux}/sync.h (90%)

diff --git a/drivers/Kconfig b/drivers/Kconfig
index d2ac339..430f761 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -114,6 +114,8 @@ source "drivers/rtc/Kconfig"

source "drivers/dma/Kconfig"

+source "drivers/dma-buf/Kconfig"
+
source "drivers/dca/Kconfig"

source "drivers/auxdisplay/Kconfig"
diff --git a/drivers/dma-buf/Kconfig b/drivers/dma-buf/Kconfig
new file mode 100644
index 0000000..9824bc4
--- /dev/null
+++ b/drivers/dma-buf/Kconfig
@@ -0,0 +1,11 @@
+menu "DMABUF options"
+
+config SYNC_FILE
+ bool "sync_file support for fences"
+ default n
+ select ANON_INODES
+ select DMA_SHARED_BUFFER
+ ---help---
+ This option enables the fence framework synchronization to export
+ sync_files to userspace that can represent one or more fences.
+endmenu
diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile
index 57a675f..4a424ec 100644
--- a/drivers/dma-buf/Makefile
+++ b/drivers/dma-buf/Makefile
@@ -1 +1,2 @@
obj-y := dma-buf.o fence.o reservation.o seqno-fence.o
+obj-$(CONFIG_SYNC_FILE) += sync_file.o
diff --git a/drivers/dma-buf/sync_file.c b/drivers/dma-buf/sync_file.c
new file mode 100644
index 0000000..92474dd
--- /dev/null
+++ b/drivers/dma-buf/sync_file.c
@@ -0,0 +1,440 @@
+/*
+ * drivers/dma-buf/sync_file.c
+ *
+ * Copyright (C) 2012 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/export.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/anon_inodes.h>
+#include <linux/sync_file.h>
+#include <uapi/linux/sync.h>
+
+#define CREATE_TRACE_POINTS
+#include <trace/events/sync_file.h>
+
+static const struct file_operations sync_file_fops;
+
+static struct sync_file *sync_file_alloc(int size, const char *name)
+{
+ struct sync_file *sync_file;
+
+ sync_file = kzalloc(size, GFP_KERNEL);
+ if (!sync_file)
+ return NULL;
+
+ sync_file->file = anon_inode_getfile("sync_file", &sync_file_fops,
+ sync_file, 0);
+ if (IS_ERR(sync_file->file))
+ goto err;
+
+ kref_init(&sync_file->kref);
+ strlcpy(sync_file->name, name, sizeof(sync_file->name));
+
+ init_waitqueue_head(&sync_file->wq);
+
+ return sync_file;
+
+err:
+ kfree(sync_file);
+ return NULL;
+}
+
+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;
+
+ if (atomic_dec_and_test(&sync_file->status))
+ wake_up_all(&sync_file->wq);
+}
+
+/* TODO: implement a create which takes more that one fence */
+struct sync_file *sync_file_create(const char *name, struct fence *fence)
+{
+ struct sync_file *sync_file;
+
+ sync_file = sync_file_alloc(offsetof(struct sync_file, cbs[1]),
+ name);
+ if (!sync_file)
+ return NULL;
+
+ sync_file->num_fences = 1;
+ atomic_set(&sync_file->status, 1);
+
+ 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))
+ atomic_dec(&sync_file->status);
+
+ return sync_file;
+}
+EXPORT_SYMBOL(sync_file_create);
+
+struct sync_file *sync_file_fdget(int fd)
+{
+ struct file *file = fget(fd);
+
+ if (!file)
+ return NULL;
+
+ if (file->f_op != &sync_file_fops)
+ goto err;
+
+ return file->private_data;
+
+err:
+ fput(file);
+ return NULL;
+}
+EXPORT_SYMBOL(sync_file_fdget);
+
+void sync_file_put(struct sync_file *sync_file)
+{
+ fput(sync_file->file);
+}
+EXPORT_SYMBOL(sync_file_put);
+
+void sync_file_install(struct sync_file *sync_file, int fd)
+{
+ fd_install(fd, sync_file->file);
+}
+EXPORT_SYMBOL(sync_file_install);
+
+static void sync_file_add_fence(struct sync_file *sync_file, int *i,
+ struct fence *fence)
+{
+ sync_file->cbs[*i].fence = fence;
+ sync_file->cbs[*i].sync_file = sync_file;
+
+ if (!fence_add_callback(fence, &sync_file->cbs[*i].cb,
+ fence_check_cb_func)) {
+ fence_get(fence);
+ (*i)++;
+ }
+}
+
+struct sync_file *sync_file_merge(const char *name,
+ struct sync_file *a, struct sync_file *b)
+{
+ int num_fences = a->num_fences + b->num_fences;
+ struct sync_file *sync_file;
+ int i, i_a, i_b;
+ unsigned long size = offsetof(struct sync_file, cbs[num_fences]);
+
+ sync_file = sync_file_alloc(size, name);
+ if (!sync_file)
+ return NULL;
+
+ atomic_set(&sync_file->status, num_fences);
+
+ /*
+ * Assume sync_file a and b are both ordered and have no
+ * duplicates with the same context.
+ *
+ * If a sync_file can only be created with sync_file_merge
+ * 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;
+
+ if (pt_a->context < pt_b->context) {
+ sync_file_add_fence(sync_file, &i, pt_a);
+
+ i_a++;
+ } else if (pt_a->context > pt_b->context) {
+ sync_file_add_fence(sync_file, &i, pt_b);
+
+ i_b++;
+ } else {
+ if (pt_a->seqno - pt_b->seqno <= INT_MAX)
+ sync_file_add_fence(sync_file, &i, pt_a);
+ else
+ sync_file_add_fence(sync_file, &i, pt_b);
+
+ i_a++;
+ i_b++;
+ }
+ }
+
+ for (; i_a < a->num_fences; i_a++)
+ sync_file_add_fence(sync_file, &i, a->cbs[i_a].fence);
+
+ for (; i_b < b->num_fences; i_b++)
+ sync_file_add_fence(sync_file, &i, b->cbs[i_b].fence);
+
+ if (num_fences > i)
+ atomic_sub(num_fences - i, &sync_file->status);
+ sync_file->num_fences = i;
+
+ return sync_file;
+}
+EXPORT_SYMBOL(sync_file_merge);
+
+int sync_file_wait(struct sync_file *sync_file, long timeout)
+{
+ long ret;
+ int i;
+
+ if (timeout < 0)
+ timeout = MAX_SCHEDULE_TIMEOUT;
+ else
+ timeout = msecs_to_jiffies(timeout);
+
+ trace_sync_wait(sync_file, 1);
+ for (i = 0; i < sync_file->num_fences; ++i)
+ trace_fence(sync_file->cbs[i].fence);
+ ret = wait_event_interruptible_timeout(sync_file->wq,
+ atomic_read(&sync_file->status) <= 0,
+ timeout);
+ trace_sync_wait(sync_file, 0);
+
+ if (ret < 0) {
+ return ret;
+ } else if (ret == 0) {
+ if (timeout)
+ pr_info("sync_file timeout on [%p] after %dms\n",
+ sync_file, jiffies_to_msecs(timeout));
+ return -ETIME;
+ }
+
+ ret = atomic_read(&sync_file->status);
+ if (ret)
+ pr_info("sync_file error %ld on [%p]\n", ret, sync_file);
+
+ return ret;
+}
+EXPORT_SYMBOL(sync_file_wait);
+
+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);
+ }
+
+ kfree(sync_file);
+}
+
+static int sync_file_release(struct inode *inode, struct file *file)
+{
+ struct sync_file *sync_file = file->private_data;
+
+ kref_put(&sync_file->kref, sync_file_free);
+ return 0;
+}
+
+static unsigned int sync_file_poll(struct file *file, poll_table *wait)
+{
+ struct sync_file *sync_file = file->private_data;
+ int status;
+
+ poll_wait(file, &sync_file->wq, wait);
+
+ status = atomic_read(&sync_file->status);
+
+ if (!status)
+ return POLLIN;
+ else if (status < 0)
+ return POLLERR;
+ return 0;
+}
+
+static long sync_file_ioctl_wait(struct sync_file *sync_file,
+ unsigned long arg)
+{
+ __s32 value;
+
+ if (copy_from_user(&value, (void __user *)arg, sizeof(value)))
+ return -EFAULT;
+
+ return sync_file_wait(sync_file, value);
+}
+
+static long sync_file_ioctl_merge(struct sync_file *sync_file,
+ unsigned long arg)
+{
+ int fd = get_unused_fd_flags(O_CLOEXEC);
+ int err;
+ struct sync_file *fence2, *fence3;
+ struct sync_merge_data data;
+
+ if (fd < 0)
+ return fd;
+
+ if (copy_from_user(&data, (void __user *)arg, sizeof(data))) {
+ err = -EFAULT;
+ goto err_put_fd;
+ }
+
+ fence2 = sync_file_fdget(data.fd2);
+ if (!fence2) {
+ err = -ENOENT;
+ goto err_put_fd;
+ }
+
+ data.name[sizeof(data.name) - 1] = '\0';
+ fence3 = sync_file_merge(data.name, sync_file, fence2);
+ if (!fence3) {
+ err = -ENOMEM;
+ goto err_put_fence2;
+ }
+
+ data.fence = fd;
+ if (copy_to_user((void __user *)arg, &data, sizeof(data))) {
+ err = -EFAULT;
+ goto err_put_fence3;
+ }
+
+ sync_file_install(fence3, fd);
+ sync_file_put(fence2);
+ return 0;
+
+err_put_fence3:
+ sync_file_put(fence3);
+
+err_put_fence2:
+ sync_file_put(fence2);
+
+err_put_fd:
+ put_unused_fd(fd);
+ return err;
+}
+
+static int sync_fill_pt_info(struct fence *fence, void *data, int size)
+{
+ struct fence_info *info = data;
+ int ret;
+
+ if (size < sizeof(struct fence_info))
+ return -ENOMEM;
+
+ info->len = sizeof(struct fence_info);
+
+ if (fence->ops->fill_driver_data) {
+ ret = fence->ops->fill_driver_data(fence, info->driver_data,
+ size - sizeof(*info));
+ if (ret < 0)
+ return ret;
+
+ info->len += ret;
+ }
+
+ strlcpy(info->obj_name, fence->ops->get_timeline_name(fence),
+ sizeof(info->obj_name));
+ strlcpy(info->driver_name, fence->ops->get_driver_name(fence),
+ sizeof(info->driver_name));
+ if (fence_is_signaled(fence))
+ info->status = fence->status >= 0 ? 1 : fence->status;
+ else
+ info->status = 0;
+ info->timestamp_ns = ktime_to_ns(fence->timestamp);
+
+ return info->len;
+}
+
+static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
+ unsigned long arg)
+{
+ struct sync_file_info_data *data;
+ __u32 size;
+ __u32 len = 0;
+ int ret, i;
+
+ if (copy_from_user(&size, (void __user *)arg, sizeof(size)))
+ return -EFAULT;
+
+ if (size < sizeof(struct sync_file_info_data))
+ return -EINVAL;
+
+ if (size > 4096)
+ size = 4096;
+
+ data = kzalloc(size, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ strlcpy(data->name, sync_file->name, sizeof(data->name));
+ data->status = atomic_read(&sync_file->status);
+ if (data->status >= 0)
+ data->status = !data->status;
+
+ len = sizeof(struct sync_file_info_data);
+
+ for (i = 0; i < sync_file->num_fences; ++i) {
+ struct fence *fence = sync_file->cbs[i].fence;
+
+ ret = sync_fill_pt_info(fence, (u8 *)data + len, size - len);
+
+ if (ret < 0)
+ goto out;
+
+ len += ret;
+ }
+
+ data->len = len;
+
+ if (copy_to_user((void __user *)arg, data, len))
+ ret = -EFAULT;
+ else
+ ret = 0;
+
+out:
+ kfree(data);
+
+ return ret;
+}
+
+static long sync_file_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct sync_file *sync_file = file->private_data;
+
+ switch (cmd) {
+ case SYNC_IOC_WAIT:
+ return sync_file_ioctl_wait(sync_file, arg);
+
+ case SYNC_IOC_MERGE:
+ return sync_file_ioctl_merge(sync_file, arg);
+
+ case SYNC_IOC_FENCE_INFO:
+ return sync_file_ioctl_fence_info(sync_file, arg);
+
+ default:
+ return -ENOTTY;
+ }
+}
+
+static const struct file_operations sync_file_fops = {
+ .release = sync_file_release,
+ .poll = sync_file_poll,
+ .unlocked_ioctl = sync_file_ioctl,
+ .compat_ioctl = sync_file_ioctl,
+};
+
diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig
index bd90d20..2756988 100644
--- a/drivers/staging/android/Kconfig
+++ b/drivers/staging/android/Kconfig
@@ -52,6 +52,7 @@ config SW_SYNC
bool "Software synchronization objects"
default n
depends on SYNC
+ depends on SYNC_FILE
---help---
A sync object driver that uses a 32bit counter to coordinate
synchronization. Useful when there is no hardware primitive backing
diff --git a/drivers/staging/android/sync.c b/drivers/staging/android/sync.c
index 5fa4779..1e1c009 100644
--- a/drivers/staging/android/sync.c
+++ b/drivers/staging/android/sync.c
@@ -16,10 +16,7 @@

#include <linux/debugfs.h>
#include <linux/export.h>
-#include <linux/file.h>
-#include <linux/fs.h>
#include <linux/kernel.h>
-#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
@@ -32,7 +29,6 @@
#include "trace/sync.h"

static const struct fence_ops android_fence_ops;
-static const struct file_operations sync_file_fops;

struct sync_timeline *sync_timeline_create(const struct sync_timeline_ops *ops,
int size, const char *name)
@@ -136,208 +132,6 @@ struct fence *sync_pt_create(struct sync_timeline *obj, int size)
}
EXPORT_SYMBOL(sync_pt_create);

-static struct sync_file *sync_file_alloc(int size, const char *name)
-{
- struct sync_file *sync_file;
-
- sync_file = kzalloc(size, GFP_KERNEL);
- if (!sync_file)
- return NULL;
-
- sync_file->file = anon_inode_getfile("sync_file", &sync_file_fops,
- sync_file, 0);
- if (IS_ERR(sync_file->file))
- goto err;
-
- kref_init(&sync_file->kref);
- strlcpy(sync_file->name, name, sizeof(sync_file->name));
-
- init_waitqueue_head(&sync_file->wq);
-
- return sync_file;
-
-err:
- kfree(sync_file);
- return NULL;
-}
-
-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;
-
- if (atomic_dec_and_test(&sync_file->status))
- wake_up_all(&sync_file->wq);
-}
-
-/* TODO: implement a create which takes more that one fence */
-struct sync_file *sync_file_create(const char *name, struct fence *fence)
-{
- struct sync_file *sync_file;
-
- sync_file = sync_file_alloc(offsetof(struct sync_file, cbs[1]),
- name);
- if (!sync_file)
- return NULL;
-
- sync_file->num_fences = 1;
- atomic_set(&sync_file->status, 1);
-
- 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))
- atomic_dec(&sync_file->status);
-
- sync_file_debug_add(sync_file);
-
- return sync_file;
-}
-EXPORT_SYMBOL(sync_file_create);
-
-struct sync_file *sync_file_fdget(int fd)
-{
- struct file *file = fget(fd);
-
- if (!file)
- return NULL;
-
- if (file->f_op != &sync_file_fops)
- goto err;
-
- return file->private_data;
-
-err:
- fput(file);
- return NULL;
-}
-EXPORT_SYMBOL(sync_file_fdget);
-
-void sync_file_put(struct sync_file *sync_file)
-{
- fput(sync_file->file);
-}
-EXPORT_SYMBOL(sync_file_put);
-
-void sync_file_install(struct sync_file *sync_file, int fd)
-{
- fd_install(fd, sync_file->file);
-}
-EXPORT_SYMBOL(sync_file_install);
-
-static void sync_file_add_pt(struct sync_file *sync_file, int *i,
- struct fence *fence)
-{
- sync_file->cbs[*i].fence = fence;
- sync_file->cbs[*i].sync_file = sync_file;
-
- if (!fence_add_callback(fence, &sync_file->cbs[*i].cb,
- fence_check_cb_func)) {
- fence_get(fence);
- (*i)++;
- }
-}
-
-struct sync_file *sync_file_merge(const char *name,
- struct sync_file *a, struct sync_file *b)
-{
- int num_fences = a->num_fences + b->num_fences;
- struct sync_file *sync_file;
- int i, i_a, i_b;
- unsigned long size = offsetof(struct sync_file, cbs[num_fences]);
-
- sync_file = sync_file_alloc(size, name);
- if (!sync_file)
- return NULL;
-
- atomic_set(&sync_file->status, num_fences);
-
- /*
- * Assume sync_file a and b are both ordered and have no
- * duplicates with the same context.
- *
- * If a sync_file can only be created with sync_file_merge
- * 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;
-
- if (pt_a->context < pt_b->context) {
- sync_file_add_pt(sync_file, &i, pt_a);
-
- i_a++;
- } else if (pt_a->context > pt_b->context) {
- sync_file_add_pt(sync_file, &i, pt_b);
-
- i_b++;
- } else {
- if (pt_a->seqno - pt_b->seqno <= INT_MAX)
- sync_file_add_pt(sync_file, &i, pt_a);
- else
- sync_file_add_pt(sync_file, &i, pt_b);
-
- i_a++;
- i_b++;
- }
- }
-
- for (; i_a < a->num_fences; i_a++)
- sync_file_add_pt(sync_file, &i, a->cbs[i_a].fence);
-
- for (; i_b < b->num_fences; i_b++)
- sync_file_add_pt(sync_file, &i, b->cbs[i_b].fence);
-
- if (num_fences > i)
- atomic_sub(num_fences - i, &sync_file->status);
- sync_file->num_fences = i;
-
- sync_file_debug_add(sync_file);
- return sync_file;
-}
-EXPORT_SYMBOL(sync_file_merge);
-
-int sync_file_wait(struct sync_file *sync_file, long timeout)
-{
- long ret;
- int i;
-
- if (timeout < 0)
- timeout = MAX_SCHEDULE_TIMEOUT;
- else
- timeout = msecs_to_jiffies(timeout);
-
- trace_sync_wait(sync_file, 1);
- for (i = 0; i < sync_file->num_fences; ++i)
- trace_fence(sync_file->cbs[i].fence);
- ret = wait_event_interruptible_timeout(sync_file->wq,
- atomic_read(&sync_file->status) <= 0,
- timeout);
- trace_sync_wait(sync_file, 0);
-
- if (ret < 0) {
- return ret;
- } else if (ret == 0) {
- if (timeout) {
- pr_info("sync_file timeout on [%p] after %dms\n",
- sync_file, jiffies_to_msecs(timeout));
- sync_dump();
- }
- return -ETIME;
- }
-
- ret = atomic_read(&sync_file->status);
- if (ret) {
- pr_info("sync_file error %ld on [%p]\n", ret, sync_file);
- sync_dump();
- }
- return ret;
-}
-EXPORT_SYMBOL(sync_file_wait);
-
static const char *android_fence_get_driver_name(struct fence *fence)
{
struct sync_timeline *parent = fence_parent(fence);
@@ -437,216 +231,3 @@ static const struct fence_ops android_fence_ops = {
.timeline_value_str = android_fence_timeline_value_str,
};

-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);
- }
-
- kfree(sync_file);
-}
-
-static int sync_file_release(struct inode *inode, struct file *file)
-{
- struct sync_file *sync_file = file->private_data;
-
- sync_file_debug_remove(sync_file);
-
- kref_put(&sync_file->kref, sync_file_free);
- return 0;
-}
-
-static unsigned int sync_file_poll(struct file *file, poll_table *wait)
-{
- struct sync_file *sync_file = file->private_data;
- int status;
-
- poll_wait(file, &sync_file->wq, wait);
-
- status = atomic_read(&sync_file->status);
-
- if (!status)
- return POLLIN;
- else if (status < 0)
- return POLLERR;
- return 0;
-}
-
-static long sync_file_ioctl_wait(struct sync_file *sync_file,
- unsigned long arg)
-{
- __s32 value;
-
- if (copy_from_user(&value, (void __user *)arg, sizeof(value)))
- return -EFAULT;
-
- return sync_file_wait(sync_file, value);
-}
-
-static long sync_file_ioctl_merge(struct sync_file *sync_file,
- unsigned long arg)
-{
- int fd = get_unused_fd_flags(O_CLOEXEC);
- int err;
- struct sync_file *fence2, *fence3;
- struct sync_merge_data data;
-
- if (fd < 0)
- return fd;
-
- if (copy_from_user(&data, (void __user *)arg, sizeof(data))) {
- err = -EFAULT;
- goto err_put_fd;
- }
-
- fence2 = sync_file_fdget(data.fd2);
- if (!fence2) {
- err = -ENOENT;
- goto err_put_fd;
- }
-
- data.name[sizeof(data.name) - 1] = '\0';
- fence3 = sync_file_merge(data.name, sync_file, fence2);
- if (!fence3) {
- err = -ENOMEM;
- goto err_put_fence2;
- }
-
- data.fence = fd;
- if (copy_to_user((void __user *)arg, &data, sizeof(data))) {
- err = -EFAULT;
- goto err_put_fence3;
- }
-
- sync_file_install(fence3, fd);
- sync_file_put(fence2);
- return 0;
-
-err_put_fence3:
- sync_file_put(fence3);
-
-err_put_fence2:
- sync_file_put(fence2);
-
-err_put_fd:
- put_unused_fd(fd);
- return err;
-}
-
-static int sync_fill_pt_info(struct fence *fence, void *data, int size)
-{
- struct sync_pt_info *info = data;
- int ret;
-
- if (size < sizeof(struct sync_pt_info))
- return -ENOMEM;
-
- info->len = sizeof(struct sync_pt_info);
-
- if (fence->ops->fill_driver_data) {
- ret = fence->ops->fill_driver_data(fence, info->driver_data,
- size - sizeof(*info));
- if (ret < 0)
- return ret;
-
- info->len += ret;
- }
-
- strlcpy(info->obj_name, fence->ops->get_timeline_name(fence),
- sizeof(info->obj_name));
- strlcpy(info->driver_name, fence->ops->get_driver_name(fence),
- sizeof(info->driver_name));
- if (fence_is_signaled(fence))
- info->status = fence->status >= 0 ? 1 : fence->status;
- else
- info->status = 0;
- info->timestamp_ns = ktime_to_ns(fence->timestamp);
-
- return info->len;
-}
-
-static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
- unsigned long arg)
-{
- struct sync_file_info_data *data;
- __u32 size;
- __u32 len = 0;
- int ret, i;
-
- if (copy_from_user(&size, (void __user *)arg, sizeof(size)))
- return -EFAULT;
-
- if (size < sizeof(struct sync_file_info_data))
- return -EINVAL;
-
- if (size > 4096)
- size = 4096;
-
- data = kzalloc(size, GFP_KERNEL);
- if (!data)
- return -ENOMEM;
-
- strlcpy(data->name, sync_file->name, sizeof(data->name));
- data->status = atomic_read(&sync_file->status);
- if (data->status >= 0)
- data->status = !data->status;
-
- len = sizeof(struct sync_file_info_data);
-
- for (i = 0; i < sync_file->num_fences; ++i) {
- struct fence *fence = sync_file->cbs[i].fence;
-
- ret = sync_fill_pt_info(fence, (u8 *)data + len, size - len);
-
- if (ret < 0)
- goto out;
-
- len += ret;
- }
-
- data->len = len;
-
- if (copy_to_user((void __user *)arg, data, len))
- ret = -EFAULT;
- else
- ret = 0;
-
-out:
- kfree(data);
-
- return ret;
-}
-
-static long sync_file_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- struct sync_file *sync_file = file->private_data;
-
- switch (cmd) {
- case SYNC_IOC_WAIT:
- return sync_file_ioctl_wait(sync_file, arg);
-
- case SYNC_IOC_MERGE:
- return sync_file_ioctl_merge(sync_file, arg);
-
- case SYNC_IOC_FENCE_INFO:
- return sync_file_ioctl_fence_info(sync_file, arg);
-
- default:
- return -ENOTTY;
- }
-}
-
-static const struct file_operations sync_file_fops = {
- .release = sync_file_release,
- .poll = sync_file_poll,
- .unlocked_ioctl = sync_file_ioctl,
- .compat_ioctl = sync_file_ioctl,
-};
-
diff --git a/drivers/staging/android/sync.h b/drivers/staging/android/sync.h
index 8980b55..fb209fc 100644
--- a/drivers/staging/android/sync.h
+++ b/drivers/staging/android/sync.h
@@ -18,13 +18,11 @@
#include <linux/ktime.h>
#include <linux/list.h>
#include <linux/spinlock.h>
-#include <linux/wait.h>
#include <linux/fence.h>
-
-#include "uapi/sync.h"
+#include <linux/sync_file.h>
+#include <uapi/linux/sync.h>

struct sync_timeline;
-struct sync_file;

/**
* struct sync_timeline_ops - sync object implementation ops
@@ -94,38 +92,6 @@ static inline struct sync_timeline *fence_parent(struct fence *fence)
child_list_lock);
}

-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
- * @kref: reference count on fence.
- * @name: name of sync_file. Useful for debugging
- * @sync_file_list: membership in global file list
- * @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
- */
-struct sync_file {
- struct file *file;
- struct kref kref;
- char name[32];
-#ifdef CONFIG_DEBUG_FS
- struct list_head sync_file_list;
-#endif
- int num_fences;
-
- wait_queue_head_t wq;
- atomic_t status;
-
- struct sync_file_cb cbs[];
-};
-
/*
* API for sync_timeline implementers
*/
@@ -175,73 +141,6 @@ void sync_timeline_signal(struct sync_timeline *obj);
*/
struct fence *sync_pt_create(struct sync_timeline *parent, int size);

-/**
- * sync_fence_create() - creates a sync fence
- * @name: name of fence to create
- * @fence: fence to add to the sync_fence
- *
- * Creates a sync_file containg @fence. Once this is called, the sync_file
- * takes ownership of @fence.
- */
-struct sync_file *sync_file_create(const char *name, struct fence *fence);
-
-/*
- * API for sync_file consumers
- */
-
-/**
- * sync_file_merge() - merge two sync_files
- * @name: name of new fence
- * @a: sync_file a
- * @b: sync_file b
- *
- * Creates a new sync_file which contains copies of all the fences in both
- * @a and @b. @a and @b remain valid, independent sync_file. Returns the
- * new merged sync_file or NULL in case of error.
- */
-struct sync_file *sync_file_merge(const char *name,
- struct sync_file *a, struct sync_file *b);
-
-/**
- * sync_file_fdget() - get a sync_file from an fd
- * @fd: fd referencing a fence
- *
- * Ensures @fd references a valid sync_file, increments the refcount of the
- * backing file. Returns the sync_file or NULL in case of error.
- */
-struct sync_file *sync_file_fdget(int fd);
-
-/**
- * sync_file_put() - puts a reference of a sync_file
- * @sync_file: sync_file to put
- *
- * Puts a reference on @sync_fence. If this is the last reference, the
- * sync_fil and all it's sync_pts will be freed
- */
-void sync_file_put(struct sync_file *sync_file);
-
-/**
- * sync_file_install() - installs a sync_file into a file descriptor
- * @sync_file: sync_file to install
- * @fd: file descriptor in which to install the fence
- *
- * Installs @sync_file into @fd. @fd's should be acquired through
- * get_unused_fd_flags(O_CLOEXEC).
- */
-void sync_file_install(struct sync_file *sync_file, int fd);
-
-/**
- * sync_file_wait() - wait on sync file
- * @sync_file: file to wait on
- * @tiemout: timeout in ms
- *
- * Wait for @sync_file to be signaled or have an error. Waits indefinitely
- * if @timeout < 0.
- *
- * Returns 0 if fence signaled, > 0 if it is still active and <0 on error
- */
-int sync_file_wait(struct sync_file *sync_file, long timeout);
-
#ifdef CONFIG_DEBUG_FS

void sync_timeline_debug_add(struct sync_timeline *obj);
diff --git a/drivers/staging/android/sync_debug.c b/drivers/staging/android/sync_debug.c
index 7e53da7..b37412d 100644
--- a/drivers/staging/android/sync_debug.c
+++ b/drivers/staging/android/sync_debug.c
@@ -27,6 +27,7 @@
#include <linux/uaccess.h>
#include <linux/anon_inodes.h>
#include <linux/time64.h>
+#include <linux/sync_file.h>
#include "sw_sync.h"

#ifdef CONFIG_DEBUG_FS
diff --git a/drivers/staging/android/trace/sync.h b/drivers/staging/android/trace/sync.h
index 87c60e9..a0f80f4 100644
--- a/drivers/staging/android/trace/sync.h
+++ b/drivers/staging/android/trace/sync.h
@@ -32,50 +32,6 @@ TRACE_EVENT(sync_timeline,
TP_printk("name=%s value=%s", __get_str(name), __entry->value)
);

-TRACE_EVENT(sync_wait,
- TP_PROTO(struct sync_file *sync_file, int begin),
-
- TP_ARGS(sync_file, begin),
-
- TP_STRUCT__entry(
- __string(name, sync_file->name)
- __field(s32, status)
- __field(u32, begin)
- ),
-
- TP_fast_assign(
- __assign_str(name, sync_file->name);
- __entry->status = atomic_read(&sync_file->status);
- __entry->begin = begin;
- ),
-
- TP_printk("%s name=%s state=%d", __entry->begin ? "begin" : "end",
- __get_str(name), __entry->status)
-);
-
-TRACE_EVENT(fence,
- TP_PROTO(struct fence *fence),
-
- TP_ARGS(fence),
-
- TP_STRUCT__entry(
- __string(timeline, fence->ops->get_timeline_name(fence))
- __array(char, value, 32)
- ),
-
- TP_fast_assign(
- __assign_str(timeline, fence->ops->get_timeline_name(fence));
- if (fence->ops->fence_value_str) {
- fence->ops->fence_value_str(fence, __entry->value,
- sizeof(__entry->value));
- } else {
- __entry->value[0] = '\0';
- }
- ),
-
- TP_printk("name=%s value=%s", __get_str(timeline), __entry->value)
-);
-
#endif /* if !defined(_TRACE_SYNC_H) || defined(TRACE_HEADER_MULTI_READ) */

/* This part must be outside protection */
diff --git a/include/linux/sync_file.h b/include/linux/sync_file.h
new file mode 100644
index 0000000..ac2b4c6
--- /dev/null
+++ b/include/linux/sync_file.h
@@ -0,0 +1,123 @@
+/*
+ * include/linux/sync_file.h
+ *
+ * Copyright (C) 2012 Google, Inc.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _LINUX_SYNC_FILE_H
+#define _LINUX_SYNC_FILE_H
+
+#include <linux/types.h>
+#include <linux/kref.h>
+#include <linux/ktime.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/wait.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
+ * @kref: reference count on fence.
+ * @name: name of sync_file. Useful for debugging
+ * @sync_file_list: membership in global file list
+ * @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
+ */
+struct sync_file {
+ struct file *file;
+ struct kref kref;
+ char name[32];
+#ifdef CONFIG_DEBUG_FS
+ struct list_head sync_file_list;
+#endif
+ int num_fences;
+
+ wait_queue_head_t wq;
+ atomic_t status;
+
+ struct sync_file_cb cbs[];
+};
+
+/**
+ * sync_file_create() - creates a sync fence
+ * @name: name of fence to create
+ * @fence: fence to add to the sync_fence
+ *
+ * Creates a sync_file containg @fence. Once this is called, the sync_file
+ * takes ownership of @fence.
+ */
+struct sync_file *sync_file_create(const char *name, struct fence *fence);
+
+/*
+ * API for sync_file consumers
+ */
+
+/**
+ * sync_file_merge() - merge two sync_files
+ * @name: name of new fence
+ * @a: sync_file a
+ * @b: sync_file b
+ *
+ * Creates a new sync_file which contains copies of all the fences in both
+ * @a and @b. @a and @b remain valid, independent sync_file. Returns the
+ * new merged sync_file or NULL in case of error.
+ */
+struct sync_file *sync_file_merge(const char *name,
+ struct sync_file *a, struct sync_file *b);
+
+/**
+ * sync_file_fdget() - get a sync_file from an fd
+ * @fd: fd referencing a fence
+ *
+ * Ensures @fd references a valid sync_file, increments the refcount of the
+ * backing file. Returns the sync_file or NULL in case of error.
+ */
+struct sync_file *sync_file_fdget(int fd);
+
+/**
+ * sync_file_put() - puts a reference of a sync_file
+ * @sync_file: sync_file to put
+ *
+ * Puts a reference on @sync_fence. If this is the last reference, the
+ * sync_fil and all it's sync_pts will be freed
+ */
+void sync_file_put(struct sync_file *sync_file);
+
+/**
+ * sync_file_install() - installs a sync_file into a file descriptor
+ * @sync_file: sync_file to install
+ * @fd: file descriptor in which to install the fence
+ *
+ * Installs @sync_file into @fd. @fd's should be acquired through
+ * get_unused_fd_flags(O_CLOEXEC).
+ */
+void sync_file_install(struct sync_file *sync_file, int fd);
+
+/**
+ * sync_file_wait() - wait on sync file
+ * @sync_file: file to wait on
+ * @tiemout: timeout in ms
+ *
+ * Wait for @sync_file to be signaled or have an error. Waits indefinitely
+ * if @timeout < 0.
+ *
+ * Returns 0 if fence signaled, > 0 if it is still active and <0 on error
+ */
+int sync_file_wait(struct sync_file *sync_file, long timeout);
+
+#endif /* _LINUX_SYNC_H */
diff --git a/include/trace/events/sync_file.h b/include/trace/events/sync_file.h
new file mode 100644
index 0000000..659b5f3
--- /dev/null
+++ b/include/trace/events/sync_file.h
@@ -0,0 +1,57 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM sync_file
+
+#if !defined(_TRACE_SYNC_FILE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_SYNC_FILE_H
+
+#include <linux/sync.h>
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(sync_wait,
+ TP_PROTO(struct sync_file *sync_file, int begin),
+
+ TP_ARGS(sync_file, begin),
+
+ TP_STRUCT__entry(
+ __string(name, sync_file->name)
+ __field(s32, status)
+ __field(u32, begin)
+ ),
+
+ TP_fast_assign(
+ __assign_str(name, sync_file->name);
+ __entry->status = atomic_read(&sync_file->status);
+ __entry->begin = begin;
+ ),
+
+ TP_printk("%s name=%s state=%d", __entry->begin ? "begin" : "end",
+ __get_str(name), __entry->status)
+);
+
+TRACE_EVENT(fence,
+ TP_PROTO(struct fence *fence),
+
+ TP_ARGS(fence),
+
+ TP_STRUCT__entry(
+ __string(timeline, fence->ops->get_timeline_name(fence))
+ __array(char, value, 32)
+ ),
+
+ TP_fast_assign(
+ __assign_str(timeline, fence->ops->get_timeline_name(fence));
+ if (fence->ops->fence_value_str) {
+ fence->ops->fence_value_str(fence, __entry->value,
+ sizeof(__entry->value));
+ } else {
+ __entry->value[0] = '\0';
+ }
+ ),
+
+ TP_printk("name=%s value=%s", __get_str(timeline), __entry->value)
+);
+
+#endif /* if !defined(_TRACE_SYNC_FILE_H) || defined(TRACE_HEADER_MULTI_READ) */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/drivers/staging/android/uapi/sync.h b/include/uapi/linux/sync.h
similarity index 90%
rename from drivers/staging/android/uapi/sync.h
rename to include/uapi/linux/sync.h
index 73deb69..2a8ab04 100644
--- a/drivers/staging/android/uapi/sync.h
+++ b/include/uapi/linux/sync.h
@@ -27,15 +27,15 @@ struct sync_merge_data {
};

/**
- * struct sync_pt_info - detailed sync_pt information
- * @len: length of sync_pt_info including any driver_data
+ * struct fence_info - detailed fence information
+ * @len: length of fence_info including any driver_data
* @obj_name: name of parent sync_timeline
* @driver_name: name of driver implementing the parent
- * @status: status of the sync_pt 0:active 1:signaled <0:error
+ * @status: status of the fence 0:active 1:signaled <0:error
* @timestamp_ns: timestamp of status change in nanoseconds
* @driver_data: any driver dependent data
*/
-struct sync_pt_info {
+struct fence_info {
__u32 len;
char obj_name[32];
char driver_name[32];
@@ -52,14 +52,14 @@ struct sync_pt_info {
* userspace including pt_info.
* @name: name of fence
* @status: status of fence. 1: signaled 0:active <0:error
- * @pt_info: a sync_pt_info struct for every sync_pt in the fence
+ * @fence_info: a fence_info struct for every fence in the sync_file
*/
struct sync_file_info_data {
__u32 len;
char name[32];
__s32 status;

- __u8 pt_info[0];
+ __u8 fence_info[0];
};

#define SYNC_IOC_MAGIC '>'
--
2.5.0