Commit 64b73cff authored by Srinivas Pandruvada's avatar Srinivas Pandruvada Committed by Andy Shevchenko

platform/x86/intel-uncore-freq: Fix static checker issue and potential race condition

There is a possible race condition when:
All CPUs in a package is offlined and just before the last CPU offline,
user tries to read sysfs entry and read happens while offline callback
is about to delete the sysfs entry.

Although not reproduced but this is possible scenerio and can be
reproduced by adding a msleep() in the show_min_max_freq_khz() before
mutex_lock() and read min_freq attribute from user space. Before
msleep() finishes, force every CPUs in a package offline.

This will cause deadlock, with offline and sysfs read/write operation
because of mutex_lock. The uncore_remove_die_entry() will not release
mutex till read/write callback returns because of kobject_put() and
read/write callback waiting on mutex.

We don't have to remove the sysfs folder when the package is offline.
While there is no CPU present, we can fail the read/write calls by
returning ENXIO error. So remove the kobject_put() call in offline path.

This also address the warning from static checker, as there is no
access to "data" variable after kobject_put:
"The patch 49a474c7: "platform/x86: Add support for Uncore
frequency control" from Jan 13, 2020, leads to the following static
checker warning:

        drivers/platform/x86/intel-uncore-frequency.c:285 uncore_remove_die_entry()
        error: dereferencing freed memory 'data'
"
Reported-by: default avatarDan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: default avatarSrinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Signed-off-by: default avatarAndy Shevchenko <andriy.shevchenko@linux.intel.com>
parent 0e9c026f
...@@ -97,6 +97,9 @@ static int uncore_read_ratio(struct uncore_data *data, unsigned int *min, ...@@ -97,6 +97,9 @@ static int uncore_read_ratio(struct uncore_data *data, unsigned int *min,
u64 cap; u64 cap;
int ret; int ret;
if (data->control_cpu < 0)
return -ENXIO;
ret = rdmsrl_on_cpu(data->control_cpu, MSR_UNCORE_RATIO_LIMIT, &cap); ret = rdmsrl_on_cpu(data->control_cpu, MSR_UNCORE_RATIO_LIMIT, &cap);
if (ret) if (ret)
return ret; return ret;
...@@ -116,6 +119,11 @@ static int uncore_write_ratio(struct uncore_data *data, unsigned int input, ...@@ -116,6 +119,11 @@ static int uncore_write_ratio(struct uncore_data *data, unsigned int input,
mutex_lock(&uncore_lock); mutex_lock(&uncore_lock);
if (data->control_cpu < 0) {
ret = -ENXIO;
goto finish_write;
}
input /= UNCORE_FREQ_KHZ_MULTIPLIER; input /= UNCORE_FREQ_KHZ_MULTIPLIER;
if (!input || input > 0x7F) { if (!input || input > 0x7F) {
ret = -EINVAL; ret = -EINVAL;
...@@ -273,18 +281,15 @@ static void uncore_add_die_entry(int cpu) ...@@ -273,18 +281,15 @@ static void uncore_add_die_entry(int cpu)
mutex_unlock(&uncore_lock); mutex_unlock(&uncore_lock);
} }
/* Last CPU in this die is offline, so remove sysfs entries */ /* Last CPU in this die is offline, make control cpu invalid */
static void uncore_remove_die_entry(int cpu) static void uncore_remove_die_entry(int cpu)
{ {
struct uncore_data *data; struct uncore_data *data;
mutex_lock(&uncore_lock); mutex_lock(&uncore_lock);
data = uncore_get_instance(cpu); data = uncore_get_instance(cpu);
if (data) { if (data)
kobject_put(&data->kobj);
data->control_cpu = -1; data->control_cpu = -1;
data->valid = false;
}
mutex_unlock(&uncore_lock); mutex_unlock(&uncore_lock);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment