dma-buf/sync-file: Defer creation of sync_file->name

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
This commit is contained in:
Chris Wilson 2017-05-16 12:10:42 +01:00 committed by Gustavo Padovan
parent c16f291dee
commit 71ebc9a379
3 changed files with 44 additions and 10 deletions

View 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, static void sync_print_sync_file(struct seq_file *s,
struct sync_file *sync_file) struct sync_file *sync_file)
{ {
char buf[128];
int i; 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))); sync_status_str(dma_fence_get_status(sync_file->fence)));
if (dma_fence_is_array(sync_file->fence)) { if (dma_fence_is_array(sync_file->fence)) {

View File

@ -80,11 +80,6 @@ struct sync_file *sync_file_create(struct dma_fence *fence)
sync_file->fence = dma_fence_get(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; return sync_file;
} }
EXPORT_SYMBOL(sync_file_create); EXPORT_SYMBOL(sync_file_create);
@ -129,6 +124,36 @@ struct dma_fence *sync_file_get_fence(int fd)
} }
EXPORT_SYMBOL(sync_file_get_fence); 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, static int sync_file_set_fence(struct sync_file *sync_file,
struct dma_fence **fences, int num_fences) 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; 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; return sync_file;
err: err:
@ -413,7 +438,7 @@ static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
} }
no_fences: 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.status = dma_fence_is_signaled(sync_file->fence);
info.num_fences = num_fences; info.num_fences = num_fences;

View File

@ -23,7 +23,6 @@
/** /**
* struct sync_file - sync file to export to the userspace * struct sync_file - sync file to export to the userspace
* @file: file representing this fence * @file: file representing this fence
* @name: name of sync_file. Useful for debugging
* @sync_file_list: membership in global file list * @sync_file_list: membership in global file list
* @wq: wait queue for fence signaling * @wq: wait queue for fence signaling
* @fence: fence with the fences in the sync_file * @fence: fence with the fences in the sync_file
@ -31,7 +30,14 @@
*/ */
struct sync_file { struct sync_file {
struct file *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 #ifdef CONFIG_DEBUG_FS
struct list_head sync_file_list; struct list_head sync_file_list;
#endif #endif
@ -46,5 +52,6 @@ struct sync_file {
struct sync_file *sync_file_create(struct dma_fence *fence); struct sync_file *sync_file_create(struct dma_fence *fence);
struct dma_fence *sync_file_get_fence(int fd); 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 */ #endif /* _LINUX_SYNC_H */