From: mark gross Remove spin locking around all blocking notifier calls that can sleep. I had to re-structure some of the code to avoid locking issues. Signed-off-by: mark gross Cc: Len Brown Cc: Arjan van de Ven Cc: Venki Pallipadi Cc: Adam Belay Signed-off-by: Andrew Morton --- kernel/pm_qos_params.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff -puN kernel/pm_qos_params.c~pm-qos-remove-locks-around-blocking-notifier kernel/pm_qos_params.c --- a/kernel/pm_qos_params.c~pm-qos-remove-locks-around-blocking-notifier +++ a/kernel/pm_qos_params.c @@ -135,13 +135,14 @@ static s32 min_compare(s32 v1, s32 v2) } - -/* assumes pm_qos_lock is held */ static void update_target(int target) { s32 extreme_value; struct requirement_list *node; + unsigned long flags; + int call_notifier = 0; + spin_lock_irqsave(&pm_qos_lock, flags); extreme_value = pm_qos_array[target]->default_value; list_for_each_entry(node, &pm_qos_array[target]->requirements.list, list) { @@ -149,13 +150,16 @@ static void update_target(int target) extreme_value, node->value); } if (pm_qos_array[target]->target_value != extreme_value) { + call_notifier = 1; pm_qos_array[target]->target_value = extreme_value; pr_debug(KERN_ERR "new target for qos %d is %d\n", target, pm_qos_array[target]->target_value); - blocking_notifier_call_chain(pm_qos_array[target]->notifiers, - (unsigned long) pm_qos_array[target]->target_value, - NULL); } + spin_unlock_irqrestore(&pm_qos_lock, flags); + + if (call_notifier) + blocking_notifier_call_chain(pm_qos_array[target]->notifiers, + (unsigned long) extreme_value, NULL); } static int register_pm_qos_misc(struct pm_qos_object *qos) @@ -227,8 +231,8 @@ int pm_qos_add_requirement(int pm_qos_cl spin_lock_irqsave(&pm_qos_lock, flags); list_add(&dep->list, &pm_qos_array[pm_qos_class]->requirements.list); - update_target(pm_qos_class); spin_unlock_irqrestore(&pm_qos_lock, flags); + update_target(pm_qos_class); return 0; } @@ -269,11 +273,10 @@ int pm_qos_update_requirement(int pm_qos break; } } + spin_unlock_irqrestore(&pm_qos_lock, flags); if (pending_update) update_target(pm_qos_class); - spin_unlock_irqrestore(&pm_qos_lock, flags); - return 0; } EXPORT_SYMBOL_GPL(pm_qos_update_requirement); @@ -303,9 +306,9 @@ void pm_qos_remove_requirement(int pm_qo break; } } + spin_unlock_irqrestore(&pm_qos_lock, flags); if (pending_update) update_target(pm_qos_class); - spin_unlock_irqrestore(&pm_qos_lock, flags); } EXPORT_SYMBOL_GPL(pm_qos_remove_requirement); @@ -319,13 +322,10 @@ EXPORT_SYMBOL_GPL(pm_qos_remove_requirem */ int pm_qos_add_notifier(int pm_qos_class, struct notifier_block *notifier) { - unsigned long flags; int retval; - spin_lock_irqsave(&pm_qos_lock, flags); retval = blocking_notifier_chain_register( pm_qos_array[pm_qos_class]->notifiers, notifier); - spin_unlock_irqrestore(&pm_qos_lock, flags); return retval; } @@ -341,13 +341,10 @@ EXPORT_SYMBOL_GPL(pm_qos_add_notifier); */ int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier) { - unsigned long flags; int retval; - spin_lock_irqsave(&pm_qos_lock, flags); retval = blocking_notifier_chain_unregister( pm_qos_array[pm_qos_class]->notifiers, notifier); - spin_unlock_irqrestore(&pm_qos_lock, flags); return retval; } _