diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/percpu-rwsem.c | 21 |
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 | ||
10 | int percpu_init_rwsem(struct percpu_rw_semaphore *brw) | 11 | int __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 | */ |
70 | void percpu_down_read(struct percpu_rw_semaphore *brw) | 77 | void 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 | ||
80 | void percpu_up_read(struct percpu_rw_semaphore *brw) | 91 | void 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 | ||