From: Greg Kroah-Hartman Date: Thu, 7 Dec 2017 10:54:14 +0000 (+0100) Subject: 4.9-stable patches X-Git-Tag: v3.18.87~12 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=722dfc385c167dfcdc43390fa5d3a769c4a254ca;p=thirdparty%2Fkernel%2Fstable-queue.git 4.9-stable patches added patches: dma-buf-dma-fence-extract-__dma_fence_is_later.patch dma-buf-sw-sync-fix-locking-around-sync_timeline-lists.patch dma-buf-sw-sync-fix-the-is-signaled-test-to-handle-u32-wraparound.patch dma-buf-sw-sync-prevent-user-overflow-on-timeline-advance.patch dma-buf-sw-sync-reduce-irqsave-irqrestore-from-known-context.patch dma-buf-sw-sync-sync_pt-is-private-and-of-fixed-size.patch dma-buf-sw-sync-use-an-rbtree-to-sort-fences-in-the-timeline.patch dma-buf-sw_sync-clean-up-list-before-signaling-the-fence.patch dma-buf-sw_sync-force-signal-all-unsignaled-fences-on-dying-timeline.patch dma-buf-sw_sync-move-timeline_fence_ops-around.patch dma-fence-clear-fence-status-during-dma_fence_init.patch dma-fence-introduce-drm_fence_set_error-helper.patch dma-fence-wrap-querying-the-fence-status.patch --- diff --git a/queue-4.9/dma-buf-dma-fence-extract-__dma_fence_is_later.patch b/queue-4.9/dma-buf-dma-fence-extract-__dma_fence_is_later.patch new file mode 100644 index 00000000000..628013f1355 --- /dev/null +++ b/queue-4.9/dma-buf-dma-fence-extract-__dma_fence_is_later.patch @@ -0,0 +1,58 @@ +From 8111477663813caa1a4469cfe6afaae36cd04513 Mon Sep 17 00:00:00 2001 +From: Chris Wilson +Date: Thu, 29 Jun 2017 13:59:24 +0100 +Subject: dma-buf/dma-fence: Extract __dma_fence_is_later() + +From: Chris Wilson + +commit 8111477663813caa1a4469cfe6afaae36cd04513 upstream. + +Often we have the task of comparing two seqno known to be on the same +context, so provide a common __dma_fence_is_later(). + +Signed-off-by: Chris Wilson +Cc: Sumit Semwal +Cc: Sean Paul +Cc: Gustavo Padovan +Reviewed-by: Sean Paul +Signed-off-by: Gustavo Padovan +Link: http://patchwork.freedesktop.org/patch/msgid/20170629125930.821-1-chris@chris-wilson.co.uk +[renamed to __fence_is_later() - gregkh] +Cc: Jisheng Zhang +Signed-off-by: Greg Kroah-Hartman + +--- + include/linux/fence.h | 15 ++++++++++++++- + 1 file changed, 14 insertions(+), 1 deletion(-) + +--- a/include/linux/fence.h ++++ b/include/linux/fence.h +@@ -281,6 +281,19 @@ fence_is_signaled(struct fence *fence) + } + + /** ++ * __fence_is_later - return if f1 is chronologically later than f2 ++ * @f1: [in] the first fence's seqno ++ * @f2: [in] the second fence's seqno from the same context ++ * ++ * Returns true if f1 is chronologically later than f2. Both fences must be ++ * from the same context, since a seqno is not common across contexts. ++ */ ++static inline bool __fence_is_later(u32 f1, u32 f2) ++{ ++ return (int)(f1 - f2) > 0; ++} ++ ++/** + * fence_is_later - return if f1 is chronologically later than f2 + * @f1: [in] the first fence from the same context + * @f2: [in] the second fence from the same context +@@ -293,7 +306,7 @@ static inline bool fence_is_later(struct + if (WARN_ON(f1->context != f2->context)) + return false; + +- return (int)(f1->seqno - f2->seqno) > 0; ++ return __fence_is_later(f1->seqno, f2->seqno); + } + + /** diff --git a/queue-4.9/dma-buf-sw-sync-fix-locking-around-sync_timeline-lists.patch b/queue-4.9/dma-buf-sw-sync-fix-locking-around-sync_timeline-lists.patch new file mode 100644 index 00000000000..a95d2f1e27c --- /dev/null +++ b/queue-4.9/dma-buf-sw-sync-fix-locking-around-sync_timeline-lists.patch @@ -0,0 +1,204 @@ +From d3862e44daa7a0c94d2f6193502a8c49379acfce Mon Sep 17 00:00:00 2001 +From: Chris Wilson +Date: Thu, 29 Jun 2017 22:05:32 +0100 +Subject: dma-buf/sw-sync: Fix locking around sync_timeline lists + +From: Chris Wilson + +commit d3862e44daa7a0c94d2f6193502a8c49379acfce upstream. + +The sync_pt were not adding themselves atomically to the timeline lists, +corruption imminent. Only a single list is required to track the +unsignaled sync_pt, so reduce it and rename the lock more appropriately +along with using idiomatic names to distinguish a list from links along +it. + +v2: Prevent spinlock recursion on free during create (next patch) and +fixup crossref in kerneldoc + +Signed-off-by: Chris Wilson +Cc: Sumit Semwal +Cc: Sean Paul +Cc: Gustavo Padovan +Reviewed-by: Sean Paul +Signed-off-by: Gustavo Padovan +Link: http://patchwork.freedesktop.org/patch/msgid/20170629210532.5617-1-chris@chris-wilson.co.uk +[s/dma_fence/fence/g - gregkh] +Cc: Jisheng Zhang +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/dma-buf/sw_sync.c | 48 +++++++++++++++++-------------------------- + drivers/dma-buf/sync_debug.c | 9 +++----- + drivers/dma-buf/sync_debug.h | 22 +++++++------------ + 3 files changed, 31 insertions(+), 48 deletions(-) + +--- a/drivers/dma-buf/sw_sync.c ++++ b/drivers/dma-buf/sw_sync.c +@@ -96,9 +96,8 @@ struct sync_timeline *sync_timeline_crea + obj->context = fence_context_alloc(1); + strlcpy(obj->name, name, sizeof(obj->name)); + +- INIT_LIST_HEAD(&obj->child_list_head); +- INIT_LIST_HEAD(&obj->active_list_head); +- spin_lock_init(&obj->child_list_lock); ++ INIT_LIST_HEAD(&obj->pt_list); ++ spin_lock_init(&obj->lock); + + sync_timeline_debug_add(obj); + +@@ -139,17 +138,15 @@ static void sync_timeline_signal(struct + + trace_sync_timeline(obj); + +- spin_lock_irq(&obj->child_list_lock); ++ spin_lock_irq(&obj->lock); + + obj->value += inc; + +- list_for_each_entry_safe(pt, next, &obj->active_list_head, +- active_list) { ++ list_for_each_entry_safe(pt, next, &obj->pt_list, link) + if (fence_is_signaled_locked(&pt->base)) +- list_del_init(&pt->active_list); +- } ++ list_del_init(&pt->link); + +- spin_unlock_irq(&obj->child_list_lock); ++ spin_unlock_irq(&obj->lock); + } + + /** +@@ -171,15 +168,15 @@ static struct sync_pt *sync_pt_create(st + if (!pt) + return NULL; + +- spin_lock_irq(&obj->child_list_lock); +- + sync_timeline_get(obj); +- fence_init(&pt->base, &timeline_fence_ops, &obj->child_list_lock, ++ fence_init(&pt->base, &timeline_fence_ops, &obj->lock, + obj->context, value); +- list_add_tail(&pt->child_list, &obj->child_list_head); +- INIT_LIST_HEAD(&pt->active_list); ++ INIT_LIST_HEAD(&pt->link); + +- spin_unlock_irq(&obj->child_list_lock); ++ spin_lock_irq(&obj->lock); ++ if (!fence_is_signaled_locked(&pt->base)) ++ list_add_tail(&pt->link, &obj->pt_list); ++ spin_unlock_irq(&obj->lock); + + return pt; + } +@@ -200,15 +197,15 @@ static void timeline_fence_release(struc + { + struct sync_pt *pt = fence_to_sync_pt(fence); + struct sync_timeline *parent = fence_parent(fence); +- unsigned long flags; + +- spin_lock_irqsave(fence->lock, flags); ++ if (!list_empty(&pt->link)) { ++ unsigned long flags; + +- list_del(&pt->child_list); +- if (!list_empty(&pt->active_list)) +- list_del(&pt->active_list); +- +- spin_unlock_irqrestore(fence->lock, flags); ++ spin_lock_irqsave(fence->lock, flags); ++ if (!list_empty(&pt->link)) ++ list_del(&pt->link); ++ spin_unlock_irqrestore(fence->lock, flags); ++ } + + sync_timeline_put(parent); + fence_free(fence); +@@ -223,13 +220,6 @@ static bool timeline_fence_signaled(stru + + static bool timeline_fence_enable_signaling(struct fence *fence) + { +- struct sync_pt *pt = fence_to_sync_pt(fence); +- struct sync_timeline *parent = fence_parent(fence); +- +- if (timeline_fence_signaled(fence)) +- return false; +- +- list_add_tail(&pt->active_list, &parent->active_list_head); + return true; + } + +--- a/drivers/dma-buf/sync_debug.c ++++ b/drivers/dma-buf/sync_debug.c +@@ -119,13 +119,12 @@ static void sync_print_obj(struct seq_fi + + seq_printf(s, "%s: %d\n", obj->name, obj->value); + +- spin_lock_irq(&obj->child_list_lock); +- list_for_each(pos, &obj->child_list_head) { +- struct sync_pt *pt = +- container_of(pos, struct sync_pt, child_list); ++ spin_lock_irq(&obj->lock); ++ list_for_each(pos, &obj->pt_list) { ++ struct sync_pt *pt = container_of(pos, struct sync_pt, link); + sync_print_fence(s, &pt->base, false); + } +- spin_unlock_irq(&obj->child_list_lock); ++ spin_unlock_irq(&obj->lock); + } + + static void sync_print_sync_file(struct seq_file *s, +--- a/drivers/dma-buf/sync_debug.h ++++ b/drivers/dma-buf/sync_debug.h +@@ -24,43 +24,37 @@ + * struct sync_timeline - sync object + * @kref: reference count on fence. + * @name: name of the sync_timeline. Useful for debugging +- * @child_list_head: list of children sync_pts for this sync_timeline +- * @child_list_lock: lock protecting @child_list_head and fence.status +- * @active_list_head: list of active (unsignaled/errored) sync_pts ++ * @lock: lock protecting @pt_list and @value ++ * @pt_list: list of active (unsignaled/errored) sync_pts + * @sync_timeline_list: membership in global sync_timeline_list + */ + struct sync_timeline { + struct kref kref; + char name[32]; + +- /* protected by child_list_lock */ ++ /* protected by lock */ + u64 context; + int value; + +- struct list_head child_list_head; +- spinlock_t child_list_lock; +- +- struct list_head active_list_head; ++ struct list_head pt_list; ++ spinlock_t lock; + + struct list_head sync_timeline_list; + }; + + static inline struct sync_timeline *fence_parent(struct fence *fence) + { +- return container_of(fence->lock, struct sync_timeline, +- child_list_lock); ++ return container_of(fence->lock, struct sync_timeline, lock); + } + + /** + * struct sync_pt - sync_pt object + * @base: base fence object +- * @child_list: sync timeline child's list +- * @active_list: sync timeline active child's list ++ * @link: link on the sync timeline's list + */ + struct sync_pt { + struct fence base; +- struct list_head child_list; +- struct list_head active_list; ++ struct list_head link; + }; + + #ifdef CONFIG_SW_SYNC diff --git a/queue-4.9/dma-buf-sw-sync-fix-the-is-signaled-test-to-handle-u32-wraparound.patch b/queue-4.9/dma-buf-sw-sync-fix-the-is-signaled-test-to-handle-u32-wraparound.patch new file mode 100644 index 00000000000..820c46f4406 --- /dev/null +++ b/queue-4.9/dma-buf-sw-sync-fix-the-is-signaled-test-to-handle-u32-wraparound.patch @@ -0,0 +1,38 @@ +From 61894b02716f122dd7662d5d89f5b2245ca551e2 Mon Sep 17 00:00:00 2001 +From: Chris Wilson +Date: Thu, 29 Jun 2017 13:59:25 +0100 +Subject: dma-buf/sw-sync: Fix the is-signaled test to handle u32 wraparound + +From: Chris Wilson + +commit 61894b02716f122dd7662d5d89f5b2245ca551e2 upstream. + +Use the canonical __dma_fence_is_later() to compare the fence seqno +against the timeline seqno to check if the fence is signaled. + +Signed-off-by: Chris Wilson +Cc: Sumit Semwal +Cc: Sean Paul +Cc: Gustavo Padovan +Reviewed-by: Sean Paul +Signed-off-by: Gustavo Padovan +Link: http://patchwork.freedesktop.org/patch/msgid/20170629125930.821-2-chris@chris-wilson.co.uk +[s/dma_fence/fence/g - gregkh] +Cc: Jisheng Zhang +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/dma-buf/sw_sync.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/dma-buf/sw_sync.c ++++ b/drivers/dma-buf/sw_sync.c +@@ -219,7 +219,7 @@ static bool timeline_fence_signaled(stru + { + struct sync_timeline *parent = fence_parent(fence); + +- return (fence->seqno > parent->value) ? false : true; ++ return !__fence_is_later(fence->seqno, parent->value); + } + + static bool timeline_fence_enable_signaling(struct fence *fence) diff --git a/queue-4.9/dma-buf-sw-sync-prevent-user-overflow-on-timeline-advance.patch b/queue-4.9/dma-buf-sw-sync-prevent-user-overflow-on-timeline-advance.patch new file mode 100644 index 00000000000..0f530d82f30 --- /dev/null +++ b/queue-4.9/dma-buf-sw-sync-prevent-user-overflow-on-timeline-advance.patch @@ -0,0 +1,41 @@ +From 8f66d3aa1735bc95ae58d846a157357e8d41abb8 Mon Sep 17 00:00:00 2001 +From: Chris Wilson +Date: Thu, 29 Jun 2017 13:59:26 +0100 +Subject: dma-buf/sw-sync: Prevent user overflow on timeline advance + +From: Chris Wilson + +commit 8f66d3aa1735bc95ae58d846a157357e8d41abb8 upstream. + +The timeline is u32, which limits any single advance to INT_MAX so that +we can detect all fences that need signaling. + +Signed-off-by: Chris Wilson +Cc: Sumit Semwal +Cc: Sean Paul +Cc: Gustavo Padovan +Reviewed-by: Sean Paul +Signed-off-by: Gustavo Padovan +Link: http://patchwork.freedesktop.org/patch/msgid/20170629125930.821-3-chris@chris-wilson.co.uk +[s/dma_fence/fence/g - gregkh] +Cc: Jisheng Zhang +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/dma-buf/sw_sync.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/drivers/dma-buf/sw_sync.c ++++ b/drivers/dma-buf/sw_sync.c +@@ -345,6 +345,11 @@ static long sw_sync_ioctl_inc(struct syn + if (copy_from_user(&value, (void __user *)arg, sizeof(value))) + return -EFAULT; + ++ while (value > INT_MAX) { ++ sync_timeline_signal(obj, INT_MAX); ++ value -= INT_MAX; ++ } ++ + sync_timeline_signal(obj, value); + + return 0; diff --git a/queue-4.9/dma-buf-sw-sync-reduce-irqsave-irqrestore-from-known-context.patch b/queue-4.9/dma-buf-sw-sync-reduce-irqsave-irqrestore-from-known-context.patch new file mode 100644 index 00000000000..247511fcc00 --- /dev/null +++ b/queue-4.9/dma-buf-sw-sync-reduce-irqsave-irqrestore-from-known-context.patch @@ -0,0 +1,151 @@ +From a6aa8fca4d792c72947e341d7842d2f700534335 Mon Sep 17 00:00:00 2001 +From: Chris Wilson +Date: Thu, 29 Jun 2017 13:59:27 +0100 +Subject: dma-buf/sw-sync: Reduce irqsave/irqrestore from known context + +From: Chris Wilson + +commit a6aa8fca4d792c72947e341d7842d2f700534335 upstream. + +If we know the context under which we are called, then we can use the +simpler form of spin_lock_irq (saving the save/restore). + +Signed-off-by: Chris Wilson +Cc: Sumit Semwal +Cc: Sean Paul +Cc: Gustavo Padovan +Reviewed-by: Sean Paul +Signed-off-by: Gustavo Padovan +Link: http://patchwork.freedesktop.org/patch/msgid/20170629125930.821-4-chris@chris-wilson.co.uk +[s/dma_fence/fence/g - gregkh] +Cc: Jisheng Zhang +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/dma-buf/sw_sync.c | 15 +++++++++------ + drivers/dma-buf/sync_debug.c | 14 ++++++-------- + 2 files changed, 15 insertions(+), 14 deletions(-) + +--- a/drivers/dma-buf/sw_sync.c ++++ b/drivers/dma-buf/sw_sync.c +@@ -135,12 +135,11 @@ static void sync_timeline_put(struct syn + */ + static void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc) + { +- unsigned long flags; + struct sync_pt *pt, *next; + + trace_sync_timeline(obj); + +- spin_lock_irqsave(&obj->child_list_lock, flags); ++ spin_lock_irq(&obj->child_list_lock); + + obj->value += inc; + +@@ -150,7 +149,7 @@ static void sync_timeline_signal(struct + list_del_init(&pt->active_list); + } + +- spin_unlock_irqrestore(&obj->child_list_lock, flags); ++ spin_unlock_irq(&obj->child_list_lock); + } + + /** +@@ -167,7 +166,6 @@ static void sync_timeline_signal(struct + static struct sync_pt *sync_pt_create(struct sync_timeline *obj, int size, + unsigned int value) + { +- unsigned long flags; + struct sync_pt *pt; + + if (size < sizeof(*pt)) +@@ -177,13 +175,16 @@ static struct sync_pt *sync_pt_create(st + if (!pt) + return NULL; + +- spin_lock_irqsave(&obj->child_list_lock, flags); ++ spin_lock_irq(&obj->child_list_lock); ++ + sync_timeline_get(obj); + fence_init(&pt->base, &timeline_fence_ops, &obj->child_list_lock, + obj->context, value); + list_add_tail(&pt->child_list, &obj->child_list_head); + INIT_LIST_HEAD(&pt->active_list); +- spin_unlock_irqrestore(&obj->child_list_lock, flags); ++ ++ spin_unlock_irq(&obj->child_list_lock); ++ + return pt; + } + +@@ -206,9 +207,11 @@ static void timeline_fence_release(struc + unsigned long flags; + + spin_lock_irqsave(fence->lock, flags); ++ + list_del(&pt->child_list); + if (!list_empty(&pt->active_list)) + list_del(&pt->active_list); ++ + spin_unlock_irqrestore(fence->lock, flags); + + sync_timeline_put(parent); +--- a/drivers/dma-buf/sync_debug.c ++++ b/drivers/dma-buf/sync_debug.c +@@ -116,17 +116,16 @@ static void sync_print_fence(struct seq_ + static void sync_print_obj(struct seq_file *s, struct sync_timeline *obj) + { + struct list_head *pos; +- unsigned long flags; + + seq_printf(s, "%s: %d\n", obj->name, obj->value); + +- spin_lock_irqsave(&obj->child_list_lock, flags); ++ spin_lock_irq(&obj->child_list_lock); + list_for_each(pos, &obj->child_list_head) { + struct sync_pt *pt = + container_of(pos, struct sync_pt, child_list); + sync_print_fence(s, &pt->base, false); + } +- spin_unlock_irqrestore(&obj->child_list_lock, flags); ++ spin_unlock_irq(&obj->child_list_lock); + } + + static void sync_print_sync_file(struct seq_file *s, +@@ -149,12 +148,11 @@ static void sync_print_sync_file(struct + + static int sync_debugfs_show(struct seq_file *s, void *unused) + { +- unsigned long flags; + struct list_head *pos; + + seq_puts(s, "objs:\n--------------\n"); + +- spin_lock_irqsave(&sync_timeline_list_lock, flags); ++ spin_lock_irq(&sync_timeline_list_lock); + list_for_each(pos, &sync_timeline_list_head) { + struct sync_timeline *obj = + container_of(pos, struct sync_timeline, +@@ -163,11 +161,11 @@ static int sync_debugfs_show(struct seq_ + sync_print_obj(s, obj); + seq_puts(s, "\n"); + } +- spin_unlock_irqrestore(&sync_timeline_list_lock, flags); ++ spin_unlock_irq(&sync_timeline_list_lock); + + seq_puts(s, "fences:\n--------------\n"); + +- spin_lock_irqsave(&sync_file_list_lock, flags); ++ spin_lock_irq(&sync_file_list_lock); + list_for_each(pos, &sync_file_list_head) { + struct sync_file *sync_file = + container_of(pos, struct sync_file, sync_file_list); +@@ -175,7 +173,7 @@ static int sync_debugfs_show(struct seq_ + sync_print_sync_file(s, sync_file); + seq_puts(s, "\n"); + } +- spin_unlock_irqrestore(&sync_file_list_lock, flags); ++ spin_unlock_irq(&sync_file_list_lock); + return 0; + } + diff --git a/queue-4.9/dma-buf-sw-sync-sync_pt-is-private-and-of-fixed-size.patch b/queue-4.9/dma-buf-sw-sync-sync_pt-is-private-and-of-fixed-size.patch new file mode 100644 index 00000000000..9cbc3988db5 --- /dev/null +++ b/queue-4.9/dma-buf-sw-sync-sync_pt-is-private-and-of-fixed-size.patch @@ -0,0 +1,66 @@ +From 3b52ce44e720c240afc4c4b03140d7b7811b23bd Mon Sep 17 00:00:00 2001 +From: Chris Wilson +Date: Thu, 29 Jun 2017 13:59:28 +0100 +Subject: dma-buf/sw-sync: sync_pt is private and of fixed size + +From: Chris Wilson + +commit 3b52ce44e720c240afc4c4b03140d7b7811b23bd upstream. + +Since sync_pt is only allocated from a single location and is no longer +the base class for fences (that is struct dma_fence) it no longer needs +a generic unsized allocator. + +Signed-off-by: Chris Wilson +Cc: Sumit Semwal +Cc: Sean Paul +Cc: Gustavo Padovan +Reviewed-by: Sean Paul +Signed-off-by: Gustavo Padovan +Link: http://patchwork.freedesktop.org/patch/msgid/20170629125930.821-5-chris@chris-wilson.co.uk +[s/dma_fence/fence/g - gregkh] +Cc: Jisheng Zhang +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/dma-buf/sw_sync.c | 12 ++++-------- + 1 file changed, 4 insertions(+), 8 deletions(-) + +--- a/drivers/dma-buf/sw_sync.c ++++ b/drivers/dma-buf/sw_sync.c +@@ -155,7 +155,6 @@ static void sync_timeline_signal(struct + /** + * sync_pt_create() - creates a sync pt + * @parent: fence's parent sync_timeline +- * @size: size to allocate for this pt + * @inc: value of the fence + * + * Creates a new sync_pt as a child of @parent. @size bytes will be +@@ -163,15 +162,12 @@ static void sync_timeline_signal(struct + * the generic sync_timeline struct. Returns the sync_pt object or + * NULL in case of error. + */ +-static struct sync_pt *sync_pt_create(struct sync_timeline *obj, int size, +- unsigned int value) ++static struct sync_pt *sync_pt_create(struct sync_timeline *obj, ++ unsigned int value) + { + struct sync_pt *pt; + +- if (size < sizeof(*pt)) +- return NULL; +- +- pt = kzalloc(size, GFP_KERNEL); ++ pt = kzalloc(sizeof(*pt), GFP_KERNEL); + if (!pt) + return NULL; + +@@ -312,7 +308,7 @@ static long sw_sync_ioctl_create_fence(s + goto err; + } + +- pt = sync_pt_create(obj, sizeof(*pt), data.value); ++ pt = sync_pt_create(obj, data.value); + if (!pt) { + err = -ENOMEM; + goto err; diff --git a/queue-4.9/dma-buf-sw-sync-use-an-rbtree-to-sort-fences-in-the-timeline.patch b/queue-4.9/dma-buf-sw-sync-use-an-rbtree-to-sort-fences-in-the-timeline.patch new file mode 100644 index 00000000000..eac669f902a --- /dev/null +++ b/queue-4.9/dma-buf-sw-sync-use-an-rbtree-to-sort-fences-in-the-timeline.patch @@ -0,0 +1,150 @@ +From f1e8c67123cf171e2b0357e885e426328b241d7d Mon Sep 17 00:00:00 2001 +From: Chris Wilson +Date: Thu, 29 Jun 2017 22:12:53 +0100 +Subject: dma-buf/sw-sync: Use an rbtree to sort fences in the timeline + +From: Chris Wilson + +commit f1e8c67123cf171e2b0357e885e426328b241d7d upstream. + +Reduce the list iteration when incrementing the timeline by storing the +fences in increasing order. + +v2: Prevent spinlock recursion on free during create +v3: Fixup rebase conflict inside comments that escaped the compiler. + +Signed-off-by: Chris Wilson +Cc: Sumit Semwal +Cc: Sean Paul +Cc: Gustavo Padovan +Reviewed-by: Sean Paul +Signed-off-by: Gustavo Padovan +Link: http://patchwork.freedesktop.org/patch/msgid/20170629211253.22766-1-chris@chris-wilson.co.uk +[s/dma_fence/fence/g - gregkh] +Cc: Jisheng Zhang +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/dma-buf/sw_sync.c | 49 +++++++++++++++++++++++++++++++++++++------ + drivers/dma-buf/sync_debug.h | 5 ++++ + 2 files changed, 48 insertions(+), 6 deletions(-) + +--- a/drivers/dma-buf/sw_sync.c ++++ b/drivers/dma-buf/sw_sync.c +@@ -96,6 +96,7 @@ struct sync_timeline *sync_timeline_crea + obj->context = fence_context_alloc(1); + strlcpy(obj->name, name, sizeof(obj->name)); + ++ obj->pt_tree = RB_ROOT; + INIT_LIST_HEAD(&obj->pt_list); + spin_lock_init(&obj->lock); + +@@ -142,9 +143,13 @@ static void sync_timeline_signal(struct + + obj->value += inc; + +- list_for_each_entry_safe(pt, next, &obj->pt_list, link) +- if (fence_is_signaled_locked(&pt->base)) +- list_del_init(&pt->link); ++ list_for_each_entry_safe(pt, next, &obj->pt_list, link) { ++ if (!fence_is_signaled_locked(&pt->base)) ++ break; ++ ++ list_del_init(&pt->link); ++ rb_erase(&pt->node, &obj->pt_tree); ++ } + + spin_unlock_irq(&obj->lock); + } +@@ -174,8 +179,38 @@ static struct sync_pt *sync_pt_create(st + INIT_LIST_HEAD(&pt->link); + + spin_lock_irq(&obj->lock); +- if (!fence_is_signaled_locked(&pt->base)) +- list_add_tail(&pt->link, &obj->pt_list); ++ if (!fence_is_signaled_locked(&pt->base)) { ++ struct rb_node **p = &obj->pt_tree.rb_node; ++ struct rb_node *parent = NULL; ++ ++ while (*p) { ++ struct sync_pt *other; ++ int cmp; ++ ++ parent = *p; ++ other = rb_entry(parent, typeof(*pt), node); ++ cmp = value - other->base.seqno; ++ if (cmp > 0) { ++ p = &parent->rb_right; ++ } else if (cmp < 0) { ++ p = &parent->rb_left; ++ } else { ++ if (fence_get_rcu(&other->base)) { ++ fence_put(&pt->base); ++ pt = other; ++ goto unlock; ++ } ++ p = &parent->rb_left; ++ } ++ } ++ rb_link_node(&pt->node, parent, p); ++ rb_insert_color(&pt->node, &obj->pt_tree); ++ ++ parent = rb_next(&pt->node); ++ list_add_tail(&pt->link, ++ parent ? &rb_entry(parent, typeof(*pt), node)->link : &obj->pt_list); ++ } ++unlock: + spin_unlock_irq(&obj->lock); + + return pt; +@@ -202,8 +237,10 @@ static void timeline_fence_release(struc + unsigned long flags; + + spin_lock_irqsave(fence->lock, flags); +- if (!list_empty(&pt->link)) ++ if (!list_empty(&pt->link)) { + list_del(&pt->link); ++ rb_erase(&pt->node, &parent->pt_tree); ++ } + spin_unlock_irqrestore(fence->lock, flags); + } + +--- a/drivers/dma-buf/sync_debug.h ++++ b/drivers/dma-buf/sync_debug.h +@@ -14,6 +14,7 @@ + #define _LINUX_SYNC_H + + #include ++#include + #include + #include + +@@ -25,6 +26,7 @@ + * @kref: reference count on fence. + * @name: name of the sync_timeline. Useful for debugging + * @lock: lock protecting @pt_list and @value ++ * @pt_tree: rbtree of active (unsignaled/errored) sync_pts + * @pt_list: list of active (unsignaled/errored) sync_pts + * @sync_timeline_list: membership in global sync_timeline_list + */ +@@ -36,6 +38,7 @@ struct sync_timeline { + u64 context; + int value; + ++ struct rb_root pt_tree; + struct list_head pt_list; + spinlock_t lock; + +@@ -51,10 +54,12 @@ static inline struct sync_timeline *fenc + * struct sync_pt - sync_pt object + * @base: base fence object + * @link: link on the sync timeline's list ++ * @node: node in the sync timeline's tree + */ + struct sync_pt { + struct fence base; + struct list_head link; ++ struct rb_node node; + }; + + #ifdef CONFIG_SW_SYNC diff --git a/queue-4.9/dma-buf-sw_sync-clean-up-list-before-signaling-the-fence.patch b/queue-4.9/dma-buf-sw_sync-clean-up-list-before-signaling-the-fence.patch new file mode 100644 index 00000000000..9046701c26a --- /dev/null +++ b/queue-4.9/dma-buf-sw_sync-clean-up-list-before-signaling-the-fence.patch @@ -0,0 +1,59 @@ +From 3792b7c1a70815fe4e954221c096f9278638fd21 Mon Sep 17 00:00:00 2001 +From: Gustavo Padovan +Date: Sat, 29 Jul 2017 12:22:16 -0300 +Subject: dma-buf/sw_sync: clean up list before signaling the fence + +From: Gustavo Padovan + +commit 3792b7c1a70815fe4e954221c096f9278638fd21 upstream. + +If userspace already dropped its own reference by closing the sw_sync +fence fd we might end up in a deadlock where +dma_fence_is_signaled_locked() will trigger the release of the fence and +thus try to hold the lock to remove the fence from the list. + +dma_fence_is_signaled_locked() tries to release/free the fence and hold +the lock in the process. + +We fix that by changing the order operation and clean up the list and +rb-tree first. + +v2: Drop fence get/put dance and manipulate the list first (Chris Wilson) + +Cc: Chris Wilson +Signed-off-by: Gustavo Padovan +Reviewed-by: Chris Wilson +Link: https://patchwork.freedesktop.org/patch/msgid/20170729152217.8362-2-gustavo@padovan.org +[s/dma_fence/fence/g - gregkh] +Cc: Jisheng Zhang +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/dma-buf/sw_sync.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +--- a/drivers/dma-buf/sw_sync.c ++++ b/drivers/dma-buf/sw_sync.c +@@ -213,11 +213,21 @@ static void sync_timeline_signal(struct + obj->value += inc; + + list_for_each_entry_safe(pt, next, &obj->pt_list, link) { +- if (!fence_is_signaled_locked(&pt->base)) ++ if (!timeline_fence_signaled(&pt->base)) + break; + + list_del_init(&pt->link); + rb_erase(&pt->node, &obj->pt_tree); ++ ++ /* ++ * A signal callback may release the last reference to this ++ * fence, causing it to be freed. That operation has to be ++ * last to avoid a use after free inside this loop, and must ++ * be after we remove the fence from the timeline in order to ++ * prevent deadlocking on timeline->lock inside ++ * timeline_fence_release(). ++ */ ++ fence_signal_locked(&pt->base); + } + + spin_unlock_irq(&obj->lock); diff --git a/queue-4.9/dma-buf-sw_sync-force-signal-all-unsignaled-fences-on-dying-timeline.patch b/queue-4.9/dma-buf-sw_sync-force-signal-all-unsignaled-fences-on-dying-timeline.patch new file mode 100644 index 00000000000..a7f444d9aab --- /dev/null +++ b/queue-4.9/dma-buf-sw_sync-force-signal-all-unsignaled-fences-on-dying-timeline.patch @@ -0,0 +1,51 @@ +From ea4d5a270b57fa8d4871f372ca9b97b7697fdfda Mon Sep 17 00:00:00 2001 +From: Dominik Behr +Date: Thu, 7 Sep 2017 16:02:46 -0300 +Subject: dma-buf/sw_sync: force signal all unsignaled fences on dying timeline + +From: Dominik Behr + +commit ea4d5a270b57fa8d4871f372ca9b97b7697fdfda upstream. + +To avoid hanging userspace components that might have been waiting on the +active fences of the destroyed timeline we need to signal with error all +remaining fences on such timeline. + +This restore the default behaviour of the Android sw_sync framework, which +Android still relies on. It was broken on the dma fence conversion a few +years ago and never fixed. + +v2: Do not bother with cleanup do the list (Chris Wilson) + +Reviewed-by: Chris Wilson +Signed-off-by: Dominik Behr +Signed-off-by: Gustavo Padovan +Link: https://patchwork.freedesktop.org/patch/msgid/20170907190246.16425-2-gustavo@padovan.org +[s/dma_fence/fence/g - gregkh] +Cc: Jisheng Zhang +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/dma-buf/sw_sync.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +--- a/drivers/dma-buf/sw_sync.c ++++ b/drivers/dma-buf/sw_sync.c +@@ -321,8 +321,16 @@ static int sw_sync_debugfs_open(struct i + static int sw_sync_debugfs_release(struct inode *inode, struct file *file) + { + struct sync_timeline *obj = file->private_data; ++ struct sync_pt *pt, *next; + +- smp_wmb(); ++ spin_lock_irq(&obj->lock); ++ ++ list_for_each_entry_safe(pt, next, &obj->pt_list, link) { ++ fence_set_error(&pt->base, -ENOENT); ++ fence_signal_locked(&pt->base); ++ } ++ ++ spin_unlock_irq(&obj->lock); + + sync_timeline_put(obj); + return 0; diff --git a/queue-4.9/dma-buf-sw_sync-move-timeline_fence_ops-around.patch b/queue-4.9/dma-buf-sw_sync-move-timeline_fence_ops-around.patch new file mode 100644 index 00000000000..ed44edb2775 --- /dev/null +++ b/queue-4.9/dma-buf-sw_sync-move-timeline_fence_ops-around.patch @@ -0,0 +1,178 @@ +From 150b6a9d7d6fffb95c0a5349960a10569e8218b5 Mon Sep 17 00:00:00 2001 +From: Gustavo Padovan +Date: Sat, 29 Jul 2017 12:22:15 -0300 +Subject: dma-buf/sw_sync: move timeline_fence_ops around + +From: Gustavo Padovan + +commit 150b6a9d7d6fffb95c0a5349960a10569e8218b5 upstream. + +We are going to use timeline_fence_signaled() in a internal function in +the next commit. + +Cc: Chris Wilson +Signed-off-by: Gustavo Padovan +Reviewed-by: Chris Wilson +Link: https://patchwork.freedesktop.org/patch/msgid/20170729152217.8362-1-gustavo@padovan.org +[s/dma_fence/fence/g - gregkh] +Cc: Jisheng Zhang +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/dma-buf/sw_sync.c | 138 +++++++++++++++++++++++----------------------- + 1 file changed, 69 insertions(+), 69 deletions(-) + +--- a/drivers/dma-buf/sw_sync.c ++++ b/drivers/dma-buf/sw_sync.c +@@ -125,6 +125,75 @@ static void sync_timeline_put(struct syn + kref_put(&obj->kref, sync_timeline_free); + } + ++static const char *timeline_fence_get_driver_name(struct fence *fence) ++{ ++ return "sw_sync"; ++} ++ ++static const char *timeline_fence_get_timeline_name(struct fence *fence) ++{ ++ struct sync_timeline *parent = fence_parent(fence); ++ ++ return parent->name; ++} ++ ++static void timeline_fence_release(struct fence *fence) ++{ ++ struct sync_pt *pt = fence_to_sync_pt(fence); ++ struct sync_timeline *parent = fence_parent(fence); ++ ++ if (!list_empty(&pt->link)) { ++ unsigned long flags; ++ ++ spin_lock_irqsave(fence->lock, flags); ++ if (!list_empty(&pt->link)) { ++ list_del(&pt->link); ++ rb_erase(&pt->node, &parent->pt_tree); ++ } ++ spin_unlock_irqrestore(fence->lock, flags); ++ } ++ ++ sync_timeline_put(parent); ++ fence_free(fence); ++} ++ ++static bool timeline_fence_signaled(struct fence *fence) ++{ ++ struct sync_timeline *parent = fence_parent(fence); ++ ++ return !__fence_is_later(fence->seqno, parent->value); ++} ++ ++static bool timeline_fence_enable_signaling(struct fence *fence) ++{ ++ return true; ++} ++ ++static void timeline_fence_value_str(struct fence *fence, ++ char *str, int size) ++{ ++ snprintf(str, size, "%d", fence->seqno); ++} ++ ++static void timeline_fence_timeline_value_str(struct fence *fence, ++ char *str, int size) ++{ ++ struct sync_timeline *parent = fence_parent(fence); ++ ++ snprintf(str, size, "%d", parent->value); ++} ++ ++static const struct fence_ops timeline_fence_ops = { ++ .get_driver_name = timeline_fence_get_driver_name, ++ .get_timeline_name = timeline_fence_get_timeline_name, ++ .enable_signaling = timeline_fence_enable_signaling, ++ .signaled = timeline_fence_signaled, ++ .wait = fence_default_wait, ++ .release = timeline_fence_release, ++ .fence_value_str = timeline_fence_value_str, ++ .timeline_value_str = timeline_fence_timeline_value_str, ++}; ++ + /** + * sync_timeline_signal() - signal a status change on a sync_timeline + * @obj: sync_timeline to signal +@@ -216,75 +285,6 @@ unlock: + return pt; + } + +-static const char *timeline_fence_get_driver_name(struct fence *fence) +-{ +- return "sw_sync"; +-} +- +-static const char *timeline_fence_get_timeline_name(struct fence *fence) +-{ +- struct sync_timeline *parent = fence_parent(fence); +- +- return parent->name; +-} +- +-static void timeline_fence_release(struct fence *fence) +-{ +- struct sync_pt *pt = fence_to_sync_pt(fence); +- struct sync_timeline *parent = fence_parent(fence); +- +- if (!list_empty(&pt->link)) { +- unsigned long flags; +- +- spin_lock_irqsave(fence->lock, flags); +- if (!list_empty(&pt->link)) { +- list_del(&pt->link); +- rb_erase(&pt->node, &parent->pt_tree); +- } +- spin_unlock_irqrestore(fence->lock, flags); +- } +- +- sync_timeline_put(parent); +- fence_free(fence); +-} +- +-static bool timeline_fence_signaled(struct fence *fence) +-{ +- struct sync_timeline *parent = fence_parent(fence); +- +- return !__fence_is_later(fence->seqno, parent->value); +-} +- +-static bool timeline_fence_enable_signaling(struct fence *fence) +-{ +- return true; +-} +- +-static void timeline_fence_value_str(struct fence *fence, +- char *str, int size) +-{ +- snprintf(str, size, "%d", fence->seqno); +-} +- +-static void timeline_fence_timeline_value_str(struct fence *fence, +- char *str, int size) +-{ +- struct sync_timeline *parent = fence_parent(fence); +- +- snprintf(str, size, "%d", parent->value); +-} +- +-static const struct fence_ops timeline_fence_ops = { +- .get_driver_name = timeline_fence_get_driver_name, +- .get_timeline_name = timeline_fence_get_timeline_name, +- .enable_signaling = timeline_fence_enable_signaling, +- .signaled = timeline_fence_signaled, +- .wait = fence_default_wait, +- .release = timeline_fence_release, +- .fence_value_str = timeline_fence_value_str, +- .timeline_value_str = timeline_fence_timeline_value_str, +-}; +- + /* + * *WARNING* + * diff --git a/queue-4.9/dma-fence-clear-fence-status-during-dma_fence_init.patch b/queue-4.9/dma-fence-clear-fence-status-during-dma_fence_init.patch new file mode 100644 index 00000000000..39da2412f95 --- /dev/null +++ b/queue-4.9/dma-fence-clear-fence-status-during-dma_fence_init.patch @@ -0,0 +1,38 @@ +From 83dd1376fd92f33bdeca9e83d479534a4e7f870b Mon Sep 17 00:00:00 2001 +From: Chris Wilson +Date: Wed, 4 Jan 2017 14:12:20 +0000 +Subject: dma-fence: Clear fence->status during dma_fence_init() + +From: Chris Wilson + +commit 83dd1376fd92f33bdeca9e83d479534a4e7f870b upstream. + +As the fence->status is an optional field that may be set before +dma_fence_signal() is called to convey that the fence completed with an +error, we have to ensure that it is always set to zero on initialisation +so that the typical use (i.e. unset) always flags a successful completion. + +Signed-off-by: Chris Wilson +Reviewed-by: Tvrtko Ursulin +Reviewed-by: Daniel Vetter +Reviewed-by: Sumit Semwal +Signed-off-by: Sumit Semwal +Link: http://patchwork.freedesktop.org/patch/msgid/20170104141222.6992-1-chris@chris-wilson.co.uk +[s/dma_fence/fence/g - gregkh] +Cc: Jisheng Zhang +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/dma-buf/fence.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/dma-buf/fence.c ++++ b/drivers/dma-buf/fence.c +@@ -526,6 +526,7 @@ fence_init(struct fence *fence, const st + fence->context = context; + fence->seqno = seqno; + fence->flags = 0UL; ++ fence->status = 0; + + trace_fence_init(fence); + } diff --git a/queue-4.9/dma-fence-introduce-drm_fence_set_error-helper.patch b/queue-4.9/dma-fence-introduce-drm_fence_set_error-helper.patch new file mode 100644 index 00000000000..f7447310619 --- /dev/null +++ b/queue-4.9/dma-fence-introduce-drm_fence_set_error-helper.patch @@ -0,0 +1,119 @@ +From a009e975da5c7d42a7f5eaadc54946eb5f76c9af Mon Sep 17 00:00:00 2001 +From: Chris Wilson +Date: Wed, 4 Jan 2017 14:12:22 +0000 +Subject: dma-fence: Introduce drm_fence_set_error() helper + +From: Chris Wilson + +commit a009e975da5c7d42a7f5eaadc54946eb5f76c9af upstream. + +The dma_fence.error field (formerly known as dma_fence.status) is an +optional field that may be set by drivers before calling +dma_fence_signal(). The field can be used to indicate that the fence was +completed in err rather than with success, and is visible to other +consumers of the fence and to userspace via sync_file. + +This patch renames the field from status to error so that its meaning is +hopefully more clear (and distinct from dma_fence_get_status() which is +a composite between the error state and signal state) and adds a helper +that validates the preconditions of when it is suitable to adjust the +error field. + +Signed-off-by: Chris Wilson +Reviewed-by: Daniel Vetter +Reviewed-by: Sumit Semwal +Signed-off-by: Sumit Semwal +Link: http://patchwork.freedesktop.org/patch/msgid/20170104141222.6992-3-chris@chris-wilson.co.uk +[s/dma_fence/fence/g - gregkh] +Cc: Jisheng Zhang +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/dma-buf/fence.c | 2 +- + include/linux/fence.h | 30 +++++++++++++++++++++++++----- + 2 files changed, 26 insertions(+), 6 deletions(-) + +--- a/drivers/dma-buf/fence.c ++++ b/drivers/dma-buf/fence.c +@@ -551,7 +551,7 @@ fence_init(struct fence *fence, const st + fence->context = context; + fence->seqno = seqno; + fence->flags = 0UL; +- fence->status = 0; ++ fence->error = 0; + + trace_fence_init(fence); + } +--- a/include/linux/fence.h ++++ b/include/linux/fence.h +@@ -47,7 +47,7 @@ struct fence_cb; + * can be compared to decide which fence would be signaled later. + * @flags: A mask of FENCE_FLAG_* defined below + * @timestamp: Timestamp when the fence was signaled. +- * @status: Optional, only valid if < 0, must be set before calling ++ * @error: Optional, only valid if < 0, must be set before calling + * fence_signal, indicates that the fence has completed with an error. + * + * the flags member must be manipulated and read using the appropriate +@@ -79,7 +79,7 @@ struct fence { + unsigned seqno; + unsigned long flags; + ktime_t timestamp; +- int status; ++ int error; + }; + + enum fence_flag_bits { +@@ -132,7 +132,7 @@ struct fence_cb { + * or some failure occurred that made it impossible to enable + * signaling. True indicates successful enabling. + * +- * fence->status may be set in enable_signaling, but only when false is ++ * fence->error may be set in enable_signaling, but only when false is + * returned. + * + * Calling fence_signal before enable_signaling is called allows +@@ -144,7 +144,7 @@ struct fence_cb { + * the second time will be a noop since it was already signaled. + * + * Notes on signaled: +- * May set fence->status if returning true. ++ * May set fence->error if returning true. + * + * Notes on wait: + * Must not be NULL, set to fence_default_wait for default implementation. +@@ -351,13 +351,33 @@ static inline struct fence *fence_later( + static inline int fence_get_status_locked(struct fence *fence) + { + if (fence_is_signaled_locked(fence)) +- return fence->status < 0 ? fence->status : 1; ++ return fence->error ?: 1; + else + return 0; + } + + int fence_get_status(struct fence *fence); + ++/** ++ * fence_set_error - flag an error condition on the fence ++ * @fence: [in] the fence ++ * @error: [in] the error to store ++ * ++ * Drivers can supply an optional error status condition before they signal ++ * the fence, to indicate that the fence was completed due to an error ++ * rather than success. This must be set before signaling (so that the value ++ * is visible before any waiters on the signal callback are woken). This ++ * helper exists to help catching erroneous setting of #fence.error. ++ */ ++static inline void fence_set_error(struct fence *fence, ++ int error) ++{ ++ BUG_ON(test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->flags)); ++ BUG_ON(error >= 0 || error < -MAX_ERRNO); ++ ++ fence->error = error; ++} ++ + signed long fence_wait_timeout(struct fence *, bool intr, signed long timeout); + signed long fence_wait_any_timeout(struct fence **fences, uint32_t count, + bool intr, signed long timeout); diff --git a/queue-4.9/dma-fence-wrap-querying-the-fence-status.patch b/queue-4.9/dma-fence-wrap-querying-the-fence-status.patch new file mode 100644 index 00000000000..7615a7e8439 --- /dev/null +++ b/queue-4.9/dma-fence-wrap-querying-the-fence-status.patch @@ -0,0 +1,163 @@ +From d6c99f4bf093a58d3ab47caaec74b81f18bc4e3f Mon Sep 17 00:00:00 2001 +From: Chris Wilson +Date: Wed, 4 Jan 2017 14:12:21 +0000 +Subject: dma-fence: Wrap querying the fence->status + +From: Chris Wilson + +commit d6c99f4bf093a58d3ab47caaec74b81f18bc4e3f upstream. + +The fence->status is an optional field that is only valid once the fence +has been signaled. (Driver may fill the fence->status with an error code +prior to calling dma_fence_signal().) Given the restriction upon its +validity, wrap querying of the fence->status into a helper +dma_fence_get_status(). + +Signed-off-by: Chris Wilson +Reviewed-by: Daniel Vetter +Reviewed-by: Sumit Semwal +Signed-off-by: Sumit Semwal +Link: http://patchwork.freedesktop.org/patch/msgid/20170104141222.6992-2-chris@chris-wilson.co.uk +[s/dma_fence/fence/g - gregkh] +Cc: Jisheng Zhang +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/dma-buf/fence.c | 25 +++++++++++++++++++++++++ + drivers/dma-buf/sync_debug.c | 20 ++++++++++---------- + drivers/dma-buf/sync_file.c | 6 ++---- + include/linux/fence.h | 24 ++++++++++++++++++++++++ + 4 files changed, 61 insertions(+), 14 deletions(-) + +--- a/drivers/dma-buf/fence.c ++++ b/drivers/dma-buf/fence.c +@@ -281,6 +281,31 @@ int fence_add_callback(struct fence *fen + EXPORT_SYMBOL(fence_add_callback); + + /** ++ * fence_get_status - returns the status upon completion ++ * @fence: [in] the fence to query ++ * ++ * This wraps fence_get_status_locked() to return the error status ++ * condition on a signaled fence. See fence_get_status_locked() for more ++ * details. ++ * ++ * Returns 0 if the fence has not yet been signaled, 1 if the fence has ++ * been signaled without an error condition, or a negative error code ++ * if the fence has been completed in err. ++ */ ++int fence_get_status(struct fence *fence) ++{ ++ unsigned long flags; ++ int status; ++ ++ spin_lock_irqsave(fence->lock, flags); ++ status = fence_get_status_locked(fence); ++ spin_unlock_irqrestore(fence->lock, flags); ++ ++ return status; ++} ++EXPORT_SYMBOL(fence_get_status); ++ ++/** + * fence_remove_callback - remove a callback from the signaling list + * @fence: [in] the fence to wait on + * @cb: [in] the callback to remove +--- a/drivers/dma-buf/sync_debug.c ++++ b/drivers/dma-buf/sync_debug.c +@@ -62,29 +62,29 @@ void sync_file_debug_remove(struct sync_ + + static const char *sync_status_str(int status) + { +- if (status == 0) +- return "signaled"; ++ if (status < 0) ++ return "error"; + + if (status > 0) +- return "active"; ++ return "signaled"; + +- return "error"; ++ return "active"; + } + +-static void sync_print_fence(struct seq_file *s, struct fence *fence, bool show) ++static void sync_print_fence(struct seq_file *s, ++ struct fence *fence, bool show) + { +- int status = 1; + struct sync_timeline *parent = fence_parent(fence); ++ int status; + +- if (fence_is_signaled_locked(fence)) +- status = fence->status; ++ status = fence_get_status_locked(fence); + + seq_printf(s, " %s%sfence %s", + show ? parent->name : "", + show ? "_" : "", + sync_status_str(status)); + +- if (status <= 0) { ++ if (status) { + struct timespec64 ts64 = + ktime_to_timespec64(fence->timestamp); + +@@ -133,7 +133,7 @@ static void sync_print_sync_file(struct + int i; + + seq_printf(s, "[%p] %s: %s\n", sync_file, sync_file->name, +- sync_status_str(!fence_is_signaled(sync_file->fence))); ++ sync_status_str(fence_get_status(sync_file->fence))); + + if (fence_is_array(sync_file->fence)) { + struct fence_array *array = to_fence_array(sync_file->fence); +--- a/drivers/dma-buf/sync_file.c ++++ b/drivers/dma-buf/sync_file.c +@@ -377,10 +377,8 @@ static void sync_fill_fence_info(struct + 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->status = fence_get_status(fence); + info->timestamp_ns = ktime_to_ns(fence->timestamp); + } + +--- a/include/linux/fence.h ++++ b/include/linux/fence.h +@@ -334,6 +334,30 @@ static inline struct fence *fence_later( + return fence_is_signaled(f2) ? NULL : f2; + } + ++/** ++ * fence_get_status_locked - returns the status upon completion ++ * @fence: [in] the fence to query ++ * ++ * Drivers can supply an optional error status condition before they signal ++ * the fence (to indicate whether the fence was completed due to an error ++ * rather than success). The value of the status condition is only valid ++ * if the fence has been signaled, fence_get_status_locked() first checks ++ * the signal state before reporting the error status. ++ * ++ * Returns 0 if the fence has not yet been signaled, 1 if the fence has ++ * been signaled without an error condition, or a negative error code ++ * if the fence has been completed in err. ++ */ ++static inline int fence_get_status_locked(struct fence *fence) ++{ ++ if (fence_is_signaled_locked(fence)) ++ return fence->status < 0 ? fence->status : 1; ++ else ++ return 0; ++} ++ ++int fence_get_status(struct fence *fence); ++ + signed long fence_wait_timeout(struct fence *, bool intr, signed long timeout); + signed long fence_wait_any_timeout(struct fence **fences, uint32_t count, + bool intr, signed long timeout); diff --git a/queue-4.9/series b/queue-4.9/series index 1256d54eb1e..1f5a7faf07a 100644 --- a/queue-4.9/series +++ b/queue-4.9/series @@ -85,3 +85,16 @@ xen-netfront-improve-error-handling-during-initialization.patch cec-initiator-should-be-the-same-as-the-destination-for-poll.patch xen-netback-vif-counters-from-int-long-to-u64.patch net-fec-fix-multicast-filtering-hardware-setup.patch +dma-buf-dma-fence-extract-__dma_fence_is_later.patch +dma-buf-sw-sync-fix-the-is-signaled-test-to-handle-u32-wraparound.patch +dma-buf-sw-sync-prevent-user-overflow-on-timeline-advance.patch +dma-buf-sw-sync-reduce-irqsave-irqrestore-from-known-context.patch +dma-buf-sw-sync-sync_pt-is-private-and-of-fixed-size.patch +dma-buf-sw-sync-fix-locking-around-sync_timeline-lists.patch +dma-buf-sw-sync-use-an-rbtree-to-sort-fences-in-the-timeline.patch +dma-buf-sw_sync-move-timeline_fence_ops-around.patch +dma-buf-sw_sync-clean-up-list-before-signaling-the-fence.patch +dma-fence-clear-fence-status-during-dma_fence_init.patch +dma-fence-wrap-querying-the-fence-status.patch +dma-fence-introduce-drm_fence_set_error-helper.patch +dma-buf-sw_sync-force-signal-all-unsignaled-fences-on-dying-timeline.patch