Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

locking/qrwlock: Fix write unlock bug on big endian systems

This patch aims to get rid of endianness in queued_write_unlock(). We
want to set __qrwlock->wmode to NULL, however the address is not
&lock->cnts in big endian machine. That causes queued_write_unlock()
write NULL to the wrong field of __qrwlock.

So implement __qrwlock_write_byte() which returns the correct
__qrwlock->wmode address.

Suggested-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Pan Xinhui <xinhui.pan@linux.vnet.ibm.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Waiman.Long@hpe.com
Cc: arnd@arndb.de
Cc: boqun.feng@gmail.com
Cc: will.deacon@arm.com
Link: http://lkml.kernel.org/r/1468835259-4486-1-git-send-email-xinhui.pan@linux.vnet.ibm.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>

authored by

pan xinhui and committed by
Ingo Molnar
2db34e8b a2071cd7

+25 -2
+25 -2
include/asm-generic/qrwlock.h
··· 25 25 #include <asm-generic/qrwlock_types.h> 26 26 27 27 /* 28 - * Writer states & reader shift and bias 28 + * Writer states & reader shift and bias. 29 + * 30 + * | +0 | +1 | +2 | +3 | 31 + * ----+----+----+----+----+ 32 + * LE | 78 | 56 | 34 | 12 | 0x12345678 33 + * ----+----+----+----+----+ 34 + * | wr | rd | 35 + * +----+----+----+----+ 36 + * 37 + * ----+----+----+----+----+ 38 + * BE | 12 | 34 | 56 | 78 | 0x12345678 39 + * ----+----+----+----+----+ 40 + * | rd | wr | 41 + * +----+----+----+----+ 29 42 */ 30 43 #define _QW_WAITING 1 /* A writer is waiting */ 31 44 #define _QW_LOCKED 0xff /* A writer holds the lock */ ··· 147 134 } 148 135 149 136 /** 137 + * __qrwlock_write_byte - retrieve the write byte address of a queue rwlock 138 + * @lock : Pointer to queue rwlock structure 139 + * Return: the write byte address of a queue rwlock 140 + */ 141 + static inline u8 *__qrwlock_write_byte(struct qrwlock *lock) 142 + { 143 + return (u8 *)lock + 3 * IS_BUILTIN(CONFIG_CPU_BIG_ENDIAN); 144 + } 145 + 146 + /** 150 147 * queued_write_unlock - release write lock of a queue rwlock 151 148 * @lock : Pointer to queue rwlock structure 152 149 */ 153 150 static inline void queued_write_unlock(struct qrwlock *lock) 154 151 { 155 - smp_store_release((u8 *)&lock->cnts, 0); 152 + smp_store_release(__qrwlock_write_byte(lock), 0); 156 153 } 157 154 158 155 /*