X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=kernel%2Fsys.c;h=6e2101dec0fcfc9e95c52a1ac53bc6898b976edf;hb=d5112a4f31a361409d3c57dc9d58dd69f8014bef;hp=c7675c1bfdf24e8c9d45b22e67da5c5679ba662b;hpb=9cdf083f981b8d37b3212400a359368661385099;p=linux-2.6 diff --git a/kernel/sys.c b/kernel/sys.c index c7675c1bfd..6e2101dec0 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -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; }