Skip to content
Snippets Groups Projects
Commit 97c22788 authored by 陈佳骏's avatar 陈佳骏 Committed by Cheng Jian
Browse files

cpuidle: fix container_of err in cpuidle_device and cpuidle_driver

euleros inclusion
category: bugfix
bugzilla: 34, https://gitee.com/openeuler/kernel/issues/I3VXYP


CVE: NA

--------------------------------------------------------------

Since we use struct wrapper to fix kabi broken in cpuidle_device
and cpuidle_driver, but it only cares about haltpoll device and driver,
which will cause memory error in case of that we use other cpuidle driver.

Fixes: 5c14d4a7 ("cpuidle: fix kabi broken in cpuidle_device and cpuidle_driver")
Signed-off-by: default avatarJiajun Chen <chenjiajun8@huawei.com>
Reviewed-by: default avatarXiangyou Xie <xiexiangyou@huawei.com>
Signed-off-by: default avatarCheng Jian <cj.chengjian@huawei.com>
parent 3eb3533c
No related branches found
Tags 4.19.90-2106.3.0
No related merge requests found
......@@ -117,7 +117,9 @@ static int __init haltpoll_init(void)
return -ENODEV;
ret = cpuidle_register_driver(drv);
if (ret < 0)
if (ret == 0)
haltpoll_switch_governor(drv);
else if (ret < 0)
return ret;
haltpoll_cpuidle_dev_wrap = alloc_percpu(struct cpuidle_device_wrapper);
......
......@@ -330,15 +330,9 @@ void cpuidle_reflect(struct cpuidle_device *dev, int index)
u64 cpuidle_poll_time(struct cpuidle_driver *drv,
struct cpuidle_device *dev)
{
struct cpuidle_device_wrapper *devw =
container_of(dev, struct cpuidle_device_wrapper, dev);
u64 limit_ns = TICK_NSEC;
int i;
u64 limit_ns;
if (devw->poll_limit_ns)
return devw->poll_limit_ns;
limit_ns = TICK_NSEC;
for (i = 1; i < drv->state_count; i++) {
if (drv->states[i].disabled || dev->states_usage[i].disable)
continue;
......@@ -348,7 +342,19 @@ u64 cpuidle_poll_time(struct cpuidle_driver *drv,
break;
}
devw->poll_limit_ns = limit_ns;
return limit_ns;
}
u64 cpuidle_haltpoll_time(struct cpuidle_driver *drv,
struct cpuidle_device *dev)
{
struct cpuidle_device_wrapper *devw =
container_of(dev, struct cpuidle_device_wrapper, dev);
if (devw->poll_limit_ns)
return devw->poll_limit_ns;
devw->poll_limit_ns = cpuidle_poll_time(drv, dev);
return devw->poll_limit_ns;
}
......
......@@ -241,6 +241,25 @@ static void __cpuidle_unregister_driver(struct cpuidle_driver *drv)
__cpuidle_unset_driver(drv);
}
void haltpoll_switch_governor(struct cpuidle_driver *drv)
{
struct cpuidle_governor *gov;
struct cpuidle_driver_wrapper *drvw;
drvw = container_of(drv, struct cpuidle_driver_wrapper, drv);
if (!strlen(param_governor) && drvw->governor &&
(cpuidle_get_driver() == drv)) {
mutex_lock(&cpuidle_lock);
gov = cpuidle_find_governor(drvw->governor);
if (gov) {
cpuidle_prev_governor = cpuidle_curr_governor;
if (cpuidle_switch_governor(gov) < 0)
cpuidle_prev_governor = NULL;
}
mutex_unlock(&cpuidle_lock);
}
}
/**
* cpuidle_register_driver - registers a driver
* @drv: a pointer to a valid struct cpuidle_driver
......@@ -253,29 +272,15 @@ static void __cpuidle_unregister_driver(struct cpuidle_driver *drv)
*/
int cpuidle_register_driver(struct cpuidle_driver *drv)
{
struct cpuidle_governor *gov;
struct cpuidle_driver_wrapper *drvw;
int ret;
spin_lock(&cpuidle_driver_lock);
ret = __cpuidle_register_driver(drv);
spin_unlock(&cpuidle_driver_lock);
drvw = container_of(drv, struct cpuidle_driver_wrapper, drv);
if (!ret && !strlen(param_governor) && drvw->governor &&
(cpuidle_get_driver() == drv)) {
mutex_lock(&cpuidle_lock);
gov = cpuidle_find_governor(drvw->governor);
if (gov) {
cpuidle_prev_governor = cpuidle_curr_governor;
if (cpuidle_switch_governor(gov) < 0)
cpuidle_prev_governor = NULL;
}
mutex_unlock(&cpuidle_lock);
}
return ret;
}
EXPORT_SYMBOL_GPL(cpuidle_register_driver);
/**
......
......@@ -26,7 +26,10 @@ static int __cpuidle poll_idle(struct cpuidle_device *dev,
unsigned int loop_count = 0;
u64 limit;
limit = cpuidle_poll_time(drv, dev);
if (drv->name && !strcmp(drv->name, "haltpoll"))
limit = cpuidle_haltpoll_time(drv, dev);
else
limit = cpuidle_poll_time(drv, dev);
while (!need_resched()) {
cpu_relax();
......
......@@ -410,16 +410,10 @@ static ssize_t cpuidle_state_store(struct kobject *kobj, struct attribute *attr,
struct cpuidle_state *state = kobj_to_state(kobj);
struct cpuidle_state_usage *state_usage = kobj_to_state_usage(kobj);
struct cpuidle_state_attr *cattr = attr_to_stateattr(attr);
struct cpuidle_device *dev = kobj_to_device(kobj);
struct cpuidle_device_wrapper *devw =
container_of(dev, struct cpuidle_device_wrapper, dev);
if (cattr->store)
ret = cattr->store(state, state_usage, buf, size);
/* reset poll time cache */
devw->poll_limit_ns = 0;
return ret;
}
......
......@@ -155,7 +155,10 @@ extern int cpuidle_enter(struct cpuidle_driver *drv,
extern void cpuidle_reflect(struct cpuidle_device *dev, int index);
extern u64 cpuidle_poll_time(struct cpuidle_driver *drv,
struct cpuidle_device *dev);
extern u64 cpuidle_haltpoll_time(struct cpuidle_driver *drv,
struct cpuidle_device *dev);
extern void haltpoll_switch_governor(struct cpuidle_driver *drv);
extern int cpuidle_register_driver(struct cpuidle_driver *drv);
extern struct cpuidle_driver *cpuidle_get_driver(void);
extern struct cpuidle_driver *cpuidle_driver_ref(void);
......@@ -192,8 +195,13 @@ static inline void cpuidle_reflect(struct cpuidle_device *dev, int index) { }
static inline u64 cpuidle_poll_time(struct cpuidle_driver *drv,
struct cpuidle_device *dev)
{return 0; }
static inline u64 cpuidle_haltpoll_time(struct cpuidle_driver *drv,
struct cpuidle_device *dev)
{return 0; }
static inline int cpuidle_register_driver(struct cpuidle_driver *drv)
{return -ENODEV; }
static inline void haltpoll_switch_governor(struct cpuidle_driver *drv)
{return -ENODEV; }
static inline struct cpuidle_driver *cpuidle_get_driver(void) {return NULL; }
static inline struct cpuidle_driver *cpuidle_driver_ref(void) {return NULL; }
static inline void cpuidle_driver_unref(void) {}
......
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