dma-buf/sync-file: Defer creation of sync_file->name
authorChris Wilson <chris@chris-wilson.co.uk>
Tue, 16 May 2017 11:10:42 +0000 (12:10 +0100)
committerGustavo Padovan <gustavo.padovan@collabora.com>
Wed, 24 May 2017 16:08:29 +0000 (13:08 -0300)
Constructing the name takes the majority of the time for allocating a
sync_file to wrap a fence, and the name is very rarely used (only via
the sync_file status user interface). To reduce the impact on the common
path (that of creating sync_file to pass around), defer the construction
of the name until it is first used.

v2: Update kerneldoc (kbuild test robot)
v3: sync_debug.c was peeking at the name
v4: Comment upon the potential race between two users of
sync_file_get_name() and claim that such a race is below the level of
notice. However, to prevent any future nuisance, use a global spinlock
to serialize the assignment of the name.
v5: Completely avoid the read/write race by only storing the name passed
in from the user inside sync_file->user_name and passing in a buffer to
dynamically construct the name otherwise.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Sumit Semwal <sumit.semwal@linaro.org>
Cc: Gustavo Padovan <gustavo@padovan.org>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: David Herrmann <dh.herrmann@gmail.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.com>
Link: http://patchwork.freedesktop.org/patch/msgid/20170516111042.24719-1-chris@chris-wilson.co.uk
drivers/dma-buf/sync_debug.c
drivers/dma-buf/sync_file.c
include/linux/sync_file.h

index a0d780a..82a6e7f 100644 (file)
@@ -132,9 +132,11 @@ 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)
 {
+       char buf[128];
        int i;
 
-       seq_printf(s, "[%p] %s: %s\n", sync_file, sync_file->name,
+       seq_printf(s, "[%p] %s: %s\n", sync_file,
+                  sync_file_get_name(sync_file, buf, sizeof(buf)),
                   sync_status_str(dma_fence_get_status(sync_file->fence)));
 
        if (dma_fence_is_array(sync_file->fence)) {
index dc89b1d..545e2c5 100644 (file)
@@ -80,11 +80,6 @@ struct sync_file *sync_file_create(struct dma_fence *fence)
 
        sync_file->fence = dma_fence_get(fence);
 
-       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);
-
        return sync_file;
 }
 EXPORT_SYMBOL(sync_file_create);
@@ -129,6 +124,36 @@ struct dma_fence *sync_file_get_fence(int fd)
 }
 EXPORT_SYMBOL(sync_file_get_fence);
 
+/**
+ * sync_file_get_name - get the name of the sync_file
+ * @sync_file:         sync_file to get the fence from
+ * @buf:               destination buffer to copy sync_file name into
+ * @len:               available size of destination buffer.
+ *
+ * Each sync_file may have a name assigned either by the user (when merging
+ * sync_files together) or created from the fence it contains. In the latter
+ * case construction of the name is deferred until use, and so requires
+ * sync_file_get_name().
+ *
+ * Returns: a string representing the name.
+ */
+char *sync_file_get_name(struct sync_file *sync_file, char *buf, int len)
+{
+       if (sync_file->user_name[0]) {
+               strlcpy(buf, sync_file->user_name, len);
+       } else {
+               struct dma_fence *fence = sync_file->fence;
+
+               snprintf(buf, len, "%s-%s%llu-%d",
+                        fence->ops->get_driver_name(fence),
+                        fence->ops->get_timeline_name(fence),
+                        fence->context,
+                        fence->seqno);
+       }
+
+       return buf;
+}
+
 static int sync_file_set_fence(struct sync_file *sync_file,
                               struct dma_fence **fences, int num_fences)
 {
@@ -266,7 +291,7 @@ static struct sync_file *sync_file_merge(const char *name, struct sync_file *a,
                goto err;
        }
 
-       strlcpy(sync_file->name, name, sizeof(sync_file->name));
+       strlcpy(sync_file->user_name, name, sizeof(sync_file->user_name));
        return sync_file;
 
 err:
@@ -413,7 +438,7 @@ static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
        }
 
 no_fences:
-       strlcpy(info.name, sync_file->name, sizeof(info.name));
+       sync_file_get_name(sync_file, info.name, sizeof(info.name));
        info.status = dma_fence_is_signaled(sync_file->fence);
        info.num_fences = num_fences;
 
index d37beef..5726107 100644 (file)
@@ -23,7 +23,6 @@
 /**
  * struct sync_file - sync file to export to the userspace
  * @file:              file representing this fence
- * @name:              name of sync_file.  Useful for debugging
  * @sync_file_list:    membership in global file list
  * @wq:                        wait queue for fence signaling
  * @fence:             fence with the fences in the sync_file
  */
 struct sync_file {
        struct file             *file;
-       char                    name[32];
+       /**
+        * @user_name:
+        *
+        * Name of the sync file provided by userspace, for merged fences.
+        * Otherwise generated through driver callbacks (in which case the
+        * entire array is 0).
+        */
+       char                    user_name[32];
 #ifdef CONFIG_DEBUG_FS
        struct list_head        sync_file_list;
 #endif
@@ -46,5 +52,6 @@ struct sync_file {
 
 struct sync_file *sync_file_create(struct dma_fence *fence);
 struct dma_fence *sync_file_get_fence(int fd);
+char *sync_file_get_name(struct sync_file *sync_file, char *buf, int len);
 
 #endif /* _LINUX_SYNC_H */