In order for a writer to unlock correctly on big-endian machines, we need to expose the internal layout of the qrwlock structure so that we also zero the correct sub-field. Signed-off-by: Will Deacon <will.deacon@xxxxxxx> --- include/asm-generic/qrwlock.h | 2 +- include/asm-generic/qrwlock_types.h | 17 ++++++++++++++++- kernel/locking/qrwlock.c | 26 ++------------------------ 3 files changed, 19 insertions(+), 26 deletions(-) diff --git a/include/asm-generic/qrwlock.h b/include/asm-generic/qrwlock.h index dbaac5f2af8f..25e97942726a 100644 --- a/include/asm-generic/qrwlock.h +++ b/include/asm-generic/qrwlock.h @@ -143,7 +143,7 @@ static inline void queued_read_unlock(struct qrwlock *lock) #ifndef queued_write_unlock static inline void queued_write_unlock(struct qrwlock *lock) { - smp_store_release((u8 *)&lock->cnts, 0); + smp_store_release(&lock->wmode, 0); } #endif diff --git a/include/asm-generic/qrwlock_types.h b/include/asm-generic/qrwlock_types.h index 4d76f24df518..4c4f87fcf720 100644 --- a/include/asm-generic/qrwlock_types.h +++ b/include/asm-generic/qrwlock_types.h @@ -2,14 +2,29 @@ #define __ASM_GENERIC_QRWLOCK_TYPES_H #include <linux/types.h> +#include <asm/byteorder.h> #include <asm/spinlock_types.h> /* * The queue read/write lock data structure + * + * The 32-bit count is divided into an 8-bit writer mode byte (least + * significant) and a 24-bit reader count. */ typedef struct qrwlock { - atomic_t cnts; + union { + atomic_t cnts; + struct { +#ifdef __LITTLE_ENDIAN + u8 wmode; /* Writer mode */ + u8 rcnts[3]; /* Reader counts */ +#else + u8 rcnts[3]; /* Reader counts */ + u8 wmode; /* Writer mode */ +#endif + }; + }; arch_spinlock_t lock; } arch_rwlock_t; diff --git a/kernel/locking/qrwlock.c b/kernel/locking/qrwlock.c index 45fbb48f83f6..6ae1ae321897 100644 --- a/kernel/locking/qrwlock.c +++ b/kernel/locking/qrwlock.c @@ -27,26 +27,6 @@ # define arch_qrwlock_relax(lock) cpu_relax_lowlatency() #endif -/* - * This internal data structure is used for optimizing access to some of - * the subfields within the atomic_t cnts. - */ -struct __qrwlock { - union { - atomic_t cnts; - struct { -#ifdef __LITTLE_ENDIAN - u8 wmode; /* Writer mode */ - u8 rcnts[3]; /* Reader counts */ -#else - u8 rcnts[3]; /* Reader counts */ - u8 wmode; /* Writer mode */ -#endif - }; - }; - arch_spinlock_t lock; -}; - /** * rspin_until_writer_unlock - spin until writer is gone * @lock : Pointer to queue rwlock structure @@ -138,10 +118,8 @@ void queued_write_lock_slowpath(struct qrwlock *lock) * or wait for a previous writer to go away. */ for (;;) { - struct __qrwlock *l = (struct __qrwlock *)lock; - - if (!READ_ONCE(l->wmode) && - (cmpxchg_relaxed(&l->wmode, 0, _QW_WAITING) == 0)) + if (!READ_ONCE(lock->wmode) && + (cmpxchg_relaxed(&lock->wmode, 0, _QW_WAITING) == 0)) break; arch_qrwlock_relax(lock); -- 2.1.4 -- To unsubscribe from this list: send the line "unsubscribe linux-arch" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html