| .. | .. |
|---|
| 193 | 193 | */ |
|---|
| 194 | 194 | static void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc) |
|---|
| 195 | 195 | { |
|---|
| 196 | + LIST_HEAD(signalled); |
|---|
| 196 | 197 | struct sync_pt *pt, *next; |
|---|
| 197 | 198 | |
|---|
| 198 | 199 | trace_sync_timeline(obj); |
|---|
| .. | .. |
|---|
| 205 | 206 | if (!timeline_fence_signaled(&pt->base)) |
|---|
| 206 | 207 | break; |
|---|
| 207 | 208 | |
|---|
| 208 | | - list_del_init(&pt->link); |
|---|
| 209 | + dma_fence_get(&pt->base); |
|---|
| 210 | + |
|---|
| 211 | + list_move_tail(&pt->link, &signalled); |
|---|
| 209 | 212 | rb_erase(&pt->node, &obj->pt_tree); |
|---|
| 210 | 213 | |
|---|
| 211 | | - /* |
|---|
| 212 | | - * A signal callback may release the last reference to this |
|---|
| 213 | | - * fence, causing it to be freed. That operation has to be |
|---|
| 214 | | - * last to avoid a use after free inside this loop, and must |
|---|
| 215 | | - * be after we remove the fence from the timeline in order to |
|---|
| 216 | | - * prevent deadlocking on timeline->lock inside |
|---|
| 217 | | - * timeline_fence_release(). |
|---|
| 218 | | - */ |
|---|
| 219 | 214 | dma_fence_signal_locked(&pt->base); |
|---|
| 220 | 215 | } |
|---|
| 221 | 216 | |
|---|
| 222 | 217 | spin_unlock_irq(&obj->lock); |
|---|
| 218 | + |
|---|
| 219 | + list_for_each_entry_safe(pt, next, &signalled, link) { |
|---|
| 220 | + list_del_init(&pt->link); |
|---|
| 221 | + dma_fence_put(&pt->base); |
|---|
| 222 | + } |
|---|
| 223 | 223 | } |
|---|
| 224 | 224 | |
|---|
| 225 | 225 | /** |
|---|