summaryrefslogtreecommitdiffstats
path: root/drivers/dma-buf
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2017-06-29 17:05:32 -0400
committerGustavo Padovan <gustavo.padovan@collabora.com>2017-06-29 17:53:47 -0400
commitd3862e44daa7a0c94d2f6193502a8c49379acfce (patch)
tree6716a8b2f9830b5b052837f2eddd40c10e64b124 /drivers/dma-buf
parent3b52ce44e720c240afc4c4b03140d7b7811b23bd (diff)
dma-buf/sw-sync: Fix locking around sync_timeline lists
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 <chris@chris-wilson.co.uk> Cc: Sumit Semwal <sumit.semwal@linaro.org> Cc: Sean Paul <seanpaul@chromium.org> Cc: Gustavo Padovan <gustavo@padovan.org> Reviewed-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.com> Link: http://patchwork.freedesktop.org/patch/msgid/20170629210532.5617-1-chris@chris-wilson.co.uk
Diffstat (limited to 'drivers/dma-buf')
-rw-r--r--drivers/dma-buf/sw_sync.c48
-rw-r--r--drivers/dma-buf/sync_debug.c9
-rw-r--r--drivers/dma-buf/sync_debug.h21
3 files changed, 31 insertions, 47 deletions
diff --git a/drivers/dma-buf/sw_sync.c b/drivers/dma-buf/sw_sync.c
index 6effa1ce010e..f20d18c421a3 100644
--- a/drivers/dma-buf/sw_sync.c
+++ b/drivers/dma-buf/sw_sync.c
@@ -96,9 +96,8 @@ static struct sync_timeline *sync_timeline_create(const char *name)
96 obj->context = dma_fence_context_alloc(1); 96 obj->context = dma_fence_context_alloc(1);
97 strlcpy(obj->name, name, sizeof(obj->name)); 97 strlcpy(obj->name, name, sizeof(obj->name));
98 98
99 INIT_LIST_HEAD(&obj->child_list_head); 99 INIT_LIST_HEAD(&obj->pt_list);
100 INIT_LIST_HEAD(&obj->active_list_head); 100 spin_lock_init(&obj->lock);
101 spin_lock_init(&obj->child_list_lock);
102 101
103 sync_timeline_debug_add(obj); 102 sync_timeline_debug_add(obj);
104 103
@@ -139,17 +138,15 @@ static void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc)
139 138
140 trace_sync_timeline(obj); 139 trace_sync_timeline(obj);
141 140
142 spin_lock_irq(&obj->child_list_lock); 141 spin_lock_irq(&obj->lock);
143 142
144 obj->value += inc; 143 obj->value += inc;
145 144
146 list_for_each_entry_safe(pt, next, &obj->active_list_head, 145 list_for_each_entry_safe(pt, next, &obj->pt_list, link)
147 active_list) {
148 if (dma_fence_is_signaled_locked(&pt->base)) 146 if (dma_fence_is_signaled_locked(&pt->base))
149 list_del_init(&pt->active_list); 147 list_del_init(&pt->link);
150 }
151 148
152 spin_unlock_irq(&obj->child_list_lock); 149 spin_unlock_irq(&obj->lock);
153} 150}
154 151
155/** 152/**
@@ -171,15 +168,15 @@ static struct sync_pt *sync_pt_create(struct sync_timeline *obj,
171 if (!pt) 168 if (!pt)
172 return NULL; 169 return NULL;
173 170
174 spin_lock_irq(&obj->child_list_lock);
175
176 sync_timeline_get(obj); 171 sync_timeline_get(obj);
177 dma_fence_init(&pt->base, &timeline_fence_ops, &obj->child_list_lock, 172 dma_fence_init(&pt->base, &timeline_fence_ops, &obj->lock,
178 obj->context, value); 173 obj->context, value);
179 list_add_tail(&pt->child_list, &obj->child_list_head); 174 INIT_LIST_HEAD(&pt->link);
180 INIT_LIST_HEAD(&pt->active_list);
181 175
182 spin_unlock_irq(&obj->child_list_lock); 176 spin_lock_irq(&obj->lock);
177 if (!dma_fence_is_signaled_locked(&pt->base))
178 list_add_tail(&pt->link, &obj->pt_list);
179 spin_unlock_irq(&obj->lock);
183 180
184 return pt; 181 return pt;
185} 182}
@@ -200,15 +197,15 @@ static void timeline_fence_release(struct dma_fence *fence)
200{ 197{
201 struct sync_pt *pt = dma_fence_to_sync_pt(fence); 198 struct sync_pt *pt = dma_fence_to_sync_pt(fence);
202 struct sync_timeline *parent = dma_fence_parent(fence); 199 struct sync_timeline *parent = dma_fence_parent(fence);
203 unsigned long flags;
204 200
205 spin_lock_irqsave(fence->lock, flags); 201 if (!list_empty(&pt->link)) {
202 unsigned long flags;
206 203
207 list_del(&pt->child_list); 204 spin_lock_irqsave(fence->lock, flags);
208 if (!list_empty(&pt->active_list)) 205 if (!list_empty(&pt->link))
209 list_del(&pt->active_list); 206 list_del(&pt->link);
210 207 spin_unlock_irqrestore(fence->lock, flags);
211 spin_unlock_irqrestore(fence->lock, flags); 208 }
212 209
213 sync_timeline_put(parent); 210 sync_timeline_put(parent);
214 dma_fence_free(fence); 211 dma_fence_free(fence);
@@ -223,13 +220,6 @@ static bool timeline_fence_signaled(struct dma_fence *fence)
223 220
224static bool timeline_fence_enable_signaling(struct dma_fence *fence) 221static bool timeline_fence_enable_signaling(struct dma_fence *fence)
225{ 222{
226 struct sync_pt *pt = dma_fence_to_sync_pt(fence);
227 struct sync_timeline *parent = dma_fence_parent(fence);
228
229 if (timeline_fence_signaled(fence))
230 return false;
231
232 list_add_tail(&pt->active_list, &parent->active_list_head);
233 return true; 223 return true;
234} 224}
235 225
diff --git a/drivers/dma-buf/sync_debug.c b/drivers/dma-buf/sync_debug.c
index 0e91632248ba..2264a075f6a9 100644
--- 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_file *s, struct sync_timeline *obj)
119 119
120 seq_printf(s, "%s: %d\n", obj->name, obj->value); 120 seq_printf(s, "%s: %d\n", obj->name, obj->value);
121 121
122 spin_lock_irq(&obj->child_list_lock); 122 spin_lock_irq(&obj->lock);
123 list_for_each(pos, &obj->child_list_head) { 123 list_for_each(pos, &obj->pt_list) {
124 struct sync_pt *pt = 124 struct sync_pt *pt = container_of(pos, struct sync_pt, link);
125 container_of(pos, struct sync_pt, child_list);
126 sync_print_fence(s, &pt->base, false); 125 sync_print_fence(s, &pt->base, false);
127 } 126 }
128 spin_unlock_irq(&obj->child_list_lock); 127 spin_unlock_irq(&obj->lock);
129} 128}
130 129
131static void sync_print_sync_file(struct seq_file *s, 130static void sync_print_sync_file(struct seq_file *s,
diff --git a/drivers/dma-buf/sync_debug.h b/drivers/dma-buf/sync_debug.h
index 26fe8b9907b3..6a2a8e69a7d0 100644
--- a/drivers/dma-buf/sync_debug.h
+++ b/drivers/dma-buf/sync_debug.h
@@ -24,42 +24,37 @@
24 * struct sync_timeline - sync object 24 * struct sync_timeline - sync object
25 * @kref: reference count on fence. 25 * @kref: reference count on fence.
26 * @name: name of the sync_timeline. Useful for debugging 26 * @name: name of the sync_timeline. Useful for debugging
27 * @child_list_head: list of children sync_pts for this sync_timeline 27 * @lock: lock protecting @pt_list and @value
28 * @child_list_lock: lock protecting @child_list_head and fence.status 28 * @pt_list: list of active (unsignaled/errored) sync_pts
29 * @active_list_head: list of active (unsignaled/errored) sync_pts
30 * @sync_timeline_list: membership in global sync_timeline_list 29 * @sync_timeline_list: membership in global sync_timeline_list
31 */ 30 */
32struct sync_timeline { 31struct sync_timeline {
33 struct kref kref; 32 struct kref kref;
34 char name[32]; 33 char name[32];
35 34
36 /* protected by child_list_lock */ 35 /* protected by lock */
37 u64 context; 36 u64 context;
38 int value; 37 int value;
39 38
40 struct list_head child_list_head; 39 struct list_head pt_list;
41 spinlock_t child_list_lock; 40 spinlock_t lock;
42
43 struct list_head active_list_head;
44 41
45 struct list_head sync_timeline_list; 42 struct list_head sync_timeline_list;
46}; 43};
47 44
48static inline struct sync_timeline *dma_fence_parent(struct dma_fence *fence) 45static inline struct sync_timeline *dma_fence_parent(struct dma_fence *fence)
49{ 46{
50 return container_of(fence->lock, struct sync_timeline, child_list_lock); 47 return container_of(fence->lock, struct sync_timeline, lock);
51} 48}
52 49
53/** 50/**
54 * struct sync_pt - sync_pt object 51 * struct sync_pt - sync_pt object
55 * @base: base fence object 52 * @base: base fence object
56 * @child_list: sync timeline child's list 53 * @link: link on the sync timeline's list
57 * @active_list: sync timeline active child's list
58 */ 54 */
59struct sync_pt { 55struct sync_pt {
60 struct dma_fence base; 56 struct dma_fence base;
61 struct list_head child_list; 57 struct list_head link;
62 struct list_head active_list;
63}; 58};
64 59
65#ifdef CONFIG_SW_SYNC 60#ifdef CONFIG_SW_SYNC