mirror of
https://github.com/tbsdtv/linux_media.git
synced 2025-07-23 12:43:29 +02: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:
committed by
Ingo Molnar
parent
f75aef392f
commit
70d9329857
@@ -161,20 +161,19 @@ extern int srcu_notifier_chain_unregister(struct srcu_notifier_head *nh,
|
||||
|
||||
extern int atomic_notifier_call_chain(struct atomic_notifier_head *nh,
|
||||
unsigned long val, void *v);
|
||||
extern int __atomic_notifier_call_chain(struct atomic_notifier_head *nh,
|
||||
unsigned long val, void *v, int nr_to_call, int *nr_calls);
|
||||
extern int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
|
||||
unsigned long val, void *v);
|
||||
extern int __blocking_notifier_call_chain(struct blocking_notifier_head *nh,
|
||||
unsigned long val, void *v, int nr_to_call, int *nr_calls);
|
||||
extern int raw_notifier_call_chain(struct raw_notifier_head *nh,
|
||||
unsigned long val, void *v);
|
||||
extern int __raw_notifier_call_chain(struct raw_notifier_head *nh,
|
||||
unsigned long val, void *v, int nr_to_call, int *nr_calls);
|
||||
extern int srcu_notifier_call_chain(struct srcu_notifier_head *nh,
|
||||
unsigned long val, void *v);
|
||||
extern int __srcu_notifier_call_chain(struct srcu_notifier_head *nh,
|
||||
unsigned long val, void *v, int nr_to_call, int *nr_calls);
|
||||
|
||||
extern int atomic_notifier_call_chain_robust(struct atomic_notifier_head *nh,
|
||||
unsigned long val_up, unsigned long val_down, void *v);
|
||||
extern int blocking_notifier_call_chain_robust(struct blocking_notifier_head *nh,
|
||||
unsigned long val_up, unsigned long val_down, void *v);
|
||||
extern int raw_notifier_call_chain_robust(struct raw_notifier_head *nh,
|
||||
unsigned long val_up, unsigned long val_down, void *v);
|
||||
|
||||
#define NOTIFY_DONE 0x0000 /* Don't care */
|
||||
#define NOTIFY_OK 0x0001 /* Suits me */
|
||||
|
Reference in New Issue
Block a user