Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 08481e28 authored by Deepak Kumar's avatar Deepak Kumar
Browse files

msm: kgsl: Correct locking in timeline destroy and fence release



Both "timeline->lock" and "fence_lock" are required to be held
while accessing timeline fence list and "timeline->lock" is
required to be held while signaling timeline fences. This is
not followed during timeline destroy and fence release resulting
in an invalid fence pointer access during timeline destroy. Fix
this by acquiring required locks at both places.

Change-Id: I353a6b9dece666c25d702c004a8bdabcac6d10a3
Signed-off-by: default avatarDeepak Kumar <dkumar@codeaurora.org>
parent e2ae22f9
Loading
Loading
Loading
Loading
+19 −8
Original line number Original line Diff line number Diff line
@@ -166,7 +166,8 @@ static void timeline_fence_release(struct dma_fence *fence)
	struct kgsl_timeline_fence *cur, *temp;
	struct kgsl_timeline_fence *cur, *temp;
	unsigned long flags;
	unsigned long flags;


	spin_lock_irqsave(&fence_lock, flags);
	spin_lock_irqsave(&timeline->lock, flags);
	spin_lock(&fence_lock);


	/* If the fence is still on the active list, remove it */
	/* If the fence is still on the active list, remove it */
	list_for_each_entry_safe(cur, temp, &timeline->fences, node) {
	list_for_each_entry_safe(cur, temp, &timeline->fences, node) {
@@ -176,8 +177,8 @@ static void timeline_fence_release(struct dma_fence *fence)
		list_del_init(&f->node);
		list_del_init(&f->node);
		break;
		break;
	}
	}
	spin_unlock_irqrestore(&fence_lock, flags);
	spin_unlock(&fence_lock);

	spin_unlock_irqrestore(&timeline->lock, flags);
	trace_kgsl_timeline_fence_release(f->timeline->id, fence->seqno);
	trace_kgsl_timeline_fence_release(f->timeline->id, fence->seqno);


	kgsl_timeline_put(f->timeline);
	kgsl_timeline_put(f->timeline);
@@ -519,19 +520,29 @@ long kgsl_ioctl_timeline_destroy(struct kgsl_device_private *dev_priv,
	spin_lock_irq(&timeline->lock);
	spin_lock_irq(&timeline->lock);


	/* Copy any still pending fences to a temporary list */
	/* Copy any still pending fences to a temporary list */
	spin_lock(&fence_lock);
	list_replace_init(&timeline->fences, &temp);
	list_replace_init(&timeline->fences, &temp);
	spin_unlock(&fence_lock);


	/*
	 * Set an error on each still pending fence and signal
	 * them to release any callbacks. Hold the refcount
	 * to avoid fence getting destroyed during signaling.
	 */
	list_for_each_entry_safe(fence, tmp, &temp, node) {
		dma_fence_get(&fence->base);
		dma_fence_set_error(&fence->base, -ENOENT);
		dma_fence_signal_locked(&fence->base);
	}
	spin_unlock_irq(&timeline->lock);
	spin_unlock_irq(&timeline->lock);


	/*
	/*
	 * Set an error on each still pending fence and signal them outside of
	 * Put the fence refcount taken above outside lock
	 * the lock so we don't get a spinlock recursion if the fences get
	 * to avoid spinlock recursion during fence release.
	 * destroyed inside of the signal callback
	 */
	 */
	list_for_each_entry_safe(fence, tmp, &temp, node) {
	list_for_each_entry_safe(fence, tmp, &temp, node) {
		list_del_init(&fence->node);
		list_del_init(&fence->node);
		dma_fence_set_error(&fence->base, -ENOENT);
		dma_fence_put(&fence->base);
		dma_fence_signal(&fence->base);
	}
	}


	kgsl_timeline_put(timeline);
	kgsl_timeline_put(timeline);