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

Commit 25064a00 authored by Amir Vajid's avatar Amir Vajid
Browse files

PM / devfreq: memlat: fix deadlock and pointer check in new design



We currently wait for a cpu_grp's work function (memlat_monitor_work)
to finish executing when we attempt to cancel it. However this can
result in a deadlock since we also hold mons_lock when cancelling it.
Also check that we have at least one active mon when our work function
runs to prevent reading the common PMU counters after the last mon
within a cpu_grp is stopped.

Lastly, add missing pointer check in delete_event(). This protects us
from trying to delete events that aren't defined (e.g. stall-ev).

Change-Id: I28afe1de7111984bc3d85a37fdc17d14442aa2a8
Signed-off-by: default avatarAmir Vajid <avajid@codeaurora.org>
parent 84f8bed8
Loading
Loading
Loading
Loading
+11 −5
Original line number Diff line number Diff line
@@ -227,9 +227,11 @@ static unsigned long get_cnt(struct memlat_hwmon *hw)
static void delete_event(struct event_data *event)
{
	event->prev_count = event->last_delta = 0;
	if (event->pevent) {
		perf_event_release_kernel(event->pevent);
		event->pevent = NULL;
	}
}

static struct perf_event_attr *alloc_attr(void)
{
@@ -307,6 +309,8 @@ static void memlat_monitor_work(struct work_struct *work)
	unsigned int i;

	mutex_lock(&cpu_grp->mons_lock);
	if (!cpu_grp->num_active_mons)
		goto unlock_out;
	update_counts(cpu_grp);
	for (i = 0; i < cpu_grp->num_mons; i++) {
		struct devfreq *df;
@@ -326,6 +330,8 @@ static void memlat_monitor_work(struct work_struct *work)

	queue_delayed_work(memlat_wq, &cpu_grp->work,
			   msecs_to_jiffies(cpu_grp->update_ms));

unlock_out:
	mutex_unlock(&cpu_grp->mons_lock);
}

@@ -395,7 +401,7 @@ static void stop_hwmon(struct memlat_hwmon *hw)
	}

	if (!cpu_grp->num_active_mons) {
		cancel_delayed_work_sync(&cpu_grp->work);
		cancel_delayed_work(&cpu_grp->work);
		free_common_evs(cpu_grp);
	}
	mutex_unlock(&cpu_grp->mons_lock);
@@ -419,12 +425,12 @@ static void set_update_ms(struct memlat_cpu_grp *cpu_grp)
	}

	if (new_update_ms == UINT_MAX) {
		cancel_delayed_work_sync(&cpu_grp->work);
		cancel_delayed_work(&cpu_grp->work);
	} else if (cpu_grp->update_ms == UINT_MAX) {
		queue_delayed_work(memlat_wq, &cpu_grp->work,
				   msecs_to_jiffies(new_update_ms));
	} else if (new_update_ms > cpu_grp->update_ms) {
		cancel_delayed_work_sync(&cpu_grp->work);
		cancel_delayed_work(&cpu_grp->work);
		queue_delayed_work(memlat_wq, &cpu_grp->work,
				   msecs_to_jiffies(new_update_ms));
	}