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

Commit b5f1b82e authored by Akhil P Oommen's avatar Akhil P Oommen
Browse files

msm: kgsl: Properly take syncsource_lock spinlock



Syncsource spinlock is not properly taken while removing syncsource
id from the synsource_idr. idr_find() and idr_remove() should be called
atomically. Fix this by keeping idr_find() and idr_remove() inside
a single lock.

Change-Id: I51b8dcd0d67deda746c05e4cbd9eb1355d8f5d0b
Signed-off-by: default avatarAkhil P Oommen <akhilpo@codeaurora.org>
parent 71636eec
Loading
Loading
Loading
Loading
+2 −19
Original line number Diff line number Diff line
@@ -977,24 +977,6 @@ static void process_release_memory(struct kgsl_process_private *private)
	}
}

static void process_release_sync_sources(struct kgsl_process_private *private)
{
	struct kgsl_syncsource *syncsource;
	int next = 0;

	while (1) {
		spin_lock(&private->syncsource_lock);
		syncsource = idr_get_next(&private->syncsource_idr, &next);
		spin_unlock(&private->syncsource_lock);

		if (syncsource == NULL)
			break;

		kgsl_syncsource_cleanup(private, syncsource);
		next = next + 1;
	}
}

static void kgsl_process_private_close(struct kgsl_device_private *dev_priv,
		struct kgsl_process_private *private)
{
@@ -1013,7 +995,8 @@ static void kgsl_process_private_close(struct kgsl_device_private *dev_priv,

	kgsl_process_uninit_sysfs(private);

	process_release_sync_sources(private);
	/* Release all syncsource objects from process private */
	kgsl_syncsource_process_release_syncsources(private);

	/* When using global pagetables, do not detach global pagetable */
	if (private->pagetable->name != KGSL_MMU_GLOBAL_PT)
+36 −10
Original line number Diff line number Diff line
@@ -623,18 +623,11 @@ void kgsl_syncsource_put(struct kgsl_syncsource *syncsource)
		kref_put(&syncsource->refcount, kgsl_syncsource_destroy);
}

void kgsl_syncsource_cleanup(struct kgsl_process_private *private,
static void kgsl_syncsource_cleanup(struct kgsl_process_private *private,
				struct kgsl_syncsource *syncsource)
{
	struct kgsl_syncsource_fence *sfence, *next;

	spin_lock(&private->syncsource_lock);
	if (syncsource->id != 0) {
		idr_remove(&private->syncsource_idr, syncsource->id);
		syncsource->id = 0;
	}
	spin_unlock(&private->syncsource_lock);

	/* Signal all fences to release any callbacks */
	spin_lock(&syncsource->lock);

@@ -659,10 +652,17 @@ long kgsl_ioctl_syncsource_destroy(struct kgsl_device_private *dev_priv,

	spin_lock(&private->syncsource_lock);
	syncsource = idr_find(&private->syncsource_idr, param->id);
	spin_unlock(&private->syncsource_lock);

	if (syncsource == NULL)
	if (syncsource == NULL) {
		spin_unlock(&private->syncsource_lock);
		return -EINVAL;
	}

	if (syncsource->id != 0) {
		idr_remove(&private->syncsource_idr, syncsource->id);
		syncsource->id = 0;
	}
	spin_unlock(&private->syncsource_lock);

	kgsl_syncsource_cleanup(private, syncsource);
	return 0;
@@ -807,6 +807,32 @@ static void kgsl_syncsource_fence_release(struct fence *fence)
	kfree(sfence);
}

void kgsl_syncsource_process_release_syncsources(
		struct kgsl_process_private *private)
{
	struct kgsl_syncsource *syncsource;
	int next = 0;

	while (1) {
		spin_lock(&private->syncsource_lock);
		syncsource = idr_get_next(&private->syncsource_idr, &next);

		if (syncsource == NULL) {
			spin_unlock(&private->syncsource_lock);
			break;
		}

		if (syncsource->id != 0) {
			idr_remove(&private->syncsource_idr, syncsource->id);
			syncsource->id = 0;
		}
		spin_unlock(&private->syncsource_lock);

		kgsl_syncsource_cleanup(private, syncsource);
		next = next + 1;
	}
}

static const char *kgsl_syncsource_get_timeline_name(struct fence *fence)
{
	struct kgsl_syncsource_fence *sfence =
+4 −4
Original line number Diff line number Diff line
@@ -108,8 +108,8 @@ long kgsl_ioctl_syncsource_signal_fence(struct kgsl_device_private *dev_priv,

void kgsl_syncsource_put(struct kgsl_syncsource *syncsource);

void kgsl_syncsource_cleanup(struct kgsl_process_private *private,
					struct kgsl_syncsource *syncsource);
void kgsl_syncsource_process_release_syncsources(
		struct kgsl_process_private *private);

void kgsl_dump_fence(struct kgsl_drawobj_sync_event *event,
					char *fence_str, int len);
@@ -182,8 +182,8 @@ static inline void kgsl_syncsource_put(struct kgsl_syncsource *syncsource)

}

static inline void kgsl_syncsource_cleanup(struct kgsl_process_private *private,
					struct kgsl_syncsource *syncsource)
static inline void kgsl_syncsource_process_release_syncsources(
		struct kgsl_process_private *private)
{

}