aboutsummaryrefslogtreecommitdiff
path: root/kernel/sys.c
diff options
context:
space:
mode:
authorJeff Garzik <jeff@garzik.org>2007-01-24 02:14:25 -0500
committerJeff Garzik <jeff@garzik.org>2007-01-24 02:14:25 -0500
commite47b207a5bcb73bb097f94d9fe364f50737b0eb2 (patch)
tree57389653c37d001de3a90655cb4172ba29199ce4 /kernel/sys.c
parentd344bff9c36db17dc4765215495aaa7212c1eb6c (diff)
parent419dd8378dfa32985672ab7927b4bc827f33b332 (diff)
Merge branch 'master' into upstream-fixes
Diffstat (limited to 'kernel/sys.c')
-rw-r--r--kernel/sys.c15
1 files changed, 11 insertions, 4 deletions
diff --git a/kernel/sys.c b/kernel/sys.c
index c7675c1bfdf..6e2101dec0f 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;
}