This source file includes following definitions.
- __percpu_init_rwsem
- percpu_free_rwsem
- __percpu_down_read
- __percpu_up_read
- readers_active_check
- percpu_down_write
- percpu_up_write
1
2 #include <linux/atomic.h>
3 #include <linux/rwsem.h>
4 #include <linux/percpu.h>
5 #include <linux/lockdep.h>
6 #include <linux/percpu-rwsem.h>
7 #include <linux/rcupdate.h>
8 #include <linux/sched.h>
9 #include <linux/errno.h>
10
11 #include "rwsem.h"
12
13 int __percpu_init_rwsem(struct percpu_rw_semaphore *sem,
14 const char *name, struct lock_class_key *rwsem_key)
15 {
16 sem->read_count = alloc_percpu(int);
17 if (unlikely(!sem->read_count))
18 return -ENOMEM;
19
20
21 rcu_sync_init(&sem->rss);
22 __init_rwsem(&sem->rw_sem, name, rwsem_key);
23 rcuwait_init(&sem->writer);
24 sem->readers_block = 0;
25 return 0;
26 }
27 EXPORT_SYMBOL_GPL(__percpu_init_rwsem);
28
29 void percpu_free_rwsem(struct percpu_rw_semaphore *sem)
30 {
31
32
33
34
35 if (!sem->read_count)
36 return;
37
38 rcu_sync_dtor(&sem->rss);
39 free_percpu(sem->read_count);
40 sem->read_count = NULL;
41 }
42 EXPORT_SYMBOL_GPL(percpu_free_rwsem);
43
44 int __percpu_down_read(struct percpu_rw_semaphore *sem, int try)
45 {
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61 smp_mb();
62
63
64
65
66
67 if (likely(!smp_load_acquire(&sem->readers_block)))
68 return 1;
69
70
71
72
73
74 __percpu_up_read(sem);
75
76 if (try)
77 return 0;
78
79
80
81
82
83 preempt_enable_no_resched();
84
85
86
87
88 __down_read(&sem->rw_sem);
89 this_cpu_inc(*sem->read_count);
90 __up_read(&sem->rw_sem);
91
92 preempt_disable();
93 return 1;
94 }
95 EXPORT_SYMBOL_GPL(__percpu_down_read);
96
97 void __percpu_up_read(struct percpu_rw_semaphore *sem)
98 {
99 smp_mb();
100
101
102
103
104
105 __this_cpu_dec(*sem->read_count);
106
107
108 rcuwait_wake_up(&sem->writer);
109 }
110 EXPORT_SYMBOL_GPL(__percpu_up_read);
111
112 #define per_cpu_sum(var) \
113 ({ \
114 typeof(var) __sum = 0; \
115 int cpu; \
116 compiletime_assert_atomic_type(__sum); \
117 for_each_possible_cpu(cpu) \
118 __sum += per_cpu(var, cpu); \
119 __sum; \
120 })
121
122
123
124
125
126
127
128 static bool readers_active_check(struct percpu_rw_semaphore *sem)
129 {
130 if (per_cpu_sum(*sem->read_count) != 0)
131 return false;
132
133
134
135
136
137
138 smp_mb();
139
140 return true;
141 }
142
143 void percpu_down_write(struct percpu_rw_semaphore *sem)
144 {
145
146 rcu_sync_enter(&sem->rss);
147
148 down_write(&sem->rw_sem);
149
150
151
152
153
154 WRITE_ONCE(sem->readers_block, 1);
155
156 smp_mb();
157
158
159
160
161
162
163
164
165 rcuwait_wait_event(&sem->writer, readers_active_check(sem));
166 }
167 EXPORT_SYMBOL_GPL(percpu_down_write);
168
169 void percpu_up_write(struct percpu_rw_semaphore *sem)
170 {
171
172
173
174
175
176
177
178
179
180
181 smp_store_release(&sem->readers_block, 0);
182
183
184
185
186 up_write(&sem->rw_sem);
187
188
189
190
191
192
193 rcu_sync_exit(&sem->rss);
194 }
195 EXPORT_SYMBOL_GPL(percpu_up_write);