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 Diff line number Diff line
@@ -166,7 +166,8 @@ static void timeline_fence_release(struct dma_fence *fence)
	struct kgsl_timeline_fence *cur, *temp;
	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 */
	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);
		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);

	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);

	/* Copy any still pending fences to a temporary list */
	spin_lock(&fence_lock);
	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);

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

	kgsl_timeline_put(timeline);