aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux/percpu-rwsem.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/linux/percpu-rwsem.h')
-rw-r--r--include/linux/percpu-rwsem.h28
1 files changed, 11 insertions, 17 deletions
diff --git a/include/linux/percpu-rwsem.h b/include/linux/percpu-rwsem.h
index cf80f7e5277f..250a4acddb2b 100644
--- a/include/linux/percpu-rwsem.h
+++ b/include/linux/percpu-rwsem.h
@@ -12,34 +12,27 @@ struct percpu_rw_semaphore {
12 struct mutex mtx; 12 struct mutex mtx;
13}; 13};
14 14
15#define light_mb() barrier()
16#define heavy_mb() synchronize_sched()
17
15static inline void percpu_down_read(struct percpu_rw_semaphore *p) 18static inline void percpu_down_read(struct percpu_rw_semaphore *p)
16{ 19{
17 rcu_read_lock(); 20 rcu_read_lock_sched();
18 if (unlikely(p->locked)) { 21 if (unlikely(p->locked)) {
19 rcu_read_unlock(); 22 rcu_read_unlock_sched();
20 mutex_lock(&p->mtx); 23 mutex_lock(&p->mtx);
21 this_cpu_inc(*p->counters); 24 this_cpu_inc(*p->counters);
22 mutex_unlock(&p->mtx); 25 mutex_unlock(&p->mtx);
23 return; 26 return;
24 } 27 }
25 this_cpu_inc(*p->counters); 28 this_cpu_inc(*p->counters);
26 rcu_read_unlock(); 29 rcu_read_unlock_sched();
30 light_mb(); /* A, between read of p->locked and read of data, paired with D */
27} 31}
28 32
29static inline void percpu_up_read(struct percpu_rw_semaphore *p) 33static inline void percpu_up_read(struct percpu_rw_semaphore *p)
30{ 34{
31 /* 35 light_mb(); /* B, between read of the data and write to p->counter, paired with C */
32 * On X86, write operation in this_cpu_dec serves as a memory unlock
33 * barrier (i.e. memory accesses may be moved before the write, but
34 * no memory accesses are moved past the write).
35 * On other architectures this may not be the case, so we need smp_mb()
36 * there.
37 */
38#if defined(CONFIG_X86) && (!defined(CONFIG_X86_PPRO_FENCE) && !defined(CONFIG_X86_OOSTORE))
39 barrier();
40#else
41 smp_mb();
42#endif
43 this_cpu_dec(*p->counters); 36 this_cpu_dec(*p->counters);
44} 37}
45 38
@@ -58,14 +51,15 @@ static inline void percpu_down_write(struct percpu_rw_semaphore *p)
58{ 51{
59 mutex_lock(&p->mtx); 52 mutex_lock(&p->mtx);
60 p->locked = true; 53 p->locked = true;
61 synchronize_rcu(); 54 synchronize_sched(); /* make sure that all readers exit the rcu_read_lock_sched region */
62 while (__percpu_count(p->counters)) 55 while (__percpu_count(p->counters))
63 msleep(1); 56 msleep(1);
64 smp_rmb(); /* paired with smp_mb() in percpu_sem_up_read() */ 57 heavy_mb(); /* C, between read of p->counter and write to data, paired with B */
65} 58}
66 59
67static inline void percpu_up_write(struct percpu_rw_semaphore *p) 60static inline void percpu_up_write(struct percpu_rw_semaphore *p)
68{ 61{
62 heavy_mb(); /* D, between write to data and write to p->locked, paired with A */
69 p->locked = false; 63 p->locked = false;
70 mutex_unlock(&p->mtx); 64 mutex_unlock(&p->mtx);
71} 65}