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

Commit 09ed8b51 authored by Dhaval Patel's avatar Dhaval Patel
Browse files

drm/msm/sde: support fence release before fence signal



Fence create call returns the fd to caller client. Client
may close the fd before fence is signaled by timeline.
The close fd call is translated into fence_release followed
by fence memory free. If fence signal is called at later
point to adjust the timeline; it may try to pick the
dangle pointer fence from fence_list and try to delete
it. This patch fixes the race condition between fence
release and fence signal.

Change-Id: I28aaf625066b43fbb659d917adbf9dd577b4b7ea
Signed-off-by: default avatarDhaval Patel <pdhaval@codeaurora.org>
parent d3756c00
Loading
Loading
Loading
Loading
+29 −5
Original line number Diff line number Diff line
@@ -76,6 +76,10 @@ struct sde_fence {
	int fd;
};

static void sde_fence_destroy(struct kref *kref)
{
}

static inline struct sde_fence *to_sde_fence(struct fence *fence)
{
	return container_of(fence, struct sde_fence, base);
@@ -114,7 +118,26 @@ static bool sde_fence_signaled(struct fence *fence)
static void sde_fence_release(struct fence *fence)
{
	struct sde_fence *f = to_sde_fence(fence);
	struct sde_fence *fc, *next;
	struct sde_fence_context *ctx = f->ctx;
	unsigned long flags;
	bool release_kref = false;

	spin_lock_irqsave(&ctx->lock, flags);
	list_for_each_entry_safe(fc, next, &ctx->fence_list_head,
				 fence_list) {
		/* fence release called before signal */
		if (f == fc) {
			list_del_init(&fc->fence_list);
			release_kref = true;
			break;
		}
	}
	spin_unlock_irqrestore(&ctx->lock, flags);

	/* keep kput outside spin_lock because it may release ctx */
	if (release_kref)
		kref_put(&ctx->kref, sde_fence_destroy);
	kfree_rcu(f, base.rcu);
}

@@ -223,10 +246,6 @@ int sde_fence_init(struct sde_fence_context *ctx,
	return 0;
}

static void sde_fence_destroy(struct kref *kref)
{
}

void sde_fence_deinit(struct sde_fence_context *ctx)
{
	if (!ctx) {
@@ -295,6 +314,7 @@ void sde_fence_signal(struct sde_fence_context *ctx, bool is_error)
{
	unsigned long flags;
	struct sde_fence *fc, *next;
	uint32_t count = 0;

	if (!ctx) {
		SDE_ERROR("invalid ctx, %pK\n", ctx);
@@ -324,7 +344,7 @@ void sde_fence_signal(struct sde_fence_context *ctx, bool is_error)
				 fence_list) {
		if (fence_is_signaled_locked(&fc->base)) {
			list_del_init(&fc->fence_list);
			kref_put(&ctx->kref, sde_fence_destroy);
			count++;
		}
	}

@@ -332,4 +352,8 @@ void sde_fence_signal(struct sde_fence_context *ctx, bool is_error)

end:
	spin_unlock_irqrestore(&ctx->lock, flags);

	/* keep this outside spin_lock because same ctx may be released */
	for (; count > 0; count--)
		kref_put(&ctx->kref, sde_fence_destroy);
}