|
@@ -323,11 +323,18 @@ EXPORT_SYMBOL_GPL(blocking_notifier_chain_unregister);
|
|
|
int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
|
|
|
unsigned long val, void *v)
|
|
|
{
|
|
|
- int ret;
|
|
|
+ int ret = NOTIFY_DONE;
|
|
|
|
|
|
- down_read(&nh->rwsem);
|
|
|
- ret = notifier_call_chain(&nh->head, val, v);
|
|
|
- up_read(&nh->rwsem);
|
|
|
+ /*
|
|
|
+ * We check the head outside the lock, but if this access is
|
|
|
+ * racy then it does not matter what the result of the test
|
|
|
+ * is, we re-check the list after having taken the lock anyway:
|
|
|
+ */
|
|
|
+ if (rcu_dereference(nh->head)) {
|
|
|
+ down_read(&nh->rwsem);
|
|
|
+ ret = notifier_call_chain(&nh->head, val, v);
|
|
|
+ up_read(&nh->rwsem);
|
|
|
+ }
|
|
|
return ret;
|
|
|
}
|
|
|
|