devfreq: Fix possible race in tz_start() handler
The TZ governor start can be invoked through the sysfs governor store() operation. This opens up a possible race when user space tries to set the same governor operation twice leading to calling the TZ governors tz_handler() in succession. While the first one goes through successfully and queues the work for starting the bandwidth governor, before the work gets to run, the second invocation of the tz_handler reinitializes the work. This causes the internal state of the work item to be reset causing a crash in the kernel workqueue handler. This patch tries to address this problem by not allowing the tz_handler() to run the next time, if the first invocation was already successful and potentially in progress. Change-Id: Id2d6b9f680c873937a64eeb483ce8359306cd7b0 Signed-off-by: Sharat Masetty <smasetty@codeaurora.org>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2010-2019, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2010-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
#include <linux/errno.h>
|
||||
#include <linux/module.h>
|
||||
@@ -470,11 +470,14 @@ static int tz_start(struct devfreq *devfreq)
|
||||
unsigned int tz_pwrlevels[MSM_ADRENO_MAX_PWRLEVELS + 1];
|
||||
int i, out, ret;
|
||||
unsigned int version;
|
||||
struct msm_adreno_extended_profile *gpu_profile;
|
||||
|
||||
struct msm_adreno_extended_profile *gpu_profile = container_of(
|
||||
(devfreq->profile),
|
||||
struct msm_adreno_extended_profile,
|
||||
profile);
|
||||
if (partner_gpu_profile)
|
||||
return -EEXIST;
|
||||
|
||||
gpu_profile = container_of(devfreq->profile,
|
||||
struct msm_adreno_extended_profile,
|
||||
profile);
|
||||
|
||||
/*
|
||||
* Assuming that we have only one instance of the adreno device
|
||||
@@ -495,6 +498,7 @@ static int tz_start(struct devfreq *devfreq)
|
||||
tz_pwrlevels[0] = i;
|
||||
} else {
|
||||
pr_err(TAG "tz_pwrlevels[] is too short\n");
|
||||
partner_gpu_profile = NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -511,6 +515,7 @@ static int tz_start(struct devfreq *devfreq)
|
||||
sizeof(version));
|
||||
if (ret != 0 || version > MAX_TZ_VERSION) {
|
||||
pr_err(TAG "tz_init failed\n");
|
||||
partner_gpu_profile = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -606,7 +611,7 @@ static int tz_handler(struct devfreq *devfreq, unsigned int event, void *data)
|
||||
break;
|
||||
}
|
||||
|
||||
if (partner_gpu_profile && partner_gpu_profile->bus_devfreq)
|
||||
if (!result && partner_gpu_profile && partner_gpu_profile->bus_devfreq)
|
||||
switch (event) {
|
||||
case DEVFREQ_GOV_START:
|
||||
queue_work(workqueue,
|
||||
|
||||
Reference in New Issue
Block a user