mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-25 16:11:45 +00:00
notifier: Fix broken error handling pattern
The current notifiers have the following error handling pattern all over the place: int err, nr; err = __foo_notifier_call_chain(&chain, val_up, v, -1, &nr); if (err & NOTIFIER_STOP_MASK) __foo_notifier_call_chain(&chain, val_down, v, nr-1, NULL) And aside from the endless repetition thereof, it is broken. Consider blocking notifiers; both calls take and drop the rwsem, this means that the notifier list can change in between the two calls, making @nr meaningless. Fix this by replacing all the __foo_notifier_call_chain() functions with foo_notifier_call_chain_robust() that embeds the above pattern, but ensures it is inside a single lock region. Note: I switched atomic_notifier_call_chain_robust() to use the spinlock, since RCU cannot provide the guarantee required for the recovery. Note: software_resume() error handling was broken afaict. Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Ingo Molnar <mingo@kernel.org> Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Link: https://lore.kernel.org/r/20200818135804.325626653@infradead.org
This commit is contained in:
parent
f75aef392f
commit
70d9329857
9 changed files with 147 additions and 140 deletions
|
@ -15,18 +15,28 @@
|
|||
|
||||
static ATOMIC_NOTIFIER_HEAD(cpu_pm_notifier_chain);
|
||||
|
||||
static int cpu_pm_notify(enum cpu_pm_event event, int nr_to_call, int *nr_calls)
|
||||
static int cpu_pm_notify(enum cpu_pm_event event)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* __atomic_notifier_call_chain has a RCU read critical section, which
|
||||
* atomic_notifier_call_chain has a RCU read critical section, which
|
||||
* could be disfunctional in cpu idle. Copy RCU_NONIDLE code to let
|
||||
* RCU know this.
|
||||
*/
|
||||
rcu_irq_enter_irqson();
|
||||
ret = __atomic_notifier_call_chain(&cpu_pm_notifier_chain, event, NULL,
|
||||
nr_to_call, nr_calls);
|
||||
ret = atomic_notifier_call_chain(&cpu_pm_notifier_chain, event, NULL);
|
||||
rcu_irq_exit_irqson();
|
||||
|
||||
return notifier_to_errno(ret);
|
||||
}
|
||||
|
||||
static int cpu_pm_notify_robust(enum cpu_pm_event event_up, enum cpu_pm_event event_down)
|
||||
{
|
||||
int ret;
|
||||
|
||||
rcu_irq_enter_irqson();
|
||||
ret = atomic_notifier_call_chain_robust(&cpu_pm_notifier_chain, event_up, event_down, NULL);
|
||||
rcu_irq_exit_irqson();
|
||||
|
||||
return notifier_to_errno(ret);
|
||||
|
@ -80,18 +90,7 @@ EXPORT_SYMBOL_GPL(cpu_pm_unregister_notifier);
|
|||
*/
|
||||
int cpu_pm_enter(void)
|
||||
{
|
||||
int nr_calls = 0;
|
||||
int ret = 0;
|
||||
|
||||
ret = cpu_pm_notify(CPU_PM_ENTER, -1, &nr_calls);
|
||||
if (ret)
|
||||
/*
|
||||
* Inform listeners (nr_calls - 1) about failure of CPU PM
|
||||
* PM entry who are notified earlier to prepare for it.
|
||||
*/
|
||||
cpu_pm_notify(CPU_PM_ENTER_FAILED, nr_calls - 1, NULL);
|
||||
|
||||
return ret;
|
||||
return cpu_pm_notify_robust(CPU_PM_ENTER, CPU_PM_ENTER_FAILED);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cpu_pm_enter);
|
||||
|
||||
|
@ -109,7 +108,7 @@ EXPORT_SYMBOL_GPL(cpu_pm_enter);
|
|||
*/
|
||||
int cpu_pm_exit(void)
|
||||
{
|
||||
return cpu_pm_notify(CPU_PM_EXIT, -1, NULL);
|
||||
return cpu_pm_notify(CPU_PM_EXIT);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cpu_pm_exit);
|
||||
|
||||
|
@ -131,18 +130,7 @@ EXPORT_SYMBOL_GPL(cpu_pm_exit);
|
|||
*/
|
||||
int cpu_cluster_pm_enter(void)
|
||||
{
|
||||
int nr_calls = 0;
|
||||
int ret = 0;
|
||||
|
||||
ret = cpu_pm_notify(CPU_CLUSTER_PM_ENTER, -1, &nr_calls);
|
||||
if (ret)
|
||||
/*
|
||||
* Inform listeners (nr_calls - 1) about failure of CPU cluster
|
||||
* PM entry who are notified earlier to prepare for it.
|
||||
*/
|
||||
cpu_pm_notify(CPU_CLUSTER_PM_ENTER_FAILED, nr_calls - 1, NULL);
|
||||
|
||||
return ret;
|
||||
return cpu_pm_notify_robust(CPU_CLUSTER_PM_ENTER, CPU_CLUSTER_PM_ENTER_FAILED);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cpu_cluster_pm_enter);
|
||||
|
||||
|
@ -163,7 +151,7 @@ EXPORT_SYMBOL_GPL(cpu_cluster_pm_enter);
|
|||
*/
|
||||
int cpu_cluster_pm_exit(void)
|
||||
{
|
||||
return cpu_pm_notify(CPU_CLUSTER_PM_EXIT, -1, NULL);
|
||||
return cpu_pm_notify(CPU_CLUSTER_PM_EXIT);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cpu_cluster_pm_exit);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue