aboutsummaryrefslogtreecommitdiffstats
path: root/lib/percpu-rwsem.c
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@redhat.com>2012-12-17 19:01:38 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2012-12-17 20:15:18 -0500
commit8ebe34731a0d1a9d89b536430afd98d0fadec99b (patch)
treebb378645318ce7c9b1b5a389a5e522835916cbed /lib/percpu-rwsem.c
parent9390ef0c85fd065f01045fef708b046c98cda04c (diff)
percpu_rw_semaphore: add lockdep annotations
Add lockdep annotations. Not only this can help to find the potential problems, we do not want the false warnings if, say, the task takes two different percpu_rw_semaphore's for reading. IOW, at least ->rw_sem should not use a single class. This patch exposes this internal lock to lockdep so that it represents the whole percpu_rw_semaphore. This way we do not need to add another "fake" ->lockdep_map and lock_class_key. More importantly, this also makes the output from lockdep much more understandable if it finds the problem. In short, with this patch from lockdep pov percpu_down_read() and percpu_up_read() acquire/release ->rw_sem for reading, this matches the actual semantics. This abuses __up_read() but I hope this is fine and in fact I'd like to have down_read_no_lockdep() as well, percpu_down_read_recursive_readers() will need it. Signed-off-by: Oleg Nesterov <oleg@redhat.com> Cc: Anton Arapov <anton@redhat.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Michal Marek <mmarek@suse.cz> Cc: Mikulas Patocka <mpatocka@redhat.com> Cc: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'lib/percpu-rwsem.c')
-rw-r--r--lib/percpu-rwsem.c21
1 files changed, 17 insertions, 4 deletions
diff --git a/lib/percpu-rwsem.c b/lib/percpu-rwsem.c
index ce92ab563a08..652a8ee8efe9 100644
--- a/lib/percpu-rwsem.c
+++ b/lib/percpu-rwsem.c
@@ -2,18 +2,21 @@
2#include <linux/rwsem.h> 2#include <linux/rwsem.h>
3#include <linux/percpu.h> 3#include <linux/percpu.h>
4#include <linux/wait.h> 4#include <linux/wait.h>
5#include <linux/lockdep.h>
5#include <linux/percpu-rwsem.h> 6#include <linux/percpu-rwsem.h>
6#include <linux/rcupdate.h> 7#include <linux/rcupdate.h>
7#include <linux/sched.h> 8#include <linux/sched.h>
8#include <linux/errno.h> 9#include <linux/errno.h>
9 10
10int percpu_init_rwsem(struct percpu_rw_semaphore *brw) 11int __percpu_init_rwsem(struct percpu_rw_semaphore *brw,
12 const char *name, struct lock_class_key *rwsem_key)
11{ 13{
12 brw->fast_read_ctr = alloc_percpu(int); 14 brw->fast_read_ctr = alloc_percpu(int);
13 if (unlikely(!brw->fast_read_ctr)) 15 if (unlikely(!brw->fast_read_ctr))
14 return -ENOMEM; 16 return -ENOMEM;
15 17
16 init_rwsem(&brw->rw_sem); 18 /* ->rw_sem represents the whole percpu_rw_semaphore for lockdep */
19 __init_rwsem(&brw->rw_sem, name, rwsem_key);
17 atomic_set(&brw->write_ctr, 0); 20 atomic_set(&brw->write_ctr, 0);
18 atomic_set(&brw->slow_read_ctr, 0); 21 atomic_set(&brw->slow_read_ctr, 0);
19 init_waitqueue_head(&brw->write_waitq); 22 init_waitqueue_head(&brw->write_waitq);
@@ -66,19 +69,29 @@ static bool update_fast_ctr(struct percpu_rw_semaphore *brw, unsigned int val)
66/* 69/*
67 * Like the normal down_read() this is not recursive, the writer can 70 * Like the normal down_read() this is not recursive, the writer can
68 * come after the first percpu_down_read() and create the deadlock. 71 * come after the first percpu_down_read() and create the deadlock.
72 *
73 * Note: returns with lock_is_held(brw->rw_sem) == T for lockdep,
74 * percpu_up_read() does rwsem_release(). This pairs with the usage
75 * of ->rw_sem in percpu_down/up_write().
69 */ 76 */
70void percpu_down_read(struct percpu_rw_semaphore *brw) 77void percpu_down_read(struct percpu_rw_semaphore *brw)
71{ 78{
72 if (likely(update_fast_ctr(brw, +1))) 79 might_sleep();
80 if (likely(update_fast_ctr(brw, +1))) {
81 rwsem_acquire_read(&brw->rw_sem.dep_map, 0, 0, _RET_IP_);
73 return; 82 return;
83 }
74 84
75 down_read(&brw->rw_sem); 85 down_read(&brw->rw_sem);
76 atomic_inc(&brw->slow_read_ctr); 86 atomic_inc(&brw->slow_read_ctr);
77 up_read(&brw->rw_sem); 87 /* avoid up_read()->rwsem_release() */
88 __up_read(&brw->rw_sem);
78} 89}
79 90
80void percpu_up_read(struct percpu_rw_semaphore *brw) 91void percpu_up_read(struct percpu_rw_semaphore *brw)
81{ 92{
93 rwsem_release(&brw->rw_sem.dep_map, 1, _RET_IP_);
94
82 if (likely(update_fast_ctr(brw, -1))) 95 if (likely(update_fast_ctr(brw, -1)))
83 return; 96 return;
84 97