diff options
Diffstat (limited to 'kernel/locking/qrwlock.c')
-rw-r--r-- | kernel/locking/qrwlock.c | 30 |
1 files changed, 25 insertions, 5 deletions
diff --git a/kernel/locking/qrwlock.c b/kernel/locking/qrwlock.c index f956ede7f90d..6c5da483966b 100644 --- a/kernel/locking/qrwlock.c +++ b/kernel/locking/qrwlock.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Queue read/write lock | 2 | * Queued read/write locks |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or modify | 4 | * This program is free software; you can redistribute it and/or modify |
5 | * it under the terms of the GNU General Public License as published by | 5 | * it under the terms of the GNU General Public License as published by |
@@ -22,6 +22,26 @@ | |||
22 | #include <linux/hardirq.h> | 22 | #include <linux/hardirq.h> |
23 | #include <asm/qrwlock.h> | 23 | #include <asm/qrwlock.h> |
24 | 24 | ||
25 | /* | ||
26 | * This internal data structure is used for optimizing access to some of | ||
27 | * the subfields within the atomic_t cnts. | ||
28 | */ | ||
29 | struct __qrwlock { | ||
30 | union { | ||
31 | atomic_t cnts; | ||
32 | struct { | ||
33 | #ifdef __LITTLE_ENDIAN | ||
34 | u8 wmode; /* Writer mode */ | ||
35 | u8 rcnts[3]; /* Reader counts */ | ||
36 | #else | ||
37 | u8 rcnts[3]; /* Reader counts */ | ||
38 | u8 wmode; /* Writer mode */ | ||
39 | #endif | ||
40 | }; | ||
41 | }; | ||
42 | arch_spinlock_t lock; | ||
43 | }; | ||
44 | |||
25 | /** | 45 | /** |
26 | * rspin_until_writer_unlock - inc reader count & spin until writer is gone | 46 | * rspin_until_writer_unlock - inc reader count & spin until writer is gone |
27 | * @lock : Pointer to queue rwlock structure | 47 | * @lock : Pointer to queue rwlock structure |
@@ -107,10 +127,10 @@ void queue_write_lock_slowpath(struct qrwlock *lock) | |||
107 | * or wait for a previous writer to go away. | 127 | * or wait for a previous writer to go away. |
108 | */ | 128 | */ |
109 | for (;;) { | 129 | for (;;) { |
110 | cnts = atomic_read(&lock->cnts); | 130 | struct __qrwlock *l = (struct __qrwlock *)lock; |
111 | if (!(cnts & _QW_WMASK) && | 131 | |
112 | (atomic_cmpxchg(&lock->cnts, cnts, | 132 | if (!READ_ONCE(l->wmode) && |
113 | cnts | _QW_WAITING) == cnts)) | 133 | (cmpxchg(&l->wmode, 0, _QW_WAITING) == 0)) |
114 | break; | 134 | break; |
115 | 135 | ||
116 | cpu_relax_lowlatency(); | 136 | cpu_relax_lowlatency(); |