Hi
Here I'm submitting backport of patches 8238b4579866b7c1bb99883cfe102a43db5506ff and d6ffe6067a54972564552ea45d320fb98db1ac5e to the stable branches.
Mikulas
This is backport of the upstream patch 8238b4579866b7c1bb99883cfe102a43db5506ff for the stable branches 5.10, 5.15, 5.19
Signed-off-by: Mikulas Patocka mpatocka@redhat.com
--- arch/x86/include/asm/bitops.h | 21 +++++++++++++++++++ include/asm-generic/bitops/instrumented-non-atomic.h | 12 ++++++++++ include/asm-generic/bitops/non-atomic.h | 14 ++++++++++++ include/linux/buffer_head.h | 2 - include/linux/wait_bit.h | 8 +++---- kernel/sched/wait_bit.c | 2 - 6 files changed, 53 insertions(+), 6 deletions(-)
Index: linux-stable/arch/x86/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/x86/include/asm/bitops.h 2022-09-30 13:07:11.000000000 +0200 +++ linux-stable/arch/x86/include/asm/bitops.h 2022-09-30 13:07:11.000000000 +0200 @@ -207,6 +207,20 @@ static __always_inline bool constant_tes (addr[nr >> _BITOPS_LONG_SHIFT])) != 0; }
+static __always_inline bool constant_test_bit_acquire(long nr, const volatile unsigned long *addr) +{ + bool oldbit; + + asm volatile("testb %2,%1" + CC_SET(nz) + : CC_OUT(nz) (oldbit) + : "m" (((unsigned char *)addr)[nr >> 3]), + "i" (1 << (nr & 7)) + :"memory"); + + return oldbit; +} + static __always_inline bool variable_test_bit(long nr, volatile const unsigned long *addr) { bool oldbit; @@ -224,6 +238,13 @@ static __always_inline bool variable_tes ? constant_test_bit((nr), (addr)) \ : variable_test_bit((nr), (addr)))
+static __always_inline bool +arch_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + return __builtin_constant_p(nr) ? constant_test_bit_acquire(nr, addr) : + variable_test_bit(nr, addr); +} + /** * __ffs - find first set bit in word * @word: The word to search Index: linux-stable/include/asm-generic/bitops/instrumented-non-atomic.h =================================================================== --- linux-stable.orig/include/asm-generic/bitops/instrumented-non-atomic.h 2022-09-30 13:07:11.000000000 +0200 +++ linux-stable/include/asm-generic/bitops/instrumented-non-atomic.h 2022-09-30 13:07:11.000000000 +0200 @@ -135,4 +135,16 @@ static __always_inline bool test_bit(lon return arch_test_bit(nr, addr); }
+/** + * _test_bit_acquire - Determine, with acquire semantics, whether a bit is set + * @nr: bit number to test + * @addr: Address to start counting from + */ +static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + instrument_atomic_read(addr + BIT_WORD(nr), sizeof(long)); + return arch_test_bit_acquire(nr, addr); +} + #endif /* _ASM_GENERIC_BITOPS_INSTRUMENTED_NON_ATOMIC_H */ Index: linux-stable/include/asm-generic/bitops/non-atomic.h =================================================================== --- linux-stable.orig/include/asm-generic/bitops/non-atomic.h 2022-09-30 13:07:11.000000000 +0200 +++ linux-stable/include/asm-generic/bitops/non-atomic.h 2022-09-30 13:07:11.000000000 +0200 @@ -3,6 +3,7 @@ #define _ASM_GENERIC_BITOPS_NON_ATOMIC_H_
#include <asm/types.h> +#include <asm/barrier.h>
/** * arch___set_bit - Set a bit in memory @@ -119,4 +120,17 @@ arch_test_bit(unsigned int nr, const vol } #define test_bit arch_test_bit
+/** + * arch_test_bit_acquire - Determine, with acquire semantics, whether a bit is set + * @nr: bit number to test + * @addr: Address to start counting from + */ +static __always_inline bool +arch_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} +#define test_bit_acquire arch_test_bit_acquire + #endif /* _ASM_GENERIC_BITOPS_NON_ATOMIC_H_ */ Index: linux-stable/include/linux/buffer_head.h =================================================================== --- linux-stable.orig/include/linux/buffer_head.h 2022-09-30 13:07:11.000000000 +0200 +++ linux-stable/include/linux/buffer_head.h 2022-09-30 13:07:11.000000000 +0200 @@ -166,7 +166,7 @@ static __always_inline int buffer_uptoda * make it consistent with folio_test_uptodate * pairs with smp_mb__before_atomic in set_buffer_uptodate */ - return (smp_load_acquire(&bh->b_state) & (1UL << BH_Uptodate)) != 0; + return test_bit_acquire(BH_Uptodate, &bh->b_state); }
#define bh_offset(bh) ((unsigned long)(bh)->b_data & ~PAGE_MASK) Index: linux-stable/include/linux/wait_bit.h =================================================================== --- linux-stable.orig/include/linux/wait_bit.h 2022-09-30 13:07:11.000000000 +0200 +++ linux-stable/include/linux/wait_bit.h 2022-09-30 13:07:11.000000000 +0200 @@ -71,7 +71,7 @@ static inline int wait_on_bit(unsigned long *word, int bit, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, bit_wait, @@ -96,7 +96,7 @@ static inline int wait_on_bit_io(unsigned long *word, int bit, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, bit_wait_io, @@ -123,7 +123,7 @@ wait_on_bit_timeout(unsigned long *word, unsigned long timeout) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit_timeout(word, bit, bit_wait_timeout, @@ -151,7 +151,7 @@ wait_on_bit_action(unsigned long *word, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, action, mode); } Index: linux-stable/kernel/sched/wait_bit.c =================================================================== --- linux-stable.orig/kernel/sched/wait_bit.c 2022-09-30 13:07:11.000000000 +0200 +++ linux-stable/kernel/sched/wait_bit.c 2022-09-30 13:07:11.000000000 +0200 @@ -47,7 +47,7 @@ __wait_on_bit(struct wait_queue_head *wq prepare_to_wait(wq_head, &wbq_entry->wq_entry, mode); if (test_bit(wbq_entry->key.bit_nr, wbq_entry->key.flags)) ret = (*action)(&wbq_entry->key, mode); - } while (test_bit(wbq_entry->key.bit_nr, wbq_entry->key.flags) && !ret); + } while (test_bit_acquire(wbq_entry->key.bit_nr, wbq_entry->key.flags) && !ret);
finish_wait(wq_head, &wbq_entry->wq_entry);
This is backport of the upstream patch 8238b4579866b7c1bb99883cfe102a43db5506ff for the stable branch 5.4
Signed-off-by: Mikulas Patocka mpatocka@redhat.com
--- arch/x86/include/asm/bitops.h | 21 +++++++++++++++++++++ include/asm-generic/bitops-instrumented.h | 6 ++++++ include/asm-generic/bitops/non-atomic.h | 14 ++++++++++++++ include/linux/buffer_head.h | 2 +- include/linux/wait_bit.h | 8 ++++---- kernel/sched/wait_bit.c | 2 +- 6 files changed, 47 insertions(+), 6 deletions(-)
Index: linux-stable/arch/x86/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/x86/include/asm/bitops.h 2022-09-30 15:38:29.000000000 +0200 +++ linux-stable/arch/x86/include/asm/bitops.h 2022-09-30 15:38:29.000000000 +0200 @@ -207,6 +207,20 @@ static __always_inline bool constant_tes (addr[nr >> _BITOPS_LONG_SHIFT])) != 0; }
+static __always_inline bool constant_test_bit_acquire(long nr, const volatile unsigned long *addr) +{ + bool oldbit; + + asm volatile("testb %2,%1" + CC_SET(nz) + : CC_OUT(nz) (oldbit) + : "m" (((unsigned char *)addr)[nr >> 3]), + "i" (1 << (nr & 7)) + :"memory"); + + return oldbit; +} + static __always_inline bool variable_test_bit(long nr, volatile const unsigned long *addr) { bool oldbit; @@ -224,6 +238,13 @@ static __always_inline bool variable_tes ? constant_test_bit((nr), (addr)) \ : variable_test_bit((nr), (addr)))
+static __always_inline bool +arch_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + return __builtin_constant_p(nr) ? constant_test_bit_acquire(nr, addr) : + variable_test_bit(nr, addr); +} + /** * __ffs - find first set bit in word * @word: The word to search Index: linux-stable/include/asm-generic/bitops/non-atomic.h =================================================================== --- linux-stable.orig/include/asm-generic/bitops/non-atomic.h 2022-09-30 15:38:29.000000000 +0200 +++ linux-stable/include/asm-generic/bitops/non-atomic.h 2022-09-30 15:38:29.000000000 +0200 @@ -3,6 +3,7 @@ #define _ASM_GENERIC_BITOPS_NON_ATOMIC_H_
#include <asm/types.h> +#include <asm/barrier.h>
/** * __set_bit - Set a bit in memory @@ -106,4 +107,17 @@ static inline int test_bit(int nr, const return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); }
+/** + * arch_test_bit_acquire - Determine, with acquire semantics, whether a bit is set + * @nr: bit number to test + * @addr: Address to start counting from + */ +static __always_inline bool +arch_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} +#define test_bit_acquire arch_test_bit_acquire + #endif /* _ASM_GENERIC_BITOPS_NON_ATOMIC_H_ */ Index: linux-stable/include/linux/buffer_head.h =================================================================== --- linux-stable.orig/include/linux/buffer_head.h 2022-09-30 15:38:29.000000000 +0200 +++ linux-stable/include/linux/buffer_head.h 2022-09-30 15:38:29.000000000 +0200 @@ -166,7 +166,7 @@ static __always_inline int buffer_uptoda * make it consistent with folio_test_uptodate * pairs with smp_mb__before_atomic in set_buffer_uptodate */ - return (smp_load_acquire(&bh->b_state) & (1UL << BH_Uptodate)) != 0; + return test_bit_acquire(BH_Uptodate, &bh->b_state); }
#define bh_offset(bh) ((unsigned long)(bh)->b_data & ~PAGE_MASK) Index: linux-stable/include/linux/wait_bit.h =================================================================== --- linux-stable.orig/include/linux/wait_bit.h 2022-09-30 15:38:29.000000000 +0200 +++ linux-stable/include/linux/wait_bit.h 2022-09-30 15:38:29.000000000 +0200 @@ -71,7 +71,7 @@ static inline int wait_on_bit(unsigned long *word, int bit, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, bit_wait, @@ -96,7 +96,7 @@ static inline int wait_on_bit_io(unsigned long *word, int bit, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, bit_wait_io, @@ -123,7 +123,7 @@ wait_on_bit_timeout(unsigned long *word, unsigned long timeout) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit_timeout(word, bit, bit_wait_timeout, @@ -151,7 +151,7 @@ wait_on_bit_action(unsigned long *word, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, action, mode); } Index: linux-stable/kernel/sched/wait_bit.c =================================================================== --- linux-stable.orig/kernel/sched/wait_bit.c 2022-09-30 15:38:29.000000000 +0200 +++ linux-stable/kernel/sched/wait_bit.c 2022-09-30 15:38:29.000000000 +0200 @@ -47,7 +47,7 @@ __wait_on_bit(struct wait_queue_head *wq prepare_to_wait(wq_head, &wbq_entry->wq_entry, mode); if (test_bit(wbq_entry->key.bit_nr, wbq_entry->key.flags)) ret = (*action)(&wbq_entry->key, mode); - } while (test_bit(wbq_entry->key.bit_nr, wbq_entry->key.flags) && !ret); + } while (test_bit_acquire(wbq_entry->key.bit_nr, wbq_entry->key.flags) && !ret);
finish_wait(wq_head, &wbq_entry->wq_entry);
Index: linux-stable/include/asm-generic/bitops-instrumented.h =================================================================== --- linux-stable.orig/include/asm-generic/bitops-instrumented.h 2022-09-30 15:37:42.000000000 +0200 +++ linux-stable/include/asm-generic/bitops-instrumented.h 2022-09-30 15:40:55.000000000 +0200 @@ -238,6 +238,12 @@ static inline bool test_bit(long nr, con return arch_test_bit(nr, addr); }
+static inline bool test_bit_acquire(long nr, const volatile unsigned long *addr) +{ + kasan_check_read(addr + BIT_WORD(nr), sizeof(long)); + return arch_test_bit_acquire(nr, addr); +} + #if defined(arch_clear_bit_unlock_is_negative_byte) /** * clear_bit_unlock_is_negative_byte - Clear a bit in memory and test if bottom
This is backport of the upstream patch 8238b4579866b7c1bb99883cfe102a43db5506ff for the stable branch 4.19
Signed-off-by: Mikulas Patocka mpatocka@redhat.com
--- arch/x86/include/asm/bitops.h | 21 +++++++++++++++++++++ include/asm-generic/bitops/non-atomic.h | 14 ++++++++++++++ include/linux/buffer_head.h | 2 +- include/linux/wait_bit.h | 8 ++++---- kernel/sched/wait_bit.c | 2 +- 5 files changed, 41 insertions(+), 6 deletions(-)
Index: linux-stable/arch/x86/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/x86/include/asm/bitops.h 2022-09-30 15:44:48.000000000 +0200 +++ linux-stable/arch/x86/include/asm/bitops.h 2022-09-30 15:46:38.000000000 +0200 @@ -317,6 +317,20 @@ static __always_inline bool constant_tes (addr[nr >> _BITOPS_LONG_SHIFT])) != 0; }
+static __always_inline bool constant_test_bit_acquire(long nr, const volatile unsigned long *addr) +{ + bool oldbit; + + asm volatile("testb %2,%1" + CC_SET(nz) + : CC_OUT(nz) (oldbit) + : "m" (((unsigned char *)addr)[nr >> 3]), + "i" (1 << (nr & 7)) + :"memory"); + + return oldbit; +} + static __always_inline bool variable_test_bit(long nr, volatile const unsigned long *addr) { bool oldbit; @@ -343,6 +357,13 @@ static bool test_bit(int nr, const volat ? constant_test_bit((nr), (addr)) \ : variable_test_bit((nr), (addr)))
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + return __builtin_constant_p(nr) ? constant_test_bit_acquire(nr, addr) : + variable_test_bit(nr, addr); +} + /** * __ffs - find first set bit in word * @word: The word to search Index: linux-stable/include/asm-generic/bitops/non-atomic.h =================================================================== --- linux-stable.orig/include/asm-generic/bitops/non-atomic.h 2022-09-30 15:44:48.000000000 +0200 +++ linux-stable/include/asm-generic/bitops/non-atomic.h 2022-09-30 15:44:48.000000000 +0200 @@ -3,6 +3,7 @@ #define _ASM_GENERIC_BITOPS_NON_ATOMIC_H_
#include <asm/types.h> +#include <asm/barrier.h>
/** * __set_bit - Set a bit in memory @@ -106,4 +107,17 @@ static inline int test_bit(int nr, const return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); }
+/** + * arch_test_bit_acquire - Determine, with acquire semantics, whether a bit is set + * @nr: bit number to test + * @addr: Address to start counting from + */ +static __always_inline bool +arch_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} +#define test_bit_acquire arch_test_bit_acquire + #endif /* _ASM_GENERIC_BITOPS_NON_ATOMIC_H_ */ Index: linux-stable/include/linux/buffer_head.h =================================================================== --- linux-stable.orig/include/linux/buffer_head.h 2022-09-30 15:44:48.000000000 +0200 +++ linux-stable/include/linux/buffer_head.h 2022-09-30 15:44:48.000000000 +0200 @@ -166,7 +166,7 @@ static __always_inline int buffer_uptoda * make it consistent with folio_test_uptodate * pairs with smp_mb__before_atomic in set_buffer_uptodate */ - return (smp_load_acquire(&bh->b_state) & (1UL << BH_Uptodate)) != 0; + return test_bit_acquire(BH_Uptodate, &bh->b_state); }
#define bh_offset(bh) ((unsigned long)(bh)->b_data & ~PAGE_MASK) Index: linux-stable/include/linux/wait_bit.h =================================================================== --- linux-stable.orig/include/linux/wait_bit.h 2022-09-30 15:44:48.000000000 +0200 +++ linux-stable/include/linux/wait_bit.h 2022-09-30 15:44:48.000000000 +0200 @@ -71,7 +71,7 @@ static inline int wait_on_bit(unsigned long *word, int bit, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, bit_wait, @@ -96,7 +96,7 @@ static inline int wait_on_bit_io(unsigned long *word, int bit, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, bit_wait_io, @@ -123,7 +123,7 @@ wait_on_bit_timeout(unsigned long *word, unsigned long timeout) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit_timeout(word, bit, bit_wait_timeout, @@ -151,7 +151,7 @@ wait_on_bit_action(unsigned long *word, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, action, mode); } Index: linux-stable/kernel/sched/wait_bit.c =================================================================== --- linux-stable.orig/kernel/sched/wait_bit.c 2022-09-30 15:44:48.000000000 +0200 +++ linux-stable/kernel/sched/wait_bit.c 2022-09-30 15:44:48.000000000 +0200 @@ -46,7 +46,7 @@ __wait_on_bit(struct wait_queue_head *wq prepare_to_wait(wq_head, &wbq_entry->wq_entry, mode); if (test_bit(wbq_entry->key.bit_nr, wbq_entry->key.flags)) ret = (*action)(&wbq_entry->key, mode); - } while (test_bit(wbq_entry->key.bit_nr, wbq_entry->key.flags) && !ret); + } while (test_bit_acquire(wbq_entry->key.bit_nr, wbq_entry->key.flags) && !ret);
finish_wait(wq_head, &wbq_entry->wq_entry);
This is backport of the upstream patch 8238b4579866b7c1bb99883cfe102a43db5506ff for the stable branch 4.14
Signed-off-by: Mikulas Patocka mpatocka@redhat.com
--- arch/x86/include/asm/bitops.h | 21 +++++++++++++++++++++ include/asm-generic/bitops/non-atomic.h | 14 ++++++++++++++ include/linux/buffer_head.h | 2 +- include/linux/wait_bit.h | 8 ++++---- kernel/sched/wait_bit.c | 2 +- 5 files changed, 41 insertions(+), 6 deletions(-)
Index: linux-stable/arch/x86/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/x86/include/asm/bitops.h 2022-09-30 15:55:01.000000000 +0200 +++ linux-stable/arch/x86/include/asm/bitops.h 2022-09-30 15:55:01.000000000 +0200 @@ -328,6 +328,20 @@ static __always_inline bool constant_tes (addr[nr >> _BITOPS_LONG_SHIFT])) != 0; }
+static __always_inline bool constant_test_bit_acquire(long nr, const volatile unsigned long *addr) +{ + bool oldbit; + + asm volatile("testb %2,%1" + CC_SET(nz) + : CC_OUT(nz) (oldbit) + : "m" (((unsigned char *)addr)[nr >> 3]), + "i" (1 << (nr & 7)) + :"memory"); + + return oldbit; +} + static __always_inline bool variable_test_bit(long nr, volatile const unsigned long *addr) { bool oldbit; @@ -354,6 +368,13 @@ static bool test_bit(int nr, const volat ? constant_test_bit((nr), (addr)) \ : variable_test_bit((nr), (addr)))
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + return __builtin_constant_p(nr) ? constant_test_bit_acquire(nr, addr) : + variable_test_bit(nr, addr); +} + /** * __ffs - find first set bit in word * @word: The word to search Index: linux-stable/include/asm-generic/bitops/non-atomic.h =================================================================== --- linux-stable.orig/include/asm-generic/bitops/non-atomic.h 2022-09-30 15:55:01.000000000 +0200 +++ linux-stable/include/asm-generic/bitops/non-atomic.h 2022-09-30 15:55:01.000000000 +0200 @@ -3,6 +3,7 @@ #define _ASM_GENERIC_BITOPS_NON_ATOMIC_H_
#include <asm/types.h> +#include <asm/barrier.h>
/** * __set_bit - Set a bit in memory @@ -106,4 +107,17 @@ static inline int test_bit(int nr, const return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); }
+/** + * arch_test_bit_acquire - Determine, with acquire semantics, whether a bit is set + * @nr: bit number to test + * @addr: Address to start counting from + */ +static __always_inline bool +arch_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} +#define test_bit_acquire arch_test_bit_acquire + #endif /* _ASM_GENERIC_BITOPS_NON_ATOMIC_H_ */ Index: linux-stable/include/linux/buffer_head.h =================================================================== --- linux-stable.orig/include/linux/buffer_head.h 2022-09-30 15:55:01.000000000 +0200 +++ linux-stable/include/linux/buffer_head.h 2022-09-30 15:55:01.000000000 +0200 @@ -163,7 +163,7 @@ static __always_inline int buffer_uptoda * make it consistent with folio_test_uptodate * pairs with smp_mb__before_atomic in set_buffer_uptodate */ - return (smp_load_acquire(&bh->b_state) & (1UL << BH_Uptodate)) != 0; + return test_bit_acquire(BH_Uptodate, &bh->b_state); }
#define bh_offset(bh) ((unsigned long)(bh)->b_data & ~PAGE_MASK) Index: linux-stable/include/linux/wait_bit.h =================================================================== --- linux-stable.orig/include/linux/wait_bit.h 2022-09-30 15:55:01.000000000 +0200 +++ linux-stable/include/linux/wait_bit.h 2022-09-30 15:55:01.000000000 +0200 @@ -76,7 +76,7 @@ static inline int wait_on_bit(unsigned long *word, int bit, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, bit_wait, @@ -101,7 +101,7 @@ static inline int wait_on_bit_io(unsigned long *word, int bit, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, bit_wait_io, @@ -128,7 +128,7 @@ wait_on_bit_timeout(unsigned long *word, unsigned long timeout) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit_timeout(word, bit, bit_wait_timeout, @@ -156,7 +156,7 @@ wait_on_bit_action(unsigned long *word, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, action, mode); } Index: linux-stable/kernel/sched/wait_bit.c =================================================================== --- linux-stable.orig/kernel/sched/wait_bit.c 2022-09-30 15:55:01.000000000 +0200 +++ linux-stable/kernel/sched/wait_bit.c 2022-09-30 15:55:55.000000000 +0200 @@ -49,7 +49,7 @@ __wait_on_bit(struct wait_queue_head *wq prepare_to_wait(wq_head, &wbq_entry->wq_entry, mode); if (test_bit(wbq_entry->key.bit_nr, wbq_entry->key.flags)) ret = (*action)(&wbq_entry->key, mode); - } while (test_bit(wbq_entry->key.bit_nr, wbq_entry->key.flags) && !ret); + } while (test_bit_acquire(wbq_entry->key.bit_nr, wbq_entry->key.flags) && !ret); finish_wait(wq_head, &wbq_entry->wq_entry); return ret; }
This is backport of the upstream patch 8238b4579866b7c1bb99883cfe102a43db5506ff for the stable branch 4.9
Signed-off-by: Mikulas Patocka mpatocka@redhat.com
--- arch/x86/include/asm/bitops.h | 21 +++++++++++++++++++++ include/asm-generic/bitops/non-atomic.h | 14 ++++++++++++++ include/linux/buffer_head.h | 2 +- include/linux/wait.h | 8 ++++---- kernel/sched/wait.c | 2 +- 5 files changed, 41 insertions(+), 6 deletions(-)
Index: linux-stable/arch/x86/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/x86/include/asm/bitops.h 2022-09-30 16:01:38.000000000 +0200 +++ linux-stable/arch/x86/include/asm/bitops.h 2022-09-30 16:01:38.000000000 +0200 @@ -314,6 +314,20 @@ static __always_inline bool constant_tes (addr[nr >> _BITOPS_LONG_SHIFT])) != 0; }
+static __always_inline bool constant_test_bit_acquire(long nr, const volatile unsigned long *addr) +{ + bool oldbit; + + asm volatile("testb %2,%1" + CC_SET(nz) + : CC_OUT(nz) (oldbit) + : "m" (((unsigned char *)addr)[nr >> 3]), + "i" (1 << (nr & 7)) + :"memory"); + + return oldbit; +} + static __always_inline bool variable_test_bit(long nr, volatile const unsigned long *addr) { bool oldbit; @@ -340,6 +354,13 @@ static bool test_bit(int nr, const volat ? constant_test_bit((nr), (addr)) \ : variable_test_bit((nr), (addr)))
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + return __builtin_constant_p(nr) ? constant_test_bit_acquire(nr, addr) : + variable_test_bit(nr, addr); +} + /** * __ffs - find first set bit in word * @word: The word to search Index: linux-stable/include/asm-generic/bitops/non-atomic.h =================================================================== --- linux-stable.orig/include/asm-generic/bitops/non-atomic.h 2022-09-30 16:01:38.000000000 +0200 +++ linux-stable/include/asm-generic/bitops/non-atomic.h 2022-09-30 16:01:38.000000000 +0200 @@ -2,6 +2,7 @@ #define _ASM_GENERIC_BITOPS_NON_ATOMIC_H_
#include <asm/types.h> +#include <asm/barrier.h>
/** * __set_bit - Set a bit in memory @@ -105,4 +106,17 @@ static inline int test_bit(int nr, const return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); }
+/** + * arch_test_bit_acquire - Determine, with acquire semantics, whether a bit is set + * @nr: bit number to test + * @addr: Address to start counting from + */ +static __always_inline bool +arch_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} +#define test_bit_acquire arch_test_bit_acquire + #endif /* _ASM_GENERIC_BITOPS_NON_ATOMIC_H_ */ Index: linux-stable/include/linux/buffer_head.h =================================================================== --- linux-stable.orig/include/linux/buffer_head.h 2022-09-30 16:01:38.000000000 +0200 +++ linux-stable/include/linux/buffer_head.h 2022-09-30 16:01:38.000000000 +0200 @@ -162,7 +162,7 @@ static __always_inline int buffer_uptoda * make it consistent with folio_test_uptodate * pairs with smp_mb__before_atomic in set_buffer_uptodate */ - return (smp_load_acquire(&bh->b_state) & (1UL << BH_Uptodate)) != 0; + return test_bit_acquire(BH_Uptodate, &bh->b_state); }
#define bh_offset(bh) ((unsigned long)(bh)->b_data & ~PAGE_MASK) Index: linux-stable/include/linux/wait.h =================================================================== --- linux-stable.orig/include/linux/wait.h 2022-09-30 16:01:38.000000000 +0200 +++ linux-stable/include/linux/wait.h 2022-09-30 16:01:38.000000000 +0200 @@ -1066,7 +1066,7 @@ static inline int wait_on_bit(unsigned long *word, int bit, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, bit_wait, @@ -1091,7 +1091,7 @@ static inline int wait_on_bit_io(unsigned long *word, int bit, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, bit_wait_io, @@ -1118,7 +1118,7 @@ wait_on_bit_timeout(unsigned long *word, unsigned long timeout) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit_timeout(word, bit, bit_wait_timeout, @@ -1146,7 +1146,7 @@ wait_on_bit_action(unsigned long *word, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, action, mode); } Index: linux-stable/kernel/sched/wait.c =================================================================== --- linux-stable.orig/kernel/sched/wait.c 2022-09-30 16:01:38.000000000 +0200 +++ linux-stable/kernel/sched/wait.c 2022-09-30 16:01:58.000000000 +0200 @@ -389,7 +389,7 @@ __wait_on_bit(wait_queue_head_t *wq, str prepare_to_wait(wq, &q->wait, mode); if (test_bit(q->key.bit_nr, q->key.flags)) ret = (*action)(&q->key, mode); - } while (test_bit(q->key.bit_nr, q->key.flags) && !ret); + } while (test_bit_acquire(q->key.bit_nr, q->key.flags) && !ret); finish_wait(wq, &q->wait); return ret; }
On Fri, Sep 30, 2022 at 11:34:55AM -0400, Mikulas Patocka wrote:
This is backport of the upstream patch 8238b4579866b7c1bb99883cfe102a43db5506ff for the stable branch 4.9
Signed-off-by: Mikulas Patocka mpatocka@redhat.com
Again, you lost all of the original changelog and authorship/review information here :(
And what order are these to be applied in? Please make a patch series for each stable/LTS tree they are to be backported to. Would you want to try to unwind this if you were the reciever of these emails?
thanks,
greg k-h
This is backport of the upstream patch d6ffe6067a54972564552ea45d320fb98db1ac5e for the stable branches 5.19, 5.15, 5.10
Signed-off-by: Mikulas Patocka mpatocka@redhat.com
--- arch/alpha/include/asm/bitops.h | 7 +++++++ arch/hexagon/include/asm/bitops.h | 15 +++++++++++++++ arch/ia64/include/asm/bitops.h | 7 +++++++ arch/m68k/include/asm/bitops.h | 6 ++++++ arch/s390/include/asm/bitops.h | 7 +++++++ arch/sh/include/asm/bitops-op32.h | 7 +++++++ 6 files changed, 49 insertions(+)
Index: linux-stable/arch/alpha/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/alpha/include/asm/bitops.h 2022-09-30 13:07:14.000000000 +0200 +++ linux-stable/arch/alpha/include/asm/bitops.h 2022-09-30 13:07:14.000000000 +0200 @@ -289,6 +289,13 @@ test_bit(int nr, const volatile void * a return (1UL & (((const int *) addr)[nr >> 5] >> (nr & 31))) != 0UL; }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + /* * ffz = Find First Zero in word. Undefined if no zero exists, * so code should check against ~0UL first.. Index: linux-stable/arch/hexagon/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/hexagon/include/asm/bitops.h 2022-09-30 13:07:14.000000000 +0200 +++ linux-stable/arch/hexagon/include/asm/bitops.h 2022-09-30 13:07:14.000000000 +0200 @@ -172,7 +172,22 @@ static inline int __test_bit(int nr, con return retval; }
+static inline int __test_bit_acquire(int nr, const volatile unsigned long *addr) +{ + int retval; + + asm volatile( + "{P0 = tstbit(%1,%2); if (P0.new) %0 = #1; if (!P0.new) %0 = #0;}\n" + : "=&r" (retval) + : "r" (addr[BIT_WORD(nr)]), "r" (nr % BITS_PER_LONG) + : "p0", "memory" + ); + + return retval; +} + #define test_bit(nr, addr) __test_bit(nr, addr) +#define test_bit_acquire(nr, addr) __test_bit_acquire(nr, addr)
/* * ffz - find first zero in word. Index: linux-stable/arch/ia64/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/ia64/include/asm/bitops.h 2022-09-30 13:07:14.000000000 +0200 +++ linux-stable/arch/ia64/include/asm/bitops.h 2022-09-30 13:07:14.000000000 +0200 @@ -337,6 +337,13 @@ test_bit (int nr, const volatile void *a return 1 & (((const volatile __u32 *) addr)[nr >> 5] >> (nr & 31)); }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + /** * ffz - find the first zero bit in a long word * @x: The long word to find the bit in Index: linux-stable/arch/m68k/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/m68k/include/asm/bitops.h 2022-09-30 13:07:14.000000000 +0200 +++ linux-stable/arch/m68k/include/asm/bitops.h 2022-09-30 13:07:14.000000000 +0200 @@ -153,6 +153,12 @@ static inline int test_bit(int nr, const return (vaddr[nr >> 5] & (1UL << (nr & 31))) != 0; }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +}
static inline int bset_reg_test_and_set_bit(int nr, volatile unsigned long *vaddr) Index: linux-stable/arch/s390/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/s390/include/asm/bitops.h 2022-09-30 13:07:14.000000000 +0200 +++ linux-stable/arch/s390/include/asm/bitops.h 2022-09-30 13:07:14.000000000 +0200 @@ -184,6 +184,13 @@ static inline bool arch_test_bit(unsigne return *addr & mask; }
+static __always_inline bool +arch_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + static inline bool arch_test_and_set_bit_lock(unsigned long nr, volatile unsigned long *ptr) { Index: linux-stable/arch/sh/include/asm/bitops-op32.h =================================================================== --- linux-stable.orig/arch/sh/include/asm/bitops-op32.h 2022-09-30 13:07:14.000000000 +0200 +++ linux-stable/arch/sh/include/asm/bitops-op32.h 2022-09-30 13:07:14.000000000 +0200 @@ -138,4 +138,11 @@ static inline int test_bit(int nr, const return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + #endif /* __ASM_SH_BITOPS_OP32_H */
This is backport of the upstream patch d6ffe6067a54972564552ea45d320fb98db1ac5e for the stable branch 5.4
Signed-off-by: Mikulas Patocka mpatocka@redhat.com
--- arch/alpha/include/asm/bitops.h | 7 +++++++ arch/hexagon/include/asm/bitops.h | 15 +++++++++++++++ arch/ia64/include/asm/bitops.h | 7 +++++++ arch/m68k/include/asm/bitops.h | 6 ++++++ arch/s390/include/asm/bitops.h | 7 +++++++ arch/sh/include/asm/bitops-op32.h | 7 +++++++ 6 files changed, 49 insertions(+)
Index: linux-stable/arch/alpha/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/alpha/include/asm/bitops.h 2022-09-30 15:39:09.000000000 +0200 +++ linux-stable/arch/alpha/include/asm/bitops.h 2022-09-30 15:39:09.000000000 +0200 @@ -289,6 +289,13 @@ test_bit(int nr, const volatile void * a return (1UL & (((const int *) addr)[nr >> 5] >> (nr & 31))) != 0UL; }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + /* * ffz = Find First Zero in word. Undefined if no zero exists, * so code should check against ~0UL first.. Index: linux-stable/arch/hexagon/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/hexagon/include/asm/bitops.h 2022-09-30 15:39:09.000000000 +0200 +++ linux-stable/arch/hexagon/include/asm/bitops.h 2022-09-30 15:39:09.000000000 +0200 @@ -172,7 +172,22 @@ static inline int __test_bit(int nr, con return retval; }
+static inline int __test_bit_acquire(int nr, const volatile unsigned long *addr) +{ + int retval; + + asm volatile( + "{P0 = tstbit(%1,%2); if (P0.new) %0 = #1; if (!P0.new) %0 = #0;}\n" + : "=&r" (retval) + : "r" (addr[BIT_WORD(nr)]), "r" (nr % BITS_PER_LONG) + : "p0", "memory" + ); + + return retval; +} + #define test_bit(nr, addr) __test_bit(nr, addr) +#define test_bit_acquire(nr, addr) __test_bit_acquire(nr, addr)
/* * ffz - find first zero in word. Index: linux-stable/arch/ia64/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/ia64/include/asm/bitops.h 2022-09-30 15:39:09.000000000 +0200 +++ linux-stable/arch/ia64/include/asm/bitops.h 2022-09-30 15:39:09.000000000 +0200 @@ -337,6 +337,13 @@ test_bit (int nr, const volatile void *a return 1 & (((const volatile __u32 *) addr)[nr >> 5] >> (nr & 31)); }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + /** * ffz - find the first zero bit in a long word * @x: The long word to find the bit in Index: linux-stable/arch/m68k/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/m68k/include/asm/bitops.h 2022-09-30 15:39:09.000000000 +0200 +++ linux-stable/arch/m68k/include/asm/bitops.h 2022-09-30 15:39:09.000000000 +0200 @@ -153,6 +153,12 @@ static inline int test_bit(int nr, const return (vaddr[nr >> 5] & (1UL << (nr & 31))) != 0; }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +}
static inline int bset_reg_test_and_set_bit(int nr, volatile unsigned long *vaddr) Index: linux-stable/arch/s390/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/s390/include/asm/bitops.h 2022-09-30 15:39:09.000000000 +0200 +++ linux-stable/arch/s390/include/asm/bitops.h 2022-09-30 15:39:09.000000000 +0200 @@ -219,6 +219,13 @@ static inline bool arch_test_bit(unsigne return (*addr >> (nr & 7)) & 1; }
+static __always_inline bool +arch_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + static inline bool arch_test_and_set_bit_lock(unsigned long nr, volatile unsigned long *ptr) { Index: linux-stable/arch/sh/include/asm/bitops-op32.h =================================================================== --- linux-stable.orig/arch/sh/include/asm/bitops-op32.h 2022-09-30 15:39:09.000000000 +0200 +++ linux-stable/arch/sh/include/asm/bitops-op32.h 2022-09-30 15:39:09.000000000 +0200 @@ -140,4 +140,11 @@ static inline int test_bit(int nr, const return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + #endif /* __ASM_SH_BITOPS_OP32_H */
This is backport of the upstream patch d6ffe6067a54972564552ea45d320fb98db1ac5e for the stable branch 4.19
Signed-off-by: Mikulas Patocka mpatocka@redhat.com
--- arch/alpha/include/asm/bitops.h | 7 +++++++ arch/hexagon/include/asm/bitops.h | 15 +++++++++++++++ arch/ia64/include/asm/bitops.h | 7 +++++++ arch/m68k/include/asm/bitops.h | 6 ++++++ arch/s390/include/asm/bitops.h | 7 +++++++ arch/sh/include/asm/bitops-op32.h | 7 +++++++ 6 files changed, 49 insertions(+)
Index: linux-stable/arch/alpha/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/alpha/include/asm/bitops.h 2022-09-30 15:48:24.000000000 +0200 +++ linux-stable/arch/alpha/include/asm/bitops.h 2022-09-30 15:48:24.000000000 +0200 @@ -289,6 +289,13 @@ test_bit(int nr, const volatile void * a return (1UL & (((const int *) addr)[nr >> 5] >> (nr & 31))) != 0UL; }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + /* * ffz = Find First Zero in word. Undefined if no zero exists, * so code should check against ~0UL first.. Index: linux-stable/arch/hexagon/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/hexagon/include/asm/bitops.h 2022-09-30 15:48:24.000000000 +0200 +++ linux-stable/arch/hexagon/include/asm/bitops.h 2022-09-30 15:48:24.000000000 +0200 @@ -186,7 +186,22 @@ static inline int __test_bit(int nr, con return retval; }
+static inline int __test_bit_acquire(int nr, const volatile unsigned long *addr) +{ + int retval; + + asm volatile( + "{P0 = tstbit(%1,%2); if (P0.new) %0 = #1; if (!P0.new) %0 = #0;}\n" + : "=&r" (retval) + : "r" (addr[BIT_WORD(nr)]), "r" (nr % BITS_PER_LONG) + : "p0", "memory" + ); + + return retval; +} + #define test_bit(nr, addr) __test_bit(nr, addr) +#define test_bit_acquire(nr, addr) __test_bit_acquire(nr, addr)
/* * ffz - find first zero in word. Index: linux-stable/arch/ia64/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/ia64/include/asm/bitops.h 2022-09-30 15:48:24.000000000 +0200 +++ linux-stable/arch/ia64/include/asm/bitops.h 2022-09-30 15:48:24.000000000 +0200 @@ -337,6 +337,13 @@ test_bit (int nr, const volatile void *a return 1 & (((const volatile __u32 *) addr)[nr >> 5] >> (nr & 31)); }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + /** * ffz - find the first zero bit in a long word * @x: The long word to find the bit in Index: linux-stable/arch/m68k/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/m68k/include/asm/bitops.h 2022-09-30 15:48:24.000000000 +0200 +++ linux-stable/arch/m68k/include/asm/bitops.h 2022-09-30 15:48:24.000000000 +0200 @@ -153,6 +153,12 @@ static inline int test_bit(int nr, const return (vaddr[nr >> 5] & (1UL << (nr & 31))) != 0; }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +}
static inline int bset_reg_test_and_set_bit(int nr, volatile unsigned long *vaddr) Index: linux-stable/arch/s390/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/s390/include/asm/bitops.h 2022-09-30 15:48:24.000000000 +0200 +++ linux-stable/arch/s390/include/asm/bitops.h 2022-09-30 15:49:53.000000000 +0200 @@ -215,6 +215,13 @@ static inline int test_bit(unsigned long return (*addr >> (nr & 7)) & 1; }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + static inline int test_and_set_bit_lock(unsigned long nr, volatile unsigned long *ptr) { Index: linux-stable/arch/sh/include/asm/bitops-op32.h =================================================================== --- linux-stable.orig/arch/sh/include/asm/bitops-op32.h 2022-09-30 15:48:24.000000000 +0200 +++ linux-stable/arch/sh/include/asm/bitops-op32.h 2022-09-30 15:48:24.000000000 +0200 @@ -140,4 +140,11 @@ static inline int test_bit(int nr, const return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + #endif /* __ASM_SH_BITOPS_OP32_H */
This is backport of the upstream patch d6ffe6067a54972564552ea45d320fb98db1ac5e for the stable branch 4.14
Signed-off-by: Mikulas Patocka mpatocka@redhat.com
--- arch/alpha/include/asm/bitops.h | 7 +++++++ arch/hexagon/include/asm/bitops.h | 15 +++++++++++++++ arch/ia64/include/asm/bitops.h | 7 +++++++ arch/m68k/include/asm/bitops.h | 6 ++++++ arch/s390/include/asm/bitops.h | 7 +++++++ arch/sh/include/asm/bitops-op32.h | 7 +++++++ 6 files changed, 49 insertions(+)
Index: linux-stable/arch/alpha/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/alpha/include/asm/bitops.h 2022-09-30 15:48:24.000000000 +0200 +++ linux-stable/arch/alpha/include/asm/bitops.h 2022-09-30 15:48:24.000000000 +0200 @@ -289,6 +289,13 @@ test_bit(int nr, const volatile void * a return (1UL & (((const int *) addr)[nr >> 5] >> (nr & 31))) != 0UL; }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + /* * ffz = Find First Zero in word. Undefined if no zero exists, * so code should check against ~0UL first.. Index: linux-stable/arch/hexagon/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/hexagon/include/asm/bitops.h 2022-09-30 15:48:24.000000000 +0200 +++ linux-stable/arch/hexagon/include/asm/bitops.h 2022-09-30 15:48:24.000000000 +0200 @@ -186,7 +186,22 @@ static inline int __test_bit(int nr, con return retval; }
+static inline int __test_bit_acquire(int nr, const volatile unsigned long *addr) +{ + int retval; + + asm volatile( + "{P0 = tstbit(%1,%2); if (P0.new) %0 = #1; if (!P0.new) %0 = #0;}\n" + : "=&r" (retval) + : "r" (addr[BIT_WORD(nr)]), "r" (nr % BITS_PER_LONG) + : "p0", "memory" + ); + + return retval; +} + #define test_bit(nr, addr) __test_bit(nr, addr) +#define test_bit_acquire(nr, addr) __test_bit_acquire(nr, addr)
/* * ffz - find first zero in word. Index: linux-stable/arch/ia64/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/ia64/include/asm/bitops.h 2022-09-30 15:48:24.000000000 +0200 +++ linux-stable/arch/ia64/include/asm/bitops.h 2022-09-30 15:48:24.000000000 +0200 @@ -337,6 +337,13 @@ test_bit (int nr, const volatile void *a return 1 & (((const volatile __u32 *) addr)[nr >> 5] >> (nr & 31)); }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + /** * ffz - find the first zero bit in a long word * @x: The long word to find the bit in Index: linux-stable/arch/m68k/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/m68k/include/asm/bitops.h 2022-09-30 15:48:24.000000000 +0200 +++ linux-stable/arch/m68k/include/asm/bitops.h 2022-09-30 15:48:24.000000000 +0200 @@ -153,6 +153,12 @@ static inline int test_bit(int nr, const return (vaddr[nr >> 5] & (1UL << (nr & 31))) != 0; }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +}
static inline int bset_reg_test_and_set_bit(int nr, volatile unsigned long *vaddr) Index: linux-stable/arch/s390/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/s390/include/asm/bitops.h 2022-09-30 15:48:24.000000000 +0200 +++ linux-stable/arch/s390/include/asm/bitops.h 2022-09-30 15:49:53.000000000 +0200 @@ -215,6 +215,13 @@ static inline int test_bit(unsigned long return (*addr >> (nr & 7)) & 1; }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + static inline int test_and_set_bit_lock(unsigned long nr, volatile unsigned long *ptr) { Index: linux-stable/arch/sh/include/asm/bitops-op32.h =================================================================== --- linux-stable.orig/arch/sh/include/asm/bitops-op32.h 2022-09-30 15:48:24.000000000 +0200 +++ linux-stable/arch/sh/include/asm/bitops-op32.h 2022-09-30 15:48:24.000000000 +0200 @@ -140,4 +140,11 @@ static inline int test_bit(int nr, const return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + #endif /* __ASM_SH_BITOPS_OP32_H */
This is backport of the upstream patch d6ffe6067a54972564552ea45d320fb98db1ac5e for the stable branch 4.9
Signed-off-by: Mikulas Patocka mpatocka@redhat.com
--- arch/alpha/include/asm/bitops.h | 7 +++++++ arch/hexagon/include/asm/bitops.h | 15 +++++++++++++++ arch/ia64/include/asm/bitops.h | 7 +++++++ arch/m68k/include/asm/bitops.h | 6 ++++++ arch/s390/include/asm/bitops.h | 7 +++++++ arch/sh/include/asm/bitops-op32.h | 7 +++++++ 6 files changed, 49 insertions(+)
Index: linux-stable/arch/alpha/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/alpha/include/asm/bitops.h 2022-09-30 16:03:22.000000000 +0200 +++ linux-stable/arch/alpha/include/asm/bitops.h 2022-09-30 16:03:22.000000000 +0200 @@ -288,6 +288,13 @@ test_bit(int nr, const volatile void * a return (1UL & (((const int *) addr)[nr >> 5] >> (nr & 31))) != 0UL; }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + /* * ffz = Find First Zero in word. Undefined if no zero exists, * so code should check against ~0UL first.. Index: linux-stable/arch/hexagon/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/hexagon/include/asm/bitops.h 2022-09-30 16:03:22.000000000 +0200 +++ linux-stable/arch/hexagon/include/asm/bitops.h 2022-09-30 16:03:22.000000000 +0200 @@ -186,7 +186,22 @@ static inline int __test_bit(int nr, con return retval; }
+static inline int __test_bit_acquire(int nr, const volatile unsigned long *addr) +{ + int retval; + + asm volatile( + "{P0 = tstbit(%1,%2); if (P0.new) %0 = #1; if (!P0.new) %0 = #0;}\n" + : "=&r" (retval) + : "r" (addr[BIT_WORD(nr)]), "r" (nr % BITS_PER_LONG) + : "p0", "memory" + ); + + return retval; +} + #define test_bit(nr, addr) __test_bit(nr, addr) +#define test_bit_acquire(nr, addr) __test_bit_acquire(nr, addr)
/* * ffz - find first zero in word. Index: linux-stable/arch/ia64/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/ia64/include/asm/bitops.h 2022-09-30 16:03:22.000000000 +0200 +++ linux-stable/arch/ia64/include/asm/bitops.h 2022-09-30 16:03:22.000000000 +0200 @@ -336,6 +336,13 @@ test_bit (int nr, const volatile void *a return 1 & (((const volatile __u32 *) addr)[nr >> 5] >> (nr & 31)); }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + /** * ffz - find the first zero bit in a long word * @x: The long word to find the bit in Index: linux-stable/arch/m68k/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/m68k/include/asm/bitops.h 2022-09-30 16:03:22.000000000 +0200 +++ linux-stable/arch/m68k/include/asm/bitops.h 2022-09-30 16:03:22.000000000 +0200 @@ -153,6 +153,12 @@ static inline int test_bit(int nr, const return (vaddr[nr >> 5] & (1UL << (nr & 31))) != 0; }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +}
static inline int bset_reg_test_and_set_bit(int nr, volatile unsigned long *vaddr) Index: linux-stable/arch/s390/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/s390/include/asm/bitops.h 2022-09-30 16:03:22.000000000 +0200 +++ linux-stable/arch/s390/include/asm/bitops.h 2022-09-30 16:03:22.000000000 +0200 @@ -270,6 +270,13 @@ static inline int test_bit(unsigned long return (*addr >> (nr & 7)) & 1; }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + static inline int test_and_set_bit_lock(unsigned long nr, volatile unsigned long *ptr) { Index: linux-stable/arch/sh/include/asm/bitops-op32.h =================================================================== --- linux-stable.orig/arch/sh/include/asm/bitops-op32.h 2022-09-30 16:03:22.000000000 +0200 +++ linux-stable/arch/sh/include/asm/bitops-op32.h 2022-09-30 16:03:22.000000000 +0200 @@ -139,4 +139,11 @@ static inline int test_bit(int nr, const return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + #endif /* __ASM_SH_BITOPS_OP32_H */
On Fri, Sep 30, 2022 at 11:36:52AM -0400, Mikulas Patocka wrote:
This is backport of the upstream patch d6ffe6067a54972564552ea45d320fb98db1ac5e for the stable branch 4.9
Signed-off-by: Mikulas Patocka mpatocka@redhat.com
What happened to the original changelog information and the original signed-off-by information?
Please keep that when backporting changes. Fix that up for all of these when you resend.
thanks,
greg k-h
On Fri, Sep 30, 2022 at 11:32:30AM -0400, Mikulas Patocka wrote:
Hi
Here I'm submitting backport of patches 8238b4579866b7c1bb99883cfe102a43db5506ff and d6ffe6067a54972564552ea45d320fb98db1ac5e to the stable branches.
Thanks, but you provide no information as to why these are needed.
What needs them? They are just adding new functions to the tree from what I can tell.
thanks,
greg k-h
On Sat, 1 Oct 2022, Greg KH wrote:
On Fri, Sep 30, 2022 at 11:32:30AM -0400, Mikulas Patocka wrote:
Hi
Here I'm submitting backport of patches 8238b4579866b7c1bb99883cfe102a43db5506ff and d6ffe6067a54972564552ea45d320fb98db1ac5e to the stable branches.
Thanks, but you provide no information as to why these are needed.
What needs them? They are just adding new functions to the tree from what I can tell.
thanks,
greg k-h
There's a race condition in wait_on_bit. wait_on_bit tests a bit using the "test_bit" function, however this function doesn't do any memory barrier, so the memory accesses that follow wait_on_bit may be reordered before it and return invalid data.
Linus didn't want to add a memory barrier to wait_on_bit, he instead wanted to introduce a new function test_bit_acquire that performs the "acquire" memory barrier and use it in wait_on_bit.
The patch d6ffe6067a54972564552ea45d320fb98db1ac5e fixes an oversight in the patch 8238b4579866b7c1bb99883cfe102a43db5506ff where the function test_bit_acquire was not defined for some architectures and this caused compile failure.
The backport of the patch 8238b4579866b7c1bb99883cfe102a43db5506ff should be applied first and the backport of the patch d6ffe6067a54972564552ea45d320fb98db1ac5e afterwards.
Mikulas
This is backport of the upstream patch 8238b4579866b7c1bb99883cfe102a43db5506ff for the stable branches 5.10, 5.15, 5.19
wait_on_bit: add an acquire memory barrier
There are several places in the kernel where wait_on_bit is not followed by a memory barrier (for example, in drivers/md/dm-bufio.c:new_read).
On architectures with weak memory ordering, it may happen that memory accesses that follow wait_on_bit are reordered before wait_on_bit and they may return invalid data.
Fix this class of bugs by introducing a new function "test_bit_acquire" that works like test_bit, but has acquire memory ordering semantics.
Signed-off-by: Mikulas Patocka mpatocka@redhat.com Acked-by: Will Deacon will@kernel.org Cc: stable@vger.kernel.org Signed-off-by: Linus Torvalds torvalds@linux-foundation.org
--- arch/x86/include/asm/bitops.h | 21 +++++++++++++++++++ include/asm-generic/bitops/instrumented-non-atomic.h | 12 ++++++++++ include/asm-generic/bitops/non-atomic.h | 14 ++++++++++++ include/linux/buffer_head.h | 2 - include/linux/wait_bit.h | 8 +++---- kernel/sched/wait_bit.c | 2 - 6 files changed, 53 insertions(+), 6 deletions(-)
Index: linux-stable/arch/x86/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/x86/include/asm/bitops.h 2022-09-30 13:07:11.000000000 +0200 +++ linux-stable/arch/x86/include/asm/bitops.h 2022-09-30 13:07:11.000000000 +0200 @@ -207,6 +207,20 @@ static __always_inline bool constant_tes (addr[nr >> _BITOPS_LONG_SHIFT])) != 0; }
+static __always_inline bool constant_test_bit_acquire(long nr, const volatile unsigned long *addr) +{ + bool oldbit; + + asm volatile("testb %2,%1" + CC_SET(nz) + : CC_OUT(nz) (oldbit) + : "m" (((unsigned char *)addr)[nr >> 3]), + "i" (1 << (nr & 7)) + :"memory"); + + return oldbit; +} + static __always_inline bool variable_test_bit(long nr, volatile const unsigned long *addr) { bool oldbit; @@ -224,6 +238,13 @@ static __always_inline bool variable_tes ? constant_test_bit((nr), (addr)) \ : variable_test_bit((nr), (addr)))
+static __always_inline bool +arch_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + return __builtin_constant_p(nr) ? constant_test_bit_acquire(nr, addr) : + variable_test_bit(nr, addr); +} + /** * __ffs - find first set bit in word * @word: The word to search Index: linux-stable/include/asm-generic/bitops/instrumented-non-atomic.h =================================================================== --- linux-stable.orig/include/asm-generic/bitops/instrumented-non-atomic.h 2022-09-30 13:07:11.000000000 +0200 +++ linux-stable/include/asm-generic/bitops/instrumented-non-atomic.h 2022-09-30 13:07:11.000000000 +0200 @@ -135,4 +135,16 @@ static __always_inline bool test_bit(lon return arch_test_bit(nr, addr); }
+/** + * _test_bit_acquire - Determine, with acquire semantics, whether a bit is set + * @nr: bit number to test + * @addr: Address to start counting from + */ +static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + instrument_atomic_read(addr + BIT_WORD(nr), sizeof(long)); + return arch_test_bit_acquire(nr, addr); +} + #endif /* _ASM_GENERIC_BITOPS_INSTRUMENTED_NON_ATOMIC_H */ Index: linux-stable/include/asm-generic/bitops/non-atomic.h =================================================================== --- linux-stable.orig/include/asm-generic/bitops/non-atomic.h 2022-09-30 13:07:11.000000000 +0200 +++ linux-stable/include/asm-generic/bitops/non-atomic.h 2022-09-30 13:07:11.000000000 +0200 @@ -3,6 +3,7 @@ #define _ASM_GENERIC_BITOPS_NON_ATOMIC_H_
#include <asm/types.h> +#include <asm/barrier.h>
/** * arch___set_bit - Set a bit in memory @@ -119,4 +120,17 @@ arch_test_bit(unsigned int nr, const vol } #define test_bit arch_test_bit
+/** + * arch_test_bit_acquire - Determine, with acquire semantics, whether a bit is set + * @nr: bit number to test + * @addr: Address to start counting from + */ +static __always_inline bool +arch_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} +#define test_bit_acquire arch_test_bit_acquire + #endif /* _ASM_GENERIC_BITOPS_NON_ATOMIC_H_ */ Index: linux-stable/include/linux/buffer_head.h =================================================================== --- linux-stable.orig/include/linux/buffer_head.h 2022-09-30 13:07:11.000000000 +0200 +++ linux-stable/include/linux/buffer_head.h 2022-09-30 13:07:11.000000000 +0200 @@ -166,7 +166,7 @@ static __always_inline int buffer_uptoda * make it consistent with folio_test_uptodate * pairs with smp_mb__before_atomic in set_buffer_uptodate */ - return (smp_load_acquire(&bh->b_state) & (1UL << BH_Uptodate)) != 0; + return test_bit_acquire(BH_Uptodate, &bh->b_state); }
#define bh_offset(bh) ((unsigned long)(bh)->b_data & ~PAGE_MASK) Index: linux-stable/include/linux/wait_bit.h =================================================================== --- linux-stable.orig/include/linux/wait_bit.h 2022-09-30 13:07:11.000000000 +0200 +++ linux-stable/include/linux/wait_bit.h 2022-09-30 13:07:11.000000000 +0200 @@ -71,7 +71,7 @@ static inline int wait_on_bit(unsigned long *word, int bit, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, bit_wait, @@ -96,7 +96,7 @@ static inline int wait_on_bit_io(unsigned long *word, int bit, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, bit_wait_io, @@ -123,7 +123,7 @@ wait_on_bit_timeout(unsigned long *word, unsigned long timeout) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit_timeout(word, bit, bit_wait_timeout, @@ -151,7 +151,7 @@ wait_on_bit_action(unsigned long *word, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, action, mode); } Index: linux-stable/kernel/sched/wait_bit.c =================================================================== --- linux-stable.orig/kernel/sched/wait_bit.c 2022-09-30 13:07:11.000000000 +0200 +++ linux-stable/kernel/sched/wait_bit.c 2022-09-30 13:07:11.000000000 +0200 @@ -47,7 +47,7 @@ __wait_on_bit(struct wait_queue_head *wq prepare_to_wait(wq_head, &wbq_entry->wq_entry, mode); if (test_bit(wbq_entry->key.bit_nr, wbq_entry->key.flags)) ret = (*action)(&wbq_entry->key, mode); - } while (test_bit(wbq_entry->key.bit_nr, wbq_entry->key.flags) && !ret); + } while (test_bit_acquire(wbq_entry->key.bit_nr, wbq_entry->key.flags) && !ret);
finish_wait(wq_head, &wbq_entry->wq_entry);
This is backport of the upstream patch 8238b4579866b7c1bb99883cfe102a43db5506ff for the stable branch 5.4
wait_on_bit: add an acquire memory barrier
There are several places in the kernel where wait_on_bit is not followed by a memory barrier (for example, in drivers/md/dm-bufio.c:new_read).
On architectures with weak memory ordering, it may happen that memory accesses that follow wait_on_bit are reordered before wait_on_bit and they may return invalid data.
Fix this class of bugs by introducing a new function "test_bit_acquire" that works like test_bit, but has acquire memory ordering semantics.
Signed-off-by: Mikulas Patocka mpatocka@redhat.com Acked-by: Will Deacon will@kernel.org Cc: stable@vger.kernel.org Signed-off-by: Linus Torvalds torvalds@linux-foundation.org
--- arch/x86/include/asm/bitops.h | 21 +++++++++++++++++++++ include/asm-generic/bitops-instrumented.h | 6 ++++++ include/asm-generic/bitops/non-atomic.h | 14 ++++++++++++++ include/linux/buffer_head.h | 2 +- include/linux/wait_bit.h | 8 ++++---- kernel/sched/wait_bit.c | 2 +- 6 files changed, 47 insertions(+), 6 deletions(-)
Index: linux-stable/arch/x86/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/x86/include/asm/bitops.h 2022-09-30 15:38:29.000000000 +0200 +++ linux-stable/arch/x86/include/asm/bitops.h 2022-09-30 15:38:29.000000000 +0200 @@ -207,6 +207,20 @@ static __always_inline bool constant_tes (addr[nr >> _BITOPS_LONG_SHIFT])) != 0; }
+static __always_inline bool constant_test_bit_acquire(long nr, const volatile unsigned long *addr) +{ + bool oldbit; + + asm volatile("testb %2,%1" + CC_SET(nz) + : CC_OUT(nz) (oldbit) + : "m" (((unsigned char *)addr)[nr >> 3]), + "i" (1 << (nr & 7)) + :"memory"); + + return oldbit; +} + static __always_inline bool variable_test_bit(long nr, volatile const unsigned long *addr) { bool oldbit; @@ -224,6 +238,13 @@ static __always_inline bool variable_tes ? constant_test_bit((nr), (addr)) \ : variable_test_bit((nr), (addr)))
+static __always_inline bool +arch_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + return __builtin_constant_p(nr) ? constant_test_bit_acquire(nr, addr) : + variable_test_bit(nr, addr); +} + /** * __ffs - find first set bit in word * @word: The word to search Index: linux-stable/include/asm-generic/bitops/non-atomic.h =================================================================== --- linux-stable.orig/include/asm-generic/bitops/non-atomic.h 2022-09-30 15:38:29.000000000 +0200 +++ linux-stable/include/asm-generic/bitops/non-atomic.h 2022-09-30 15:38:29.000000000 +0200 @@ -3,6 +3,7 @@ #define _ASM_GENERIC_BITOPS_NON_ATOMIC_H_
#include <asm/types.h> +#include <asm/barrier.h>
/** * __set_bit - Set a bit in memory @@ -106,4 +107,17 @@ static inline int test_bit(int nr, const return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); }
+/** + * arch_test_bit_acquire - Determine, with acquire semantics, whether a bit is set + * @nr: bit number to test + * @addr: Address to start counting from + */ +static __always_inline bool +arch_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} +#define test_bit_acquire arch_test_bit_acquire + #endif /* _ASM_GENERIC_BITOPS_NON_ATOMIC_H_ */ Index: linux-stable/include/linux/buffer_head.h =================================================================== --- linux-stable.orig/include/linux/buffer_head.h 2022-09-30 15:38:29.000000000 +0200 +++ linux-stable/include/linux/buffer_head.h 2022-09-30 15:38:29.000000000 +0200 @@ -166,7 +166,7 @@ static __always_inline int buffer_uptoda * make it consistent with folio_test_uptodate * pairs with smp_mb__before_atomic in set_buffer_uptodate */ - return (smp_load_acquire(&bh->b_state) & (1UL << BH_Uptodate)) != 0; + return test_bit_acquire(BH_Uptodate, &bh->b_state); }
#define bh_offset(bh) ((unsigned long)(bh)->b_data & ~PAGE_MASK) Index: linux-stable/include/linux/wait_bit.h =================================================================== --- linux-stable.orig/include/linux/wait_bit.h 2022-09-30 15:38:29.000000000 +0200 +++ linux-stable/include/linux/wait_bit.h 2022-09-30 15:38:29.000000000 +0200 @@ -71,7 +71,7 @@ static inline int wait_on_bit(unsigned long *word, int bit, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, bit_wait, @@ -96,7 +96,7 @@ static inline int wait_on_bit_io(unsigned long *word, int bit, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, bit_wait_io, @@ -123,7 +123,7 @@ wait_on_bit_timeout(unsigned long *word, unsigned long timeout) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit_timeout(word, bit, bit_wait_timeout, @@ -151,7 +151,7 @@ wait_on_bit_action(unsigned long *word, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, action, mode); } Index: linux-stable/kernel/sched/wait_bit.c =================================================================== --- linux-stable.orig/kernel/sched/wait_bit.c 2022-09-30 15:38:29.000000000 +0200 +++ linux-stable/kernel/sched/wait_bit.c 2022-09-30 15:38:29.000000000 +0200 @@ -47,7 +47,7 @@ __wait_on_bit(struct wait_queue_head *wq prepare_to_wait(wq_head, &wbq_entry->wq_entry, mode); if (test_bit(wbq_entry->key.bit_nr, wbq_entry->key.flags)) ret = (*action)(&wbq_entry->key, mode); - } while (test_bit(wbq_entry->key.bit_nr, wbq_entry->key.flags) && !ret); + } while (test_bit_acquire(wbq_entry->key.bit_nr, wbq_entry->key.flags) && !ret);
finish_wait(wq_head, &wbq_entry->wq_entry);
Index: linux-stable/include/asm-generic/bitops-instrumented.h =================================================================== --- linux-stable.orig/include/asm-generic/bitops-instrumented.h 2022-09-30 15:37:42.000000000 +0200 +++ linux-stable/include/asm-generic/bitops-instrumented.h 2022-09-30 15:40:55.000000000 +0200 @@ -238,6 +238,12 @@ static inline bool test_bit(long nr, con return arch_test_bit(nr, addr); }
+static inline bool test_bit_acquire(long nr, const volatile unsigned long *addr) +{ + kasan_check_read(addr + BIT_WORD(nr), sizeof(long)); + return arch_test_bit_acquire(nr, addr); +} + #if defined(arch_clear_bit_unlock_is_negative_byte) /** * clear_bit_unlock_is_negative_byte - Clear a bit in memory and test if bottom
This is backport of the upstream patch 8238b4579866b7c1bb99883cfe102a43db5506ff for the stable branch 4.19
wait_on_bit: add an acquire memory barrier
There are several places in the kernel where wait_on_bit is not followed by a memory barrier (for example, in drivers/md/dm-bufio.c:new_read).
On architectures with weak memory ordering, it may happen that memory accesses that follow wait_on_bit are reordered before wait_on_bit and they may return invalid data.
Fix this class of bugs by introducing a new function "test_bit_acquire" that works like test_bit, but has acquire memory ordering semantics.
Signed-off-by: Mikulas Patocka mpatocka@redhat.com Acked-by: Will Deacon will@kernel.org Cc: stable@vger.kernel.org Signed-off-by: Linus Torvalds torvalds@linux-foundation.org
--- arch/x86/include/asm/bitops.h | 21 +++++++++++++++++++++ include/asm-generic/bitops/non-atomic.h | 14 ++++++++++++++ include/linux/buffer_head.h | 2 +- include/linux/wait_bit.h | 8 ++++---- kernel/sched/wait_bit.c | 2 +- 5 files changed, 41 insertions(+), 6 deletions(-)
Index: linux-stable/arch/x86/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/x86/include/asm/bitops.h 2022-09-30 15:44:48.000000000 +0200 +++ linux-stable/arch/x86/include/asm/bitops.h 2022-09-30 15:46:38.000000000 +0200 @@ -317,6 +317,20 @@ static __always_inline bool constant_tes (addr[nr >> _BITOPS_LONG_SHIFT])) != 0; }
+static __always_inline bool constant_test_bit_acquire(long nr, const volatile unsigned long *addr) +{ + bool oldbit; + + asm volatile("testb %2,%1" + CC_SET(nz) + : CC_OUT(nz) (oldbit) + : "m" (((unsigned char *)addr)[nr >> 3]), + "i" (1 << (nr & 7)) + :"memory"); + + return oldbit; +} + static __always_inline bool variable_test_bit(long nr, volatile const unsigned long *addr) { bool oldbit; @@ -343,6 +357,13 @@ static bool test_bit(int nr, const volat ? constant_test_bit((nr), (addr)) \ : variable_test_bit((nr), (addr)))
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + return __builtin_constant_p(nr) ? constant_test_bit_acquire(nr, addr) : + variable_test_bit(nr, addr); +} + /** * __ffs - find first set bit in word * @word: The word to search Index: linux-stable/include/asm-generic/bitops/non-atomic.h =================================================================== --- linux-stable.orig/include/asm-generic/bitops/non-atomic.h 2022-09-30 15:44:48.000000000 +0200 +++ linux-stable/include/asm-generic/bitops/non-atomic.h 2022-09-30 15:44:48.000000000 +0200 @@ -3,6 +3,7 @@ #define _ASM_GENERIC_BITOPS_NON_ATOMIC_H_
#include <asm/types.h> +#include <asm/barrier.h>
/** * __set_bit - Set a bit in memory @@ -106,4 +107,17 @@ static inline int test_bit(int nr, const return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); }
+/** + * arch_test_bit_acquire - Determine, with acquire semantics, whether a bit is set + * @nr: bit number to test + * @addr: Address to start counting from + */ +static __always_inline bool +arch_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} +#define test_bit_acquire arch_test_bit_acquire + #endif /* _ASM_GENERIC_BITOPS_NON_ATOMIC_H_ */ Index: linux-stable/include/linux/buffer_head.h =================================================================== --- linux-stable.orig/include/linux/buffer_head.h 2022-09-30 15:44:48.000000000 +0200 +++ linux-stable/include/linux/buffer_head.h 2022-09-30 15:44:48.000000000 +0200 @@ -166,7 +166,7 @@ static __always_inline int buffer_uptoda * make it consistent with folio_test_uptodate * pairs with smp_mb__before_atomic in set_buffer_uptodate */ - return (smp_load_acquire(&bh->b_state) & (1UL << BH_Uptodate)) != 0; + return test_bit_acquire(BH_Uptodate, &bh->b_state); }
#define bh_offset(bh) ((unsigned long)(bh)->b_data & ~PAGE_MASK) Index: linux-stable/include/linux/wait_bit.h =================================================================== --- linux-stable.orig/include/linux/wait_bit.h 2022-09-30 15:44:48.000000000 +0200 +++ linux-stable/include/linux/wait_bit.h 2022-09-30 15:44:48.000000000 +0200 @@ -71,7 +71,7 @@ static inline int wait_on_bit(unsigned long *word, int bit, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, bit_wait, @@ -96,7 +96,7 @@ static inline int wait_on_bit_io(unsigned long *word, int bit, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, bit_wait_io, @@ -123,7 +123,7 @@ wait_on_bit_timeout(unsigned long *word, unsigned long timeout) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit_timeout(word, bit, bit_wait_timeout, @@ -151,7 +151,7 @@ wait_on_bit_action(unsigned long *word, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, action, mode); } Index: linux-stable/kernel/sched/wait_bit.c =================================================================== --- linux-stable.orig/kernel/sched/wait_bit.c 2022-09-30 15:44:48.000000000 +0200 +++ linux-stable/kernel/sched/wait_bit.c 2022-09-30 15:44:48.000000000 +0200 @@ -46,7 +46,7 @@ __wait_on_bit(struct wait_queue_head *wq prepare_to_wait(wq_head, &wbq_entry->wq_entry, mode); if (test_bit(wbq_entry->key.bit_nr, wbq_entry->key.flags)) ret = (*action)(&wbq_entry->key, mode); - } while (test_bit(wbq_entry->key.bit_nr, wbq_entry->key.flags) && !ret); + } while (test_bit_acquire(wbq_entry->key.bit_nr, wbq_entry->key.flags) && !ret);
finish_wait(wq_head, &wbq_entry->wq_entry);
This is backport of the upstream patch 8238b4579866b7c1bb99883cfe102a43db5506ff for the stable branch 4.14
wait_on_bit: add an acquire memory barrier
There are several places in the kernel where wait_on_bit is not followed by a memory barrier (for example, in drivers/md/dm-bufio.c:new_read).
On architectures with weak memory ordering, it may happen that memory accesses that follow wait_on_bit are reordered before wait_on_bit and they may return invalid data.
Fix this class of bugs by introducing a new function "test_bit_acquire" that works like test_bit, but has acquire memory ordering semantics.
Signed-off-by: Mikulas Patocka mpatocka@redhat.com Acked-by: Will Deacon will@kernel.org Cc: stable@vger.kernel.org Signed-off-by: Linus Torvalds torvalds@linux-foundation.org
--- arch/x86/include/asm/bitops.h | 21 +++++++++++++++++++++ include/asm-generic/bitops/non-atomic.h | 14 ++++++++++++++ include/linux/buffer_head.h | 2 +- include/linux/wait_bit.h | 8 ++++---- kernel/sched/wait_bit.c | 2 +- 5 files changed, 41 insertions(+), 6 deletions(-)
Index: linux-stable/arch/x86/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/x86/include/asm/bitops.h 2022-09-30 15:55:01.000000000 +0200 +++ linux-stable/arch/x86/include/asm/bitops.h 2022-09-30 15:55:01.000000000 +0200 @@ -328,6 +328,20 @@ static __always_inline bool constant_tes (addr[nr >> _BITOPS_LONG_SHIFT])) != 0; }
+static __always_inline bool constant_test_bit_acquire(long nr, const volatile unsigned long *addr) +{ + bool oldbit; + + asm volatile("testb %2,%1" + CC_SET(nz) + : CC_OUT(nz) (oldbit) + : "m" (((unsigned char *)addr)[nr >> 3]), + "i" (1 << (nr & 7)) + :"memory"); + + return oldbit; +} + static __always_inline bool variable_test_bit(long nr, volatile const unsigned long *addr) { bool oldbit; @@ -354,6 +368,13 @@ static bool test_bit(int nr, const volat ? constant_test_bit((nr), (addr)) \ : variable_test_bit((nr), (addr)))
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + return __builtin_constant_p(nr) ? constant_test_bit_acquire(nr, addr) : + variable_test_bit(nr, addr); +} + /** * __ffs - find first set bit in word * @word: The word to search Index: linux-stable/include/asm-generic/bitops/non-atomic.h =================================================================== --- linux-stable.orig/include/asm-generic/bitops/non-atomic.h 2022-09-30 15:55:01.000000000 +0200 +++ linux-stable/include/asm-generic/bitops/non-atomic.h 2022-09-30 15:55:01.000000000 +0200 @@ -3,6 +3,7 @@ #define _ASM_GENERIC_BITOPS_NON_ATOMIC_H_
#include <asm/types.h> +#include <asm/barrier.h>
/** * __set_bit - Set a bit in memory @@ -106,4 +107,17 @@ static inline int test_bit(int nr, const return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); }
+/** + * arch_test_bit_acquire - Determine, with acquire semantics, whether a bit is set + * @nr: bit number to test + * @addr: Address to start counting from + */ +static __always_inline bool +arch_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} +#define test_bit_acquire arch_test_bit_acquire + #endif /* _ASM_GENERIC_BITOPS_NON_ATOMIC_H_ */ Index: linux-stable/include/linux/buffer_head.h =================================================================== --- linux-stable.orig/include/linux/buffer_head.h 2022-09-30 15:55:01.000000000 +0200 +++ linux-stable/include/linux/buffer_head.h 2022-09-30 15:55:01.000000000 +0200 @@ -163,7 +163,7 @@ static __always_inline int buffer_uptoda * make it consistent with folio_test_uptodate * pairs with smp_mb__before_atomic in set_buffer_uptodate */ - return (smp_load_acquire(&bh->b_state) & (1UL << BH_Uptodate)) != 0; + return test_bit_acquire(BH_Uptodate, &bh->b_state); }
#define bh_offset(bh) ((unsigned long)(bh)->b_data & ~PAGE_MASK) Index: linux-stable/include/linux/wait_bit.h =================================================================== --- linux-stable.orig/include/linux/wait_bit.h 2022-09-30 15:55:01.000000000 +0200 +++ linux-stable/include/linux/wait_bit.h 2022-09-30 15:55:01.000000000 +0200 @@ -76,7 +76,7 @@ static inline int wait_on_bit(unsigned long *word, int bit, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, bit_wait, @@ -101,7 +101,7 @@ static inline int wait_on_bit_io(unsigned long *word, int bit, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, bit_wait_io, @@ -128,7 +128,7 @@ wait_on_bit_timeout(unsigned long *word, unsigned long timeout) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit_timeout(word, bit, bit_wait_timeout, @@ -156,7 +156,7 @@ wait_on_bit_action(unsigned long *word, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, action, mode); } Index: linux-stable/kernel/sched/wait_bit.c =================================================================== --- linux-stable.orig/kernel/sched/wait_bit.c 2022-09-30 15:55:01.000000000 +0200 +++ linux-stable/kernel/sched/wait_bit.c 2022-09-30 15:55:55.000000000 +0200 @@ -49,7 +49,7 @@ __wait_on_bit(struct wait_queue_head *wq prepare_to_wait(wq_head, &wbq_entry->wq_entry, mode); if (test_bit(wbq_entry->key.bit_nr, wbq_entry->key.flags)) ret = (*action)(&wbq_entry->key, mode); - } while (test_bit(wbq_entry->key.bit_nr, wbq_entry->key.flags) && !ret); + } while (test_bit_acquire(wbq_entry->key.bit_nr, wbq_entry->key.flags) && !ret); finish_wait(wq_head, &wbq_entry->wq_entry); return ret; }
This is backport of the upstream patch 8238b4579866b7c1bb99883cfe102a43db5506ff for the stable branch 4.9
wait_on_bit: add an acquire memory barrier
There are several places in the kernel where wait_on_bit is not followed by a memory barrier (for example, in drivers/md/dm-bufio.c:new_read).
On architectures with weak memory ordering, it may happen that memory accesses that follow wait_on_bit are reordered before wait_on_bit and they may return invalid data.
Fix this class of bugs by introducing a new function "test_bit_acquire" that works like test_bit, but has acquire memory ordering semantics.
Signed-off-by: Mikulas Patocka mpatocka@redhat.com Acked-by: Will Deacon will@kernel.org Cc: stable@vger.kernel.org Signed-off-by: Linus Torvalds torvalds@linux-foundation.org
--- arch/x86/include/asm/bitops.h | 21 +++++++++++++++++++++ include/asm-generic/bitops/non-atomic.h | 14 ++++++++++++++ include/linux/buffer_head.h | 2 +- include/linux/wait.h | 8 ++++---- kernel/sched/wait.c | 2 +- 5 files changed, 41 insertions(+), 6 deletions(-)
Index: linux-stable/arch/x86/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/x86/include/asm/bitops.h 2022-09-30 16:01:38.000000000 +0200 +++ linux-stable/arch/x86/include/asm/bitops.h 2022-09-30 16:01:38.000000000 +0200 @@ -314,6 +314,20 @@ static __always_inline bool constant_tes (addr[nr >> _BITOPS_LONG_SHIFT])) != 0; }
+static __always_inline bool constant_test_bit_acquire(long nr, const volatile unsigned long *addr) +{ + bool oldbit; + + asm volatile("testb %2,%1" + CC_SET(nz) + : CC_OUT(nz) (oldbit) + : "m" (((unsigned char *)addr)[nr >> 3]), + "i" (1 << (nr & 7)) + :"memory"); + + return oldbit; +} + static __always_inline bool variable_test_bit(long nr, volatile const unsigned long *addr) { bool oldbit; @@ -340,6 +354,13 @@ static bool test_bit(int nr, const volat ? constant_test_bit((nr), (addr)) \ : variable_test_bit((nr), (addr)))
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + return __builtin_constant_p(nr) ? constant_test_bit_acquire(nr, addr) : + variable_test_bit(nr, addr); +} + /** * __ffs - find first set bit in word * @word: The word to search Index: linux-stable/include/asm-generic/bitops/non-atomic.h =================================================================== --- linux-stable.orig/include/asm-generic/bitops/non-atomic.h 2022-09-30 16:01:38.000000000 +0200 +++ linux-stable/include/asm-generic/bitops/non-atomic.h 2022-09-30 16:01:38.000000000 +0200 @@ -2,6 +2,7 @@ #define _ASM_GENERIC_BITOPS_NON_ATOMIC_H_
#include <asm/types.h> +#include <asm/barrier.h>
/** * __set_bit - Set a bit in memory @@ -105,4 +106,17 @@ static inline int test_bit(int nr, const return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); }
+/** + * arch_test_bit_acquire - Determine, with acquire semantics, whether a bit is set + * @nr: bit number to test + * @addr: Address to start counting from + */ +static __always_inline bool +arch_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} +#define test_bit_acquire arch_test_bit_acquire + #endif /* _ASM_GENERIC_BITOPS_NON_ATOMIC_H_ */ Index: linux-stable/include/linux/buffer_head.h =================================================================== --- linux-stable.orig/include/linux/buffer_head.h 2022-09-30 16:01:38.000000000 +0200 +++ linux-stable/include/linux/buffer_head.h 2022-09-30 16:01:38.000000000 +0200 @@ -162,7 +162,7 @@ static __always_inline int buffer_uptoda * make it consistent with folio_test_uptodate * pairs with smp_mb__before_atomic in set_buffer_uptodate */ - return (smp_load_acquire(&bh->b_state) & (1UL << BH_Uptodate)) != 0; + return test_bit_acquire(BH_Uptodate, &bh->b_state); }
#define bh_offset(bh) ((unsigned long)(bh)->b_data & ~PAGE_MASK) Index: linux-stable/include/linux/wait.h =================================================================== --- linux-stable.orig/include/linux/wait.h 2022-09-30 16:01:38.000000000 +0200 +++ linux-stable/include/linux/wait.h 2022-09-30 16:01:38.000000000 +0200 @@ -1066,7 +1066,7 @@ static inline int wait_on_bit(unsigned long *word, int bit, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, bit_wait, @@ -1091,7 +1091,7 @@ static inline int wait_on_bit_io(unsigned long *word, int bit, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, bit_wait_io, @@ -1118,7 +1118,7 @@ wait_on_bit_timeout(unsigned long *word, unsigned long timeout) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit_timeout(word, bit, bit_wait_timeout, @@ -1146,7 +1146,7 @@ wait_on_bit_action(unsigned long *word, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, action, mode); } Index: linux-stable/kernel/sched/wait.c =================================================================== --- linux-stable.orig/kernel/sched/wait.c 2022-09-30 16:01:38.000000000 +0200 +++ linux-stable/kernel/sched/wait.c 2022-09-30 16:01:58.000000000 +0200 @@ -389,7 +389,7 @@ __wait_on_bit(wait_queue_head_t *wq, str prepare_to_wait(wq, &q->wait, mode); if (test_bit(q->key.bit_nr, q->key.flags)) ret = (*action)(&q->key, mode); - } while (test_bit(q->key.bit_nr, q->key.flags) && !ret); + } while (test_bit_acquire(q->key.bit_nr, q->key.flags) && !ret); finish_wait(wq, &q->wait); return ret; }
This is backport of the upstream patch d6ffe6067a54972564552ea45d320fb98db1ac5e for the stable branches 5.19, 5.15, 5.10
provide arch_test_bit_acquire for architectures that define test_bit
Some architectures define their own arch_test_bit and they also need arch_test_bit_acquire, otherwise they won't compile. We also clean up the code by using the generic test_bit if that is equivalent to the arch-specific version.
Signed-off-by: Mikulas Patocka mpatocka@redhat.com Cc: stable@vger.kernel.org Fixes: 8238b4579866 ("wait_on_bit: add an acquire memory barrier") Signed-off-by: Linus Torvalds torvalds@linux-foundation.org
--- arch/alpha/include/asm/bitops.h | 7 +++++++ arch/hexagon/include/asm/bitops.h | 15 +++++++++++++++ arch/ia64/include/asm/bitops.h | 7 +++++++ arch/m68k/include/asm/bitops.h | 6 ++++++ arch/s390/include/asm/bitops.h | 7 +++++++ arch/sh/include/asm/bitops-op32.h | 7 +++++++ 6 files changed, 49 insertions(+)
Index: linux-stable/arch/alpha/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/alpha/include/asm/bitops.h 2022-09-30 13:07:14.000000000 +0200 +++ linux-stable/arch/alpha/include/asm/bitops.h 2022-09-30 13:07:14.000000000 +0200 @@ -289,6 +289,13 @@ test_bit(int nr, const volatile void * a return (1UL & (((const int *) addr)[nr >> 5] >> (nr & 31))) != 0UL; }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + /* * ffz = Find First Zero in word. Undefined if no zero exists, * so code should check against ~0UL first.. Index: linux-stable/arch/hexagon/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/hexagon/include/asm/bitops.h 2022-09-30 13:07:14.000000000 +0200 +++ linux-stable/arch/hexagon/include/asm/bitops.h 2022-09-30 13:07:14.000000000 +0200 @@ -172,7 +172,22 @@ static inline int __test_bit(int nr, con return retval; }
+static inline int __test_bit_acquire(int nr, const volatile unsigned long *addr) +{ + int retval; + + asm volatile( + "{P0 = tstbit(%1,%2); if (P0.new) %0 = #1; if (!P0.new) %0 = #0;}\n" + : "=&r" (retval) + : "r" (addr[BIT_WORD(nr)]), "r" (nr % BITS_PER_LONG) + : "p0", "memory" + ); + + return retval; +} + #define test_bit(nr, addr) __test_bit(nr, addr) +#define test_bit_acquire(nr, addr) __test_bit_acquire(nr, addr)
/* * ffz - find first zero in word. Index: linux-stable/arch/ia64/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/ia64/include/asm/bitops.h 2022-09-30 13:07:14.000000000 +0200 +++ linux-stable/arch/ia64/include/asm/bitops.h 2022-09-30 13:07:14.000000000 +0200 @@ -337,6 +337,13 @@ test_bit (int nr, const volatile void *a return 1 & (((const volatile __u32 *) addr)[nr >> 5] >> (nr & 31)); }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + /** * ffz - find the first zero bit in a long word * @x: The long word to find the bit in Index: linux-stable/arch/m68k/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/m68k/include/asm/bitops.h 2022-09-30 13:07:14.000000000 +0200 +++ linux-stable/arch/m68k/include/asm/bitops.h 2022-09-30 13:07:14.000000000 +0200 @@ -153,6 +153,12 @@ static inline int test_bit(int nr, const return (vaddr[nr >> 5] & (1UL << (nr & 31))) != 0; }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +}
static inline int bset_reg_test_and_set_bit(int nr, volatile unsigned long *vaddr) Index: linux-stable/arch/s390/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/s390/include/asm/bitops.h 2022-09-30 13:07:14.000000000 +0200 +++ linux-stable/arch/s390/include/asm/bitops.h 2022-09-30 13:07:14.000000000 +0200 @@ -184,6 +184,13 @@ static inline bool arch_test_bit(unsigne return *addr & mask; }
+static __always_inline bool +arch_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + static inline bool arch_test_and_set_bit_lock(unsigned long nr, volatile unsigned long *ptr) { Index: linux-stable/arch/sh/include/asm/bitops-op32.h =================================================================== --- linux-stable.orig/arch/sh/include/asm/bitops-op32.h 2022-09-30 13:07:14.000000000 +0200 +++ linux-stable/arch/sh/include/asm/bitops-op32.h 2022-09-30 13:07:14.000000000 +0200 @@ -138,4 +138,11 @@ static inline int test_bit(int nr, const return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + #endif /* __ASM_SH_BITOPS_OP32_H */
This is backport of the upstream patch d6ffe6067a54972564552ea45d320fb98db1ac5e for the stable branch 5.4
provide arch_test_bit_acquire for architectures that define test_bit
Some architectures define their own arch_test_bit and they also need arch_test_bit_acquire, otherwise they won't compile. We also clean up the code by using the generic test_bit if that is equivalent to the arch-specific version.
Signed-off-by: Mikulas Patocka mpatocka@redhat.com Cc: stable@vger.kernel.org Fixes: 8238b4579866 ("wait_on_bit: add an acquire memory barrier") Signed-off-by: Linus Torvalds torvalds@linux-foundation.org
--- arch/alpha/include/asm/bitops.h | 7 +++++++ arch/hexagon/include/asm/bitops.h | 15 +++++++++++++++ arch/ia64/include/asm/bitops.h | 7 +++++++ arch/m68k/include/asm/bitops.h | 6 ++++++ arch/s390/include/asm/bitops.h | 7 +++++++ arch/sh/include/asm/bitops-op32.h | 7 +++++++ 6 files changed, 49 insertions(+)
Index: linux-stable/arch/alpha/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/alpha/include/asm/bitops.h 2022-09-30 15:39:09.000000000 +0200 +++ linux-stable/arch/alpha/include/asm/bitops.h 2022-09-30 15:39:09.000000000 +0200 @@ -289,6 +289,13 @@ test_bit(int nr, const volatile void * a return (1UL & (((const int *) addr)[nr >> 5] >> (nr & 31))) != 0UL; }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + /* * ffz = Find First Zero in word. Undefined if no zero exists, * so code should check against ~0UL first.. Index: linux-stable/arch/hexagon/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/hexagon/include/asm/bitops.h 2022-09-30 15:39:09.000000000 +0200 +++ linux-stable/arch/hexagon/include/asm/bitops.h 2022-09-30 15:39:09.000000000 +0200 @@ -172,7 +172,22 @@ static inline int __test_bit(int nr, con return retval; }
+static inline int __test_bit_acquire(int nr, const volatile unsigned long *addr) +{ + int retval; + + asm volatile( + "{P0 = tstbit(%1,%2); if (P0.new) %0 = #1; if (!P0.new) %0 = #0;}\n" + : "=&r" (retval) + : "r" (addr[BIT_WORD(nr)]), "r" (nr % BITS_PER_LONG) + : "p0", "memory" + ); + + return retval; +} + #define test_bit(nr, addr) __test_bit(nr, addr) +#define test_bit_acquire(nr, addr) __test_bit_acquire(nr, addr)
/* * ffz - find first zero in word. Index: linux-stable/arch/ia64/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/ia64/include/asm/bitops.h 2022-09-30 15:39:09.000000000 +0200 +++ linux-stable/arch/ia64/include/asm/bitops.h 2022-09-30 15:39:09.000000000 +0200 @@ -337,6 +337,13 @@ test_bit (int nr, const volatile void *a return 1 & (((const volatile __u32 *) addr)[nr >> 5] >> (nr & 31)); }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + /** * ffz - find the first zero bit in a long word * @x: The long word to find the bit in Index: linux-stable/arch/m68k/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/m68k/include/asm/bitops.h 2022-09-30 15:39:09.000000000 +0200 +++ linux-stable/arch/m68k/include/asm/bitops.h 2022-09-30 15:39:09.000000000 +0200 @@ -153,6 +153,12 @@ static inline int test_bit(int nr, const return (vaddr[nr >> 5] & (1UL << (nr & 31))) != 0; }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +}
static inline int bset_reg_test_and_set_bit(int nr, volatile unsigned long *vaddr) Index: linux-stable/arch/s390/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/s390/include/asm/bitops.h 2022-09-30 15:39:09.000000000 +0200 +++ linux-stable/arch/s390/include/asm/bitops.h 2022-09-30 15:39:09.000000000 +0200 @@ -219,6 +219,13 @@ static inline bool arch_test_bit(unsigne return (*addr >> (nr & 7)) & 1; }
+static __always_inline bool +arch_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + static inline bool arch_test_and_set_bit_lock(unsigned long nr, volatile unsigned long *ptr) { Index: linux-stable/arch/sh/include/asm/bitops-op32.h =================================================================== --- linux-stable.orig/arch/sh/include/asm/bitops-op32.h 2022-09-30 15:39:09.000000000 +0200 +++ linux-stable/arch/sh/include/asm/bitops-op32.h 2022-09-30 15:39:09.000000000 +0200 @@ -140,4 +140,11 @@ static inline int test_bit(int nr, const return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + #endif /* __ASM_SH_BITOPS_OP32_H */
This is backport of the upstream patch d6ffe6067a54972564552ea45d320fb98db1ac5e for the stable branch 4.19
provide arch_test_bit_acquire for architectures that define test_bit
Some architectures define their own arch_test_bit and they also need arch_test_bit_acquire, otherwise they won't compile. We also clean up the code by using the generic test_bit if that is equivalent to the arch-specific version.
Signed-off-by: Mikulas Patocka mpatocka@redhat.com Cc: stable@vger.kernel.org Fixes: 8238b4579866 ("wait_on_bit: add an acquire memory barrier") Signed-off-by: Linus Torvalds torvalds@linux-foundation.org
--- arch/alpha/include/asm/bitops.h | 7 +++++++ arch/hexagon/include/asm/bitops.h | 15 +++++++++++++++ arch/ia64/include/asm/bitops.h | 7 +++++++ arch/m68k/include/asm/bitops.h | 6 ++++++ arch/s390/include/asm/bitops.h | 7 +++++++ arch/sh/include/asm/bitops-op32.h | 7 +++++++ 6 files changed, 49 insertions(+)
Index: linux-stable/arch/alpha/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/alpha/include/asm/bitops.h 2022-09-30 15:48:24.000000000 +0200 +++ linux-stable/arch/alpha/include/asm/bitops.h 2022-09-30 15:48:24.000000000 +0200 @@ -289,6 +289,13 @@ test_bit(int nr, const volatile void * a return (1UL & (((const int *) addr)[nr >> 5] >> (nr & 31))) != 0UL; }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + /* * ffz = Find First Zero in word. Undefined if no zero exists, * so code should check against ~0UL first.. Index: linux-stable/arch/hexagon/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/hexagon/include/asm/bitops.h 2022-09-30 15:48:24.000000000 +0200 +++ linux-stable/arch/hexagon/include/asm/bitops.h 2022-09-30 15:48:24.000000000 +0200 @@ -186,7 +186,22 @@ static inline int __test_bit(int nr, con return retval; }
+static inline int __test_bit_acquire(int nr, const volatile unsigned long *addr) +{ + int retval; + + asm volatile( + "{P0 = tstbit(%1,%2); if (P0.new) %0 = #1; if (!P0.new) %0 = #0;}\n" + : "=&r" (retval) + : "r" (addr[BIT_WORD(nr)]), "r" (nr % BITS_PER_LONG) + : "p0", "memory" + ); + + return retval; +} + #define test_bit(nr, addr) __test_bit(nr, addr) +#define test_bit_acquire(nr, addr) __test_bit_acquire(nr, addr)
/* * ffz - find first zero in word. Index: linux-stable/arch/ia64/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/ia64/include/asm/bitops.h 2022-09-30 15:48:24.000000000 +0200 +++ linux-stable/arch/ia64/include/asm/bitops.h 2022-09-30 15:48:24.000000000 +0200 @@ -337,6 +337,13 @@ test_bit (int nr, const volatile void *a return 1 & (((const volatile __u32 *) addr)[nr >> 5] >> (nr & 31)); }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + /** * ffz - find the first zero bit in a long word * @x: The long word to find the bit in Index: linux-stable/arch/m68k/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/m68k/include/asm/bitops.h 2022-09-30 15:48:24.000000000 +0200 +++ linux-stable/arch/m68k/include/asm/bitops.h 2022-09-30 15:48:24.000000000 +0200 @@ -153,6 +153,12 @@ static inline int test_bit(int nr, const return (vaddr[nr >> 5] & (1UL << (nr & 31))) != 0; }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +}
static inline int bset_reg_test_and_set_bit(int nr, volatile unsigned long *vaddr) Index: linux-stable/arch/s390/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/s390/include/asm/bitops.h 2022-09-30 15:48:24.000000000 +0200 +++ linux-stable/arch/s390/include/asm/bitops.h 2022-09-30 15:49:53.000000000 +0200 @@ -215,6 +215,13 @@ static inline int test_bit(unsigned long return (*addr >> (nr & 7)) & 1; }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + static inline int test_and_set_bit_lock(unsigned long nr, volatile unsigned long *ptr) { Index: linux-stable/arch/sh/include/asm/bitops-op32.h =================================================================== --- linux-stable.orig/arch/sh/include/asm/bitops-op32.h 2022-09-30 15:48:24.000000000 +0200 +++ linux-stable/arch/sh/include/asm/bitops-op32.h 2022-09-30 15:48:24.000000000 +0200 @@ -140,4 +140,11 @@ static inline int test_bit(int nr, const return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + #endif /* __ASM_SH_BITOPS_OP32_H */
This is backport of the upstream patch d6ffe6067a54972564552ea45d320fb98db1ac5e for the stable branch 4.14
provide arch_test_bit_acquire for architectures that define test_bit
Some architectures define their own arch_test_bit and they also need arch_test_bit_acquire, otherwise they won't compile. We also clean up the code by using the generic test_bit if that is equivalent to the arch-specific version.
Signed-off-by: Mikulas Patocka mpatocka@redhat.com Cc: stable@vger.kernel.org Fixes: 8238b4579866 ("wait_on_bit: add an acquire memory barrier") Signed-off-by: Linus Torvalds torvalds@linux-foundation.org
--- arch/alpha/include/asm/bitops.h | 7 +++++++ arch/hexagon/include/asm/bitops.h | 15 +++++++++++++++ arch/ia64/include/asm/bitops.h | 7 +++++++ arch/m68k/include/asm/bitops.h | 6 ++++++ arch/s390/include/asm/bitops.h | 7 +++++++ arch/sh/include/asm/bitops-op32.h | 7 +++++++ 6 files changed, 49 insertions(+)
Index: linux-stable/arch/alpha/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/alpha/include/asm/bitops.h 2022-09-30 15:48:24.000000000 +0200 +++ linux-stable/arch/alpha/include/asm/bitops.h 2022-09-30 15:48:24.000000000 +0200 @@ -289,6 +289,13 @@ test_bit(int nr, const volatile void * a return (1UL & (((const int *) addr)[nr >> 5] >> (nr & 31))) != 0UL; }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + /* * ffz = Find First Zero in word. Undefined if no zero exists, * so code should check against ~0UL first.. Index: linux-stable/arch/hexagon/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/hexagon/include/asm/bitops.h 2022-09-30 15:48:24.000000000 +0200 +++ linux-stable/arch/hexagon/include/asm/bitops.h 2022-09-30 15:48:24.000000000 +0200 @@ -186,7 +186,22 @@ static inline int __test_bit(int nr, con return retval; }
+static inline int __test_bit_acquire(int nr, const volatile unsigned long *addr) +{ + int retval; + + asm volatile( + "{P0 = tstbit(%1,%2); if (P0.new) %0 = #1; if (!P0.new) %0 = #0;}\n" + : "=&r" (retval) + : "r" (addr[BIT_WORD(nr)]), "r" (nr % BITS_PER_LONG) + : "p0", "memory" + ); + + return retval; +} + #define test_bit(nr, addr) __test_bit(nr, addr) +#define test_bit_acquire(nr, addr) __test_bit_acquire(nr, addr)
/* * ffz - find first zero in word. Index: linux-stable/arch/ia64/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/ia64/include/asm/bitops.h 2022-09-30 15:48:24.000000000 +0200 +++ linux-stable/arch/ia64/include/asm/bitops.h 2022-09-30 15:48:24.000000000 +0200 @@ -337,6 +337,13 @@ test_bit (int nr, const volatile void *a return 1 & (((const volatile __u32 *) addr)[nr >> 5] >> (nr & 31)); }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + /** * ffz - find the first zero bit in a long word * @x: The long word to find the bit in Index: linux-stable/arch/m68k/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/m68k/include/asm/bitops.h 2022-09-30 15:48:24.000000000 +0200 +++ linux-stable/arch/m68k/include/asm/bitops.h 2022-09-30 15:48:24.000000000 +0200 @@ -153,6 +153,12 @@ static inline int test_bit(int nr, const return (vaddr[nr >> 5] & (1UL << (nr & 31))) != 0; }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +}
static inline int bset_reg_test_and_set_bit(int nr, volatile unsigned long *vaddr) Index: linux-stable/arch/s390/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/s390/include/asm/bitops.h 2022-09-30 15:48:24.000000000 +0200 +++ linux-stable/arch/s390/include/asm/bitops.h 2022-09-30 15:49:53.000000000 +0200 @@ -215,6 +215,13 @@ static inline int test_bit(unsigned long return (*addr >> (nr & 7)) & 1; }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + static inline int test_and_set_bit_lock(unsigned long nr, volatile unsigned long *ptr) { Index: linux-stable/arch/sh/include/asm/bitops-op32.h =================================================================== --- linux-stable.orig/arch/sh/include/asm/bitops-op32.h 2022-09-30 15:48:24.000000000 +0200 +++ linux-stable/arch/sh/include/asm/bitops-op32.h 2022-09-30 15:48:24.000000000 +0200 @@ -140,4 +140,11 @@ static inline int test_bit(int nr, const return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + #endif /* __ASM_SH_BITOPS_OP32_H */
This is backport of the upstream patch d6ffe6067a54972564552ea45d320fb98db1ac5e for the stable branch 4.9
provide arch_test_bit_acquire for architectures that define test_bit
Some architectures define their own arch_test_bit and they also need arch_test_bit_acquire, otherwise they won't compile. We also clean up the code by using the generic test_bit if that is equivalent to the arch-specific version.
Signed-off-by: Mikulas Patocka mpatocka@redhat.com Cc: stable@vger.kernel.org Fixes: 8238b4579866 ("wait_on_bit: add an acquire memory barrier") Signed-off-by: Linus Torvalds torvalds@linux-foundation.org
--- arch/alpha/include/asm/bitops.h | 7 +++++++ arch/hexagon/include/asm/bitops.h | 15 +++++++++++++++ arch/ia64/include/asm/bitops.h | 7 +++++++ arch/m68k/include/asm/bitops.h | 6 ++++++ arch/s390/include/asm/bitops.h | 7 +++++++ arch/sh/include/asm/bitops-op32.h | 7 +++++++ 6 files changed, 49 insertions(+)
Index: linux-stable/arch/alpha/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/alpha/include/asm/bitops.h 2022-09-30 16:03:22.000000000 +0200 +++ linux-stable/arch/alpha/include/asm/bitops.h 2022-09-30 16:03:22.000000000 +0200 @@ -288,6 +288,13 @@ test_bit(int nr, const volatile void * a return (1UL & (((const int *) addr)[nr >> 5] >> (nr & 31))) != 0UL; }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + /* * ffz = Find First Zero in word. Undefined if no zero exists, * so code should check against ~0UL first.. Index: linux-stable/arch/hexagon/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/hexagon/include/asm/bitops.h 2022-09-30 16:03:22.000000000 +0200 +++ linux-stable/arch/hexagon/include/asm/bitops.h 2022-09-30 16:03:22.000000000 +0200 @@ -186,7 +186,22 @@ static inline int __test_bit(int nr, con return retval; }
+static inline int __test_bit_acquire(int nr, const volatile unsigned long *addr) +{ + int retval; + + asm volatile( + "{P0 = tstbit(%1,%2); if (P0.new) %0 = #1; if (!P0.new) %0 = #0;}\n" + : "=&r" (retval) + : "r" (addr[BIT_WORD(nr)]), "r" (nr % BITS_PER_LONG) + : "p0", "memory" + ); + + return retval; +} + #define test_bit(nr, addr) __test_bit(nr, addr) +#define test_bit_acquire(nr, addr) __test_bit_acquire(nr, addr)
/* * ffz - find first zero in word. Index: linux-stable/arch/ia64/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/ia64/include/asm/bitops.h 2022-09-30 16:03:22.000000000 +0200 +++ linux-stable/arch/ia64/include/asm/bitops.h 2022-09-30 16:03:22.000000000 +0200 @@ -336,6 +336,13 @@ test_bit (int nr, const volatile void *a return 1 & (((const volatile __u32 *) addr)[nr >> 5] >> (nr & 31)); }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + /** * ffz - find the first zero bit in a long word * @x: The long word to find the bit in Index: linux-stable/arch/m68k/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/m68k/include/asm/bitops.h 2022-09-30 16:03:22.000000000 +0200 +++ linux-stable/arch/m68k/include/asm/bitops.h 2022-09-30 16:03:22.000000000 +0200 @@ -153,6 +153,12 @@ static inline int test_bit(int nr, const return (vaddr[nr >> 5] & (1UL << (nr & 31))) != 0; }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +}
static inline int bset_reg_test_and_set_bit(int nr, volatile unsigned long *vaddr) Index: linux-stable/arch/s390/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/s390/include/asm/bitops.h 2022-09-30 16:03:22.000000000 +0200 +++ linux-stable/arch/s390/include/asm/bitops.h 2022-09-30 16:03:22.000000000 +0200 @@ -270,6 +270,13 @@ static inline int test_bit(unsigned long return (*addr >> (nr & 7)) & 1; }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + static inline int test_and_set_bit_lock(unsigned long nr, volatile unsigned long *ptr) { Index: linux-stable/arch/sh/include/asm/bitops-op32.h =================================================================== --- linux-stable.orig/arch/sh/include/asm/bitops-op32.h 2022-09-30 16:03:22.000000000 +0200 +++ linux-stable/arch/sh/include/asm/bitops-op32.h 2022-09-30 16:03:22.000000000 +0200 @@ -139,4 +139,11 @@ static inline int test_bit(int nr, const return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + #endif /* __ASM_SH_BITOPS_OP32_H */
On Mon, Oct 03, 2022 at 08:28:06AM -0400, Mikulas Patocka wrote:
On Sat, 1 Oct 2022, Greg KH wrote:
On Fri, Sep 30, 2022 at 11:32:30AM -0400, Mikulas Patocka wrote:
Hi
Here I'm submitting backport of patches 8238b4579866b7c1bb99883cfe102a43db5506ff and d6ffe6067a54972564552ea45d320fb98db1ac5e to the stable branches.
Thanks, but you provide no information as to why these are needed.
What needs them? They are just adding new functions to the tree from what I can tell.
thanks,
greg k-h
There's a race condition in wait_on_bit. wait_on_bit tests a bit using the "test_bit" function, however this function doesn't do any memory barrier, so the memory accesses that follow wait_on_bit may be reordered before it and return invalid data.
Linus didn't want to add a memory barrier to wait_on_bit, he instead wanted to introduce a new function test_bit_acquire that performs the "acquire" memory barrier and use it in wait_on_bit.
The patch d6ffe6067a54972564552ea45d320fb98db1ac5e fixes an oversight in the patch 8238b4579866b7c1bb99883cfe102a43db5506ff where the function test_bit_acquire was not defined for some architectures and this caused compile failure.
The backport of the patch 8238b4579866b7c1bb99883cfe102a43db5506ff should be applied first and the backport of the patch d6ffe6067a54972564552ea45d320fb98db1ac5e afterwards.
All now queued up, thanks.
greg k-h
On Wed, Oct 05, 2022 at 06:48:54PM +0200, Greg KH wrote:
On Mon, Oct 03, 2022 at 08:28:06AM -0400, Mikulas Patocka wrote:
On Sat, 1 Oct 2022, Greg KH wrote:
On Fri, Sep 30, 2022 at 11:32:30AM -0400, Mikulas Patocka wrote:
Hi
Here I'm submitting backport of patches 8238b4579866b7c1bb99883cfe102a43db5506ff and d6ffe6067a54972564552ea45d320fb98db1ac5e to the stable branches.
Thanks, but you provide no information as to why these are needed.
What needs them? They are just adding new functions to the tree from what I can tell.
thanks,
greg k-h
There's a race condition in wait_on_bit. wait_on_bit tests a bit using the "test_bit" function, however this function doesn't do any memory barrier, so the memory accesses that follow wait_on_bit may be reordered before it and return invalid data.
Linus didn't want to add a memory barrier to wait_on_bit, he instead wanted to introduce a new function test_bit_acquire that performs the "acquire" memory barrier and use it in wait_on_bit.
The patch d6ffe6067a54972564552ea45d320fb98db1ac5e fixes an oversight in the patch 8238b4579866b7c1bb99883cfe102a43db5506ff where the function test_bit_acquire was not defined for some architectures and this caused compile failure.
The backport of the patch 8238b4579866b7c1bb99883cfe102a43db5506ff should be applied first and the backport of the patch d6ffe6067a54972564552ea45d320fb98db1ac5e afterwards.
All now queued up, thanks.
Nope, these cause loads of breakages. See https://lore.kernel.org/r/09eca44e-4d91-a060-d48c-d0aa41ac5045@roeck-us.net for one such example, and I know kbuild sent you other build problems. I'll drop all of these from the stable trees now. Please feel free to resend them when you have the build issues worked out.
thanks,
greg k-h
On Mon, 10 Oct 2022, Greg KH wrote:
Nope, these cause loads of breakages. See https://lore.kernel.org/r/09eca44e-4d91-a060-d48c-d0aa41ac5045@roeck-us.net for one such example, and I know kbuild sent you other build problems. I'll drop all of these from the stable trees now. Please feel free to resend them when you have the build issues worked out.
thanks,
greg k-h
I don't have cross compilers for all the architectures that Linux supports. Is there some way how to have the patch compile-tested before I send it to you?
Or - would you accept this patch instead of the upstream patch? It fixes the same bug as the upstream patch, but it's noticeably smaller and it could be applied to the stable kernels 4.19 to 5.19.
Mikulas
From: Mikulas Patocka mpatocka@redhat.com
This fixes a bug that is fixed by the upstream patch 8238b4579866b7c1bb99883cfe102a43db5506ff.
This patch differs from the upstream patch because backporting the upstream patch causes many build failures on various architectures.
Original commit message:
There are several places in the kernel where wait_on_bit is not followed by a memory barrier (for example, in drivers/md/dm-bufio.c:new_read).
On architectures with weak memory ordering, it may happen that memory accesses that follow wait_on_bit are reordered before wait_on_bit and they may return invalid data.
Fix this class of bugs by introducing a new function "test_bit_acquire" that works like test_bit, but has acquire memory ordering semantics.
Signed-off-by: Mikulas Patocka mpatocka@redhat.com Acked-by: Will Deacon will@kernel.org Cc: stable@vger.kernel.org Signed-off-by: Linus Torvalds torvalds@linux-foundation.org
--- include/linux/wait_bit.h | 16 ++++++++++++---- kernel/sched/wait_bit.c | 2 ++ 2 files changed, 14 insertions(+), 4 deletions(-)
Index: linux-stable/include/linux/wait_bit.h =================================================================== --- linux-stable.orig/include/linux/wait_bit.h 2022-10-11 11:23:12.000000000 +0200 +++ linux-stable/include/linux/wait_bit.h 2022-10-11 11:24:33.000000000 +0200 @@ -71,8 +71,10 @@ static inline int wait_on_bit(unsigned long *word, int bit, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit(bit, word)) { + smp_rmb(); return 0; + } return out_of_line_wait_on_bit(word, bit, bit_wait, mode); @@ -96,8 +98,10 @@ static inline int wait_on_bit_io(unsigned long *word, int bit, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit(bit, word)) { + smp_rmb(); return 0; + } return out_of_line_wait_on_bit(word, bit, bit_wait_io, mode); @@ -123,8 +127,10 @@ wait_on_bit_timeout(unsigned long *word, unsigned long timeout) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit(bit, word)) { + smp_rmb(); return 0; + } return out_of_line_wait_on_bit_timeout(word, bit, bit_wait_timeout, mode, timeout); @@ -151,8 +157,10 @@ wait_on_bit_action(unsigned long *word, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit(bit, word)) { + smp_rmb(); return 0; + } return out_of_line_wait_on_bit(word, bit, action, mode); }
Index: linux-stable/kernel/sched/wait_bit.c =================================================================== --- linux-stable.orig/kernel/sched/wait_bit.c 2022-10-11 11:23:12.000000000 +0200 +++ linux-stable/kernel/sched/wait_bit.c 2022-10-11 11:25:22.000000000 +0200 @@ -51,6 +51,8 @@ __wait_on_bit(struct wait_queue_head *wq
finish_wait(wq_head, &wbq_entry->wq_entry);
+ smp_rmb(); + return ret; } EXPORT_SYMBOL(__wait_on_bit);
On Tue, Oct 11, 2022 at 05:48:26AM -0400, Mikulas Patocka wrote:
On Mon, 10 Oct 2022, Greg KH wrote:
Nope, these cause loads of breakages. See https://lore.kernel.org/r/09eca44e-4d91-a060-d48c-d0aa41ac5045@roeck-us.net for one such example, and I know kbuild sent you other build problems. I'll drop all of these from the stable trees now. Please feel free to resend them when you have the build issues worked out.
thanks,
greg k-h
I don't have cross compilers for all the architectures that Linux supports. Is there some way how to have the patch compile-tested before I send it to you?
You can download those compilers from kernel.org, they are all available there.
Or - would you accept this patch instead of the upstream patch? It fixes the same bug as the upstream patch, but it's noticeably smaller and it could be applied to the stable kernels 4.19 to 5.19.
We should stick with what is in Linus's tree so as to not cause new bugs, and to make future backports easier.
thanks,
greg k-h
On Tue, 11 Oct 2022, Greg KH wrote:
On Tue, Oct 11, 2022 at 05:48:26AM -0400, Mikulas Patocka wrote:
On Mon, 10 Oct 2022, Greg KH wrote:
Nope, these cause loads of breakages. See https://lore.kernel.org/r/09eca44e-4d91-a060-d48c-d0aa41ac5045@roeck-us.net for one such example, and I know kbuild sent you other build problems. I'll drop all of these from the stable trees now. Please feel free to resend them when you have the build issues worked out.
thanks,
greg k-h
I don't have cross compilers for all the architectures that Linux supports. Is there some way how to have the patch compile-tested before I send it to you?
You can download those compilers from kernel.org, they are all available there.
OK. I downloaded cross compilers from https://mirrors.edge.kernel.org/pub/tools/crosstool/ and compile-tested the patches with all possible architectures.
Here I'm sending new versions.
Mikulas
This is backport of the upstream patch 8238b4579866b7c1bb99883cfe102a43db5506ff for the stable branch 5.19
wait_on_bit: add an acquire memory barrier
There are several places in the kernel where wait_on_bit is not followed by a memory barrier (for example, in drivers/md/dm-bufio.c:new_read).
On architectures with weak memory ordering, it may happen that memory accesses that follow wait_on_bit are reordered before wait_on_bit and they may return invalid data.
Fix this class of bugs by introducing a new function "test_bit_acquire" that works like test_bit, but has acquire memory ordering semantics.
Signed-off-by: Mikulas Patocka mpatocka@redhat.com Acked-by: Will Deacon will@kernel.org Cc: stable@vger.kernel.org Signed-off-by: Linus Torvalds torvalds@linux-foundation.org
--- arch/alpha/include/asm/bitops.h | 7 ++++++ arch/hexagon/include/asm/bitops.h | 15 +++++++++++++ arch/ia64/include/asm/bitops.h | 7 ++++++ arch/m68k/include/asm/bitops.h | 6 +++++ arch/s390/include/asm/bitops.h | 7 ++++++ arch/sh/include/asm/bitops-op32.h | 7 ++++++ arch/x86/include/asm/bitops.h | 21 +++++++++++++++++++ include/asm-generic/bitops/instrumented-non-atomic.h | 12 ++++++++++ include/asm-generic/bitops/non-atomic.h | 14 ++++++++++++ include/linux/buffer_head.h | 2 - include/linux/wait_bit.h | 8 +++---- kernel/sched/wait_bit.c | 2 - 12 files changed, 102 insertions(+), 6 deletions(-)
Index: linux-stable/arch/x86/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/x86/include/asm/bitops.h 2022-10-17 19:02:15.000000000 +0200 +++ linux-stable/arch/x86/include/asm/bitops.h 2022-10-17 19:02:15.000000000 +0200 @@ -207,6 +207,20 @@ static __always_inline bool constant_tes (addr[nr >> _BITOPS_LONG_SHIFT])) != 0; }
+static __always_inline bool constant_test_bit_acquire(long nr, const volatile unsigned long *addr) +{ + bool oldbit; + + asm volatile("testb %2,%1" + CC_SET(nz) + : CC_OUT(nz) (oldbit) + : "m" (((unsigned char *)addr)[nr >> 3]), + "i" (1 << (nr & 7)) + :"memory"); + + return oldbit; +} + static __always_inline bool variable_test_bit(long nr, volatile const unsigned long *addr) { bool oldbit; @@ -224,6 +238,13 @@ static __always_inline bool variable_tes ? constant_test_bit((nr), (addr)) \ : variable_test_bit((nr), (addr)))
+static __always_inline bool +arch_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + return __builtin_constant_p(nr) ? constant_test_bit_acquire(nr, addr) : + variable_test_bit(nr, addr); +} + /** * __ffs - find first set bit in word * @word: The word to search Index: linux-stable/include/asm-generic/bitops/instrumented-non-atomic.h =================================================================== --- linux-stable.orig/include/asm-generic/bitops/instrumented-non-atomic.h 2022-10-17 19:02:15.000000000 +0200 +++ linux-stable/include/asm-generic/bitops/instrumented-non-atomic.h 2022-10-17 19:02:15.000000000 +0200 @@ -135,4 +135,16 @@ static __always_inline bool test_bit(lon return arch_test_bit(nr, addr); }
+/** + * _test_bit_acquire - Determine, with acquire semantics, whether a bit is set + * @nr: bit number to test + * @addr: Address to start counting from + */ +static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + instrument_atomic_read(addr + BIT_WORD(nr), sizeof(long)); + return arch_test_bit_acquire(nr, addr); +} + #endif /* _ASM_GENERIC_BITOPS_INSTRUMENTED_NON_ATOMIC_H */ Index: linux-stable/include/asm-generic/bitops/non-atomic.h =================================================================== --- linux-stable.orig/include/asm-generic/bitops/non-atomic.h 2022-10-17 19:02:15.000000000 +0200 +++ linux-stable/include/asm-generic/bitops/non-atomic.h 2022-10-17 19:02:15.000000000 +0200 @@ -3,6 +3,7 @@ #define _ASM_GENERIC_BITOPS_NON_ATOMIC_H_
#include <asm/types.h> +#include <asm/barrier.h>
/** * arch___set_bit - Set a bit in memory @@ -119,4 +120,17 @@ arch_test_bit(unsigned int nr, const vol } #define test_bit arch_test_bit
+/** + * arch_test_bit_acquire - Determine, with acquire semantics, whether a bit is set + * @nr: bit number to test + * @addr: Address to start counting from + */ +static __always_inline bool +arch_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} +#define test_bit_acquire arch_test_bit_acquire + #endif /* _ASM_GENERIC_BITOPS_NON_ATOMIC_H_ */ Index: linux-stable/include/linux/buffer_head.h =================================================================== --- linux-stable.orig/include/linux/buffer_head.h 2022-10-17 19:02:15.000000000 +0200 +++ linux-stable/include/linux/buffer_head.h 2022-10-17 19:02:15.000000000 +0200 @@ -166,7 +166,7 @@ static __always_inline int buffer_uptoda * make it consistent with folio_test_uptodate * pairs with smp_mb__before_atomic in set_buffer_uptodate */ - return (smp_load_acquire(&bh->b_state) & (1UL << BH_Uptodate)) != 0; + return test_bit_acquire(BH_Uptodate, &bh->b_state); }
#define bh_offset(bh) ((unsigned long)(bh)->b_data & ~PAGE_MASK) Index: linux-stable/include/linux/wait_bit.h =================================================================== --- linux-stable.orig/include/linux/wait_bit.h 2022-10-17 19:02:15.000000000 +0200 +++ linux-stable/include/linux/wait_bit.h 2022-10-17 19:02:15.000000000 +0200 @@ -71,7 +71,7 @@ static inline int wait_on_bit(unsigned long *word, int bit, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, bit_wait, @@ -96,7 +96,7 @@ static inline int wait_on_bit_io(unsigned long *word, int bit, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, bit_wait_io, @@ -123,7 +123,7 @@ wait_on_bit_timeout(unsigned long *word, unsigned long timeout) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit_timeout(word, bit, bit_wait_timeout, @@ -151,7 +151,7 @@ wait_on_bit_action(unsigned long *word, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, action, mode); } Index: linux-stable/kernel/sched/wait_bit.c =================================================================== --- linux-stable.orig/kernel/sched/wait_bit.c 2022-10-17 19:02:15.000000000 +0200 +++ linux-stable/kernel/sched/wait_bit.c 2022-10-17 19:02:15.000000000 +0200 @@ -47,7 +47,7 @@ __wait_on_bit(struct wait_queue_head *wq prepare_to_wait(wq_head, &wbq_entry->wq_entry, mode); if (test_bit(wbq_entry->key.bit_nr, wbq_entry->key.flags)) ret = (*action)(&wbq_entry->key, mode); - } while (test_bit(wbq_entry->key.bit_nr, wbq_entry->key.flags) && !ret); + } while (test_bit_acquire(wbq_entry->key.bit_nr, wbq_entry->key.flags) && !ret);
finish_wait(wq_head, &wbq_entry->wq_entry);
Index: linux-stable/arch/alpha/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/alpha/include/asm/bitops.h 2022-10-17 19:02:15.000000000 +0200 +++ linux-stable/arch/alpha/include/asm/bitops.h 2022-10-17 19:02:15.000000000 +0200 @@ -289,6 +289,13 @@ test_bit(int nr, const volatile void * a return (1UL & (((const int *) addr)[nr >> 5] >> (nr & 31))) != 0UL; }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + /* * ffz = Find First Zero in word. Undefined if no zero exists, * so code should check against ~0UL first.. Index: linux-stable/arch/hexagon/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/hexagon/include/asm/bitops.h 2022-10-17 19:02:15.000000000 +0200 +++ linux-stable/arch/hexagon/include/asm/bitops.h 2022-10-17 19:02:15.000000000 +0200 @@ -172,7 +172,22 @@ static inline int __test_bit(int nr, con return retval; }
+static inline int __test_bit_acquire(int nr, const volatile unsigned long *addr) +{ + int retval; + + asm volatile( + "{P0 = tstbit(%1,%2); if (P0.new) %0 = #1; if (!P0.new) %0 = #0;}\n" + : "=&r" (retval) + : "r" (addr[BIT_WORD(nr)]), "r" (nr % BITS_PER_LONG) + : "p0", "memory" + ); + + return retval; +} + #define test_bit(nr, addr) __test_bit(nr, addr) +#define test_bit_acquire(nr, addr) __test_bit_acquire(nr, addr)
/* * ffz - find first zero in word. Index: linux-stable/arch/ia64/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/ia64/include/asm/bitops.h 2022-10-17 19:02:15.000000000 +0200 +++ linux-stable/arch/ia64/include/asm/bitops.h 2022-10-17 19:02:15.000000000 +0200 @@ -337,6 +337,13 @@ test_bit (int nr, const volatile void *a return 1 & (((const volatile __u32 *) addr)[nr >> 5] >> (nr & 31)); }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + /** * ffz - find the first zero bit in a long word * @x: The long word to find the bit in Index: linux-stable/arch/m68k/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/m68k/include/asm/bitops.h 2022-10-17 19:02:15.000000000 +0200 +++ linux-stable/arch/m68k/include/asm/bitops.h 2022-10-17 19:02:15.000000000 +0200 @@ -153,6 +153,12 @@ static inline int test_bit(int nr, const return (vaddr[nr >> 5] & (1UL << (nr & 31))) != 0; }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +}
static inline int bset_reg_test_and_set_bit(int nr, volatile unsigned long *vaddr) Index: linux-stable/arch/s390/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/s390/include/asm/bitops.h 2022-10-17 19:02:15.000000000 +0200 +++ linux-stable/arch/s390/include/asm/bitops.h 2022-10-17 19:02:15.000000000 +0200 @@ -184,6 +184,13 @@ static inline bool arch_test_bit(unsigne return *addr & mask; }
+static __always_inline bool +arch_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + static inline bool arch_test_and_set_bit_lock(unsigned long nr, volatile unsigned long *ptr) { Index: linux-stable/arch/sh/include/asm/bitops-op32.h =================================================================== --- linux-stable.orig/arch/sh/include/asm/bitops-op32.h 2022-10-17 19:02:15.000000000 +0200 +++ linux-stable/arch/sh/include/asm/bitops-op32.h 2022-10-17 19:02:15.000000000 +0200 @@ -138,4 +138,11 @@ static inline int test_bit(int nr, const return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + #endif /* __ASM_SH_BITOPS_OP32_H */
This is backport of the upstream patch 8238b4579866b7c1bb99883cfe102a43db5506ff for the stable branch 5.15
wait_on_bit: add an acquire memory barrier
There are several places in the kernel where wait_on_bit is not followed by a memory barrier (for example, in drivers/md/dm-bufio.c:new_read).
On architectures with weak memory ordering, it may happen that memory accesses that follow wait_on_bit are reordered before wait_on_bit and they may return invalid data.
Fix this class of bugs by introducing a new function "test_bit_acquire" that works like test_bit, but has acquire memory ordering semantics.
Signed-off-by: Mikulas Patocka mpatocka@redhat.com Acked-by: Will Deacon will@kernel.org Cc: stable@vger.kernel.org Signed-off-by: Linus Torvalds torvalds@linux-foundation.org
--- arch/alpha/include/asm/bitops.h | 7 ++++++ arch/h8300/include/asm/bitops.h | 3 +- arch/hexagon/include/asm/bitops.h | 15 +++++++++++++ arch/ia64/include/asm/bitops.h | 7 ++++++ arch/m68k/include/asm/bitops.h | 6 +++++ arch/s390/include/asm/bitops.h | 7 ++++++ arch/sh/include/asm/bitops-op32.h | 7 ++++++ arch/x86/include/asm/bitops.h | 21 +++++++++++++++++++ include/asm-generic/bitops/instrumented-non-atomic.h | 12 ++++++++++ include/asm-generic/bitops/non-atomic.h | 14 ++++++++++++ include/linux/buffer_head.h | 2 - include/linux/wait_bit.h | 8 +++---- kernel/sched/wait_bit.c | 2 - 13 files changed, 104 insertions(+), 7 deletions(-)
Index: linux-stable/arch/x86/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/x86/include/asm/bitops.h 2022-10-18 12:42:09.000000000 +0200 +++ linux-stable/arch/x86/include/asm/bitops.h 2022-10-18 12:42:09.000000000 +0200 @@ -207,6 +207,20 @@ static __always_inline bool constant_tes (addr[nr >> _BITOPS_LONG_SHIFT])) != 0; }
+static __always_inline bool constant_test_bit_acquire(long nr, const volatile unsigned long *addr) +{ + bool oldbit; + + asm volatile("testb %2,%1" + CC_SET(nz) + : CC_OUT(nz) (oldbit) + : "m" (((unsigned char *)addr)[nr >> 3]), + "i" (1 << (nr & 7)) + :"memory"); + + return oldbit; +} + static __always_inline bool variable_test_bit(long nr, volatile const unsigned long *addr) { bool oldbit; @@ -224,6 +238,13 @@ static __always_inline bool variable_tes ? constant_test_bit((nr), (addr)) \ : variable_test_bit((nr), (addr)))
+static __always_inline bool +arch_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + return __builtin_constant_p(nr) ? constant_test_bit_acquire(nr, addr) : + variable_test_bit(nr, addr); +} + /** * __ffs - find first set bit in word * @word: The word to search Index: linux-stable/include/asm-generic/bitops/instrumented-non-atomic.h =================================================================== --- linux-stable.orig/include/asm-generic/bitops/instrumented-non-atomic.h 2022-10-18 12:42:09.000000000 +0200 +++ linux-stable/include/asm-generic/bitops/instrumented-non-atomic.h 2022-10-18 12:42:09.000000000 +0200 @@ -135,4 +135,16 @@ static inline bool test_bit(long nr, con return arch_test_bit(nr, addr); }
+/** + * _test_bit_acquire - Determine, with acquire semantics, whether a bit is set + * @nr: bit number to test + * @addr: Address to start counting from + */ +static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + instrument_atomic_read(addr + BIT_WORD(nr), sizeof(long)); + return arch_test_bit_acquire(nr, addr); +} + #endif /* _ASM_GENERIC_BITOPS_INSTRUMENTED_NON_ATOMIC_H */ Index: linux-stable/include/asm-generic/bitops/non-atomic.h =================================================================== --- linux-stable.orig/include/asm-generic/bitops/non-atomic.h 2022-10-18 12:42:09.000000000 +0200 +++ linux-stable/include/asm-generic/bitops/non-atomic.h 2022-10-18 12:42:09.000000000 +0200 @@ -3,6 +3,7 @@ #define _ASM_GENERIC_BITOPS_NON_ATOMIC_H_
#include <asm/types.h> +#include <asm/barrier.h>
/** * arch___set_bit - Set a bit in memory @@ -119,4 +120,17 @@ arch_test_bit(unsigned int nr, const vol } #define test_bit arch_test_bit
+/** + * arch_test_bit_acquire - Determine, with acquire semantics, whether a bit is set + * @nr: bit number to test + * @addr: Address to start counting from + */ +static __always_inline bool +arch_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} +#define test_bit_acquire arch_test_bit_acquire + #endif /* _ASM_GENERIC_BITOPS_NON_ATOMIC_H_ */ Index: linux-stable/include/linux/buffer_head.h =================================================================== --- linux-stable.orig/include/linux/buffer_head.h 2022-10-18 12:42:09.000000000 +0200 +++ linux-stable/include/linux/buffer_head.h 2022-10-18 12:42:09.000000000 +0200 @@ -166,7 +166,7 @@ static __always_inline int buffer_uptoda * make it consistent with folio_test_uptodate * pairs with smp_mb__before_atomic in set_buffer_uptodate */ - return (smp_load_acquire(&bh->b_state) & (1UL << BH_Uptodate)) != 0; + return test_bit_acquire(BH_Uptodate, &bh->b_state); }
#define bh_offset(bh) ((unsigned long)(bh)->b_data & ~PAGE_MASK) Index: linux-stable/include/linux/wait_bit.h =================================================================== --- linux-stable.orig/include/linux/wait_bit.h 2022-10-18 12:42:09.000000000 +0200 +++ linux-stable/include/linux/wait_bit.h 2022-10-18 12:42:09.000000000 +0200 @@ -71,7 +71,7 @@ static inline int wait_on_bit(unsigned long *word, int bit, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, bit_wait, @@ -96,7 +96,7 @@ static inline int wait_on_bit_io(unsigned long *word, int bit, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, bit_wait_io, @@ -123,7 +123,7 @@ wait_on_bit_timeout(unsigned long *word, unsigned long timeout) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit_timeout(word, bit, bit_wait_timeout, @@ -151,7 +151,7 @@ wait_on_bit_action(unsigned long *word, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, action, mode); } Index: linux-stable/kernel/sched/wait_bit.c =================================================================== --- linux-stable.orig/kernel/sched/wait_bit.c 2022-10-18 12:42:09.000000000 +0200 +++ linux-stable/kernel/sched/wait_bit.c 2022-10-18 12:42:09.000000000 +0200 @@ -47,7 +47,7 @@ __wait_on_bit(struct wait_queue_head *wq prepare_to_wait(wq_head, &wbq_entry->wq_entry, mode); if (test_bit(wbq_entry->key.bit_nr, wbq_entry->key.flags)) ret = (*action)(&wbq_entry->key, mode); - } while (test_bit(wbq_entry->key.bit_nr, wbq_entry->key.flags) && !ret); + } while (test_bit_acquire(wbq_entry->key.bit_nr, wbq_entry->key.flags) && !ret);
finish_wait(wq_head, &wbq_entry->wq_entry);
Index: linux-stable/arch/alpha/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/alpha/include/asm/bitops.h 2022-10-18 12:42:09.000000000 +0200 +++ linux-stable/arch/alpha/include/asm/bitops.h 2022-10-18 12:42:09.000000000 +0200 @@ -289,6 +289,13 @@ test_bit(int nr, const volatile void * a return (1UL & (((const int *) addr)[nr >> 5] >> (nr & 31))) != 0UL; }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + /* * ffz = Find First Zero in word. Undefined if no zero exists, * so code should check against ~0UL first.. Index: linux-stable/arch/hexagon/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/hexagon/include/asm/bitops.h 2022-10-18 12:42:09.000000000 +0200 +++ linux-stable/arch/hexagon/include/asm/bitops.h 2022-10-18 12:42:09.000000000 +0200 @@ -172,7 +172,22 @@ static inline int __test_bit(int nr, con return retval; }
+static inline int __test_bit_acquire(int nr, const volatile unsigned long *addr) +{ + int retval; + + asm volatile( + "{P0 = tstbit(%1,%2); if (P0.new) %0 = #1; if (!P0.new) %0 = #0;}\n" + : "=&r" (retval) + : "r" (addr[BIT_WORD(nr)]), "r" (nr % BITS_PER_LONG) + : "p0", "memory" + ); + + return retval; +} + #define test_bit(nr, addr) __test_bit(nr, addr) +#define test_bit_acquire(nr, addr) __test_bit_acquire(nr, addr)
/* * ffz - find first zero in word. Index: linux-stable/arch/ia64/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/ia64/include/asm/bitops.h 2022-10-18 12:42:09.000000000 +0200 +++ linux-stable/arch/ia64/include/asm/bitops.h 2022-10-18 12:42:09.000000000 +0200 @@ -337,6 +337,13 @@ test_bit (int nr, const volatile void *a return 1 & (((const volatile __u32 *) addr)[nr >> 5] >> (nr & 31)); }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + /** * ffz - find the first zero bit in a long word * @x: The long word to find the bit in Index: linux-stable/arch/m68k/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/m68k/include/asm/bitops.h 2022-10-18 12:42:09.000000000 +0200 +++ linux-stable/arch/m68k/include/asm/bitops.h 2022-10-18 12:42:09.000000000 +0200 @@ -153,6 +153,12 @@ static inline int test_bit(int nr, const return (vaddr[nr >> 5] & (1UL << (nr & 31))) != 0; }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +}
static inline int bset_reg_test_and_set_bit(int nr, volatile unsigned long *vaddr) Index: linux-stable/arch/s390/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/s390/include/asm/bitops.h 2022-10-18 12:42:09.000000000 +0200 +++ linux-stable/arch/s390/include/asm/bitops.h 2022-10-18 12:42:09.000000000 +0200 @@ -184,6 +184,13 @@ static inline bool arch_test_bit(unsigne return *addr & mask; }
+static __always_inline bool +arch_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + static inline bool arch_test_and_set_bit_lock(unsigned long nr, volatile unsigned long *ptr) { Index: linux-stable/arch/sh/include/asm/bitops-op32.h =================================================================== --- linux-stable.orig/arch/sh/include/asm/bitops-op32.h 2022-10-18 12:42:09.000000000 +0200 +++ linux-stable/arch/sh/include/asm/bitops-op32.h 2022-10-18 12:42:09.000000000 +0200 @@ -138,4 +138,11 @@ static inline int test_bit(int nr, const return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + #endif /* __ASM_SH_BITOPS_OP32_H */ Index: linux-stable/arch/h8300/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/h8300/include/asm/bitops.h 2022-10-18 12:42:09.000000000 +0200 +++ linux-stable/arch/h8300/include/asm/bitops.h 2022-10-18 12:42:09.000000000 +0200 @@ -87,7 +87,8 @@ static inline int test_bit(int nr, const return ret; }
-#define __test_bit(nr, addr) test_bit(nr, addr) +#define __test_bit(nr, addr) test_bit(nr, addr) +#define test_bit_acquire(nr, addr) test_bit(nr, addr)
#define H8300_GEN_TEST_BITOP(FNNAME, OP) \ static inline int FNNAME(int nr, void *addr) \
This is backport of the upstream patch 8238b4579866b7c1bb99883cfe102a43db5506ff for the stable branch 5.10
wait_on_bit: add an acquire memory barrier
There are several places in the kernel where wait_on_bit is not followed by a memory barrier (for example, in drivers/md/dm-bufio.c:new_read).
On architectures with weak memory ordering, it may happen that memory accesses that follow wait_on_bit are reordered before wait_on_bit and they may return invalid data.
Fix this class of bugs by introducing a new function "test_bit_acquire" that works like test_bit, but has acquire memory ordering semantics.
Signed-off-by: Mikulas Patocka mpatocka@redhat.com Acked-by: Will Deacon will@kernel.org Cc: stable@vger.kernel.org Signed-off-by: Linus Torvalds torvalds@linux-foundation.org
--- arch/alpha/include/asm/bitops.h | 7 ++++++ arch/arc/include/asm/bitops.h | 7 ++++++ arch/h8300/include/asm/bitops.h | 3 +- arch/hexagon/include/asm/bitops.h | 15 +++++++++++++ arch/ia64/include/asm/bitops.h | 7 ++++++ arch/m68k/include/asm/bitops.h | 6 +++++ arch/s390/include/asm/bitops.h | 7 ++++++ arch/sh/include/asm/bitops-op32.h | 7 ++++++ arch/x86/include/asm/bitops.h | 21 +++++++++++++++++++ include/asm-generic/bitops/instrumented-non-atomic.h | 12 ++++++++++ include/asm-generic/bitops/non-atomic.h | 14 ++++++++++++ include/linux/buffer_head.h | 2 - include/linux/wait_bit.h | 8 +++---- kernel/sched/wait_bit.c | 2 - 14 files changed, 111 insertions(+), 7 deletions(-)
Index: linux-stable/arch/x86/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/x86/include/asm/bitops.h 2022-10-17 19:38:32.000000000 +0200 +++ linux-stable/arch/x86/include/asm/bitops.h 2022-10-17 19:38:32.000000000 +0200 @@ -207,6 +207,20 @@ static __always_inline bool constant_tes (addr[nr >> _BITOPS_LONG_SHIFT])) != 0; }
+static __always_inline bool constant_test_bit_acquire(long nr, const volatile unsigned long *addr) +{ + bool oldbit; + + asm volatile("testb %2,%1" + CC_SET(nz) + : CC_OUT(nz) (oldbit) + : "m" (((unsigned char *)addr)[nr >> 3]), + "i" (1 << (nr & 7)) + :"memory"); + + return oldbit; +} + static __always_inline bool variable_test_bit(long nr, volatile const unsigned long *addr) { bool oldbit; @@ -224,6 +238,13 @@ static __always_inline bool variable_tes ? constant_test_bit((nr), (addr)) \ : variable_test_bit((nr), (addr)))
+static __always_inline bool +arch_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + return __builtin_constant_p(nr) ? constant_test_bit_acquire(nr, addr) : + variable_test_bit(nr, addr); +} + /** * __ffs - find first set bit in word * @word: The word to search Index: linux-stable/include/asm-generic/bitops/instrumented-non-atomic.h =================================================================== --- linux-stable.orig/include/asm-generic/bitops/instrumented-non-atomic.h 2022-10-17 19:38:32.000000000 +0200 +++ linux-stable/include/asm-generic/bitops/instrumented-non-atomic.h 2022-10-17 19:38:32.000000000 +0200 @@ -135,4 +135,16 @@ static inline bool test_bit(long nr, con return arch_test_bit(nr, addr); }
+/** + * _test_bit_acquire - Determine, with acquire semantics, whether a bit is set + * @nr: bit number to test + * @addr: Address to start counting from + */ +static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + instrument_atomic_read(addr + BIT_WORD(nr), sizeof(long)); + return arch_test_bit_acquire(nr, addr); +} + #endif /* _ASM_GENERIC_BITOPS_INSTRUMENTED_NON_ATOMIC_H */ Index: linux-stable/include/asm-generic/bitops/non-atomic.h =================================================================== --- linux-stable.orig/include/asm-generic/bitops/non-atomic.h 2022-10-17 19:38:32.000000000 +0200 +++ linux-stable/include/asm-generic/bitops/non-atomic.h 2022-10-17 19:38:32.000000000 +0200 @@ -3,6 +3,7 @@ #define _ASM_GENERIC_BITOPS_NON_ATOMIC_H_
#include <asm/types.h> +#include <asm/barrier.h>
/** * __set_bit - Set a bit in memory @@ -106,4 +107,17 @@ static inline int test_bit(int nr, const return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); }
+/** + * arch_test_bit_acquire - Determine, with acquire semantics, whether a bit is set + * @nr: bit number to test + * @addr: Address to start counting from + */ +static __always_inline bool +arch_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} +#define test_bit_acquire arch_test_bit_acquire + #endif /* _ASM_GENERIC_BITOPS_NON_ATOMIC_H_ */ Index: linux-stable/include/linux/buffer_head.h =================================================================== --- linux-stable.orig/include/linux/buffer_head.h 2022-10-17 19:38:32.000000000 +0200 +++ linux-stable/include/linux/buffer_head.h 2022-10-17 19:38:32.000000000 +0200 @@ -166,7 +166,7 @@ static __always_inline int buffer_uptoda * make it consistent with folio_test_uptodate * pairs with smp_mb__before_atomic in set_buffer_uptodate */ - return (smp_load_acquire(&bh->b_state) & (1UL << BH_Uptodate)) != 0; + return test_bit_acquire(BH_Uptodate, &bh->b_state); }
#define bh_offset(bh) ((unsigned long)(bh)->b_data & ~PAGE_MASK) Index: linux-stable/include/linux/wait_bit.h =================================================================== --- linux-stable.orig/include/linux/wait_bit.h 2022-10-17 19:38:32.000000000 +0200 +++ linux-stable/include/linux/wait_bit.h 2022-10-17 19:38:32.000000000 +0200 @@ -71,7 +71,7 @@ static inline int wait_on_bit(unsigned long *word, int bit, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, bit_wait, @@ -96,7 +96,7 @@ static inline int wait_on_bit_io(unsigned long *word, int bit, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, bit_wait_io, @@ -123,7 +123,7 @@ wait_on_bit_timeout(unsigned long *word, unsigned long timeout) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit_timeout(word, bit, bit_wait_timeout, @@ -151,7 +151,7 @@ wait_on_bit_action(unsigned long *word, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, action, mode); } Index: linux-stable/kernel/sched/wait_bit.c =================================================================== --- linux-stable.orig/kernel/sched/wait_bit.c 2022-10-17 19:38:32.000000000 +0200 +++ linux-stable/kernel/sched/wait_bit.c 2022-10-17 19:38:32.000000000 +0200 @@ -47,7 +47,7 @@ __wait_on_bit(struct wait_queue_head *wq prepare_to_wait(wq_head, &wbq_entry->wq_entry, mode); if (test_bit(wbq_entry->key.bit_nr, wbq_entry->key.flags)) ret = (*action)(&wbq_entry->key, mode); - } while (test_bit(wbq_entry->key.bit_nr, wbq_entry->key.flags) && !ret); + } while (test_bit_acquire(wbq_entry->key.bit_nr, wbq_entry->key.flags) && !ret);
finish_wait(wq_head, &wbq_entry->wq_entry);
Index: linux-stable/arch/alpha/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/alpha/include/asm/bitops.h 2022-10-17 19:38:32.000000000 +0200 +++ linux-stable/arch/alpha/include/asm/bitops.h 2022-10-17 19:38:32.000000000 +0200 @@ -289,6 +289,13 @@ test_bit(int nr, const volatile void * a return (1UL & (((const int *) addr)[nr >> 5] >> (nr & 31))) != 0UL; }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + /* * ffz = Find First Zero in word. Undefined if no zero exists, * so code should check against ~0UL first.. Index: linux-stable/arch/hexagon/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/hexagon/include/asm/bitops.h 2022-10-17 19:38:32.000000000 +0200 +++ linux-stable/arch/hexagon/include/asm/bitops.h 2022-10-17 19:38:32.000000000 +0200 @@ -172,7 +172,22 @@ static inline int __test_bit(int nr, con return retval; }
+static inline int __test_bit_acquire(int nr, const volatile unsigned long *addr) +{ + int retval; + + asm volatile( + "{P0 = tstbit(%1,%2); if (P0.new) %0 = #1; if (!P0.new) %0 = #0;}\n" + : "=&r" (retval) + : "r" (addr[BIT_WORD(nr)]), "r" (nr % BITS_PER_LONG) + : "p0", "memory" + ); + + return retval; +} + #define test_bit(nr, addr) __test_bit(nr, addr) +#define test_bit_acquire(nr, addr) __test_bit_acquire(nr, addr)
/* * ffz - find first zero in word. Index: linux-stable/arch/ia64/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/ia64/include/asm/bitops.h 2022-10-17 19:38:32.000000000 +0200 +++ linux-stable/arch/ia64/include/asm/bitops.h 2022-10-17 19:38:32.000000000 +0200 @@ -337,6 +337,13 @@ test_bit (int nr, const volatile void *a return 1 & (((const volatile __u32 *) addr)[nr >> 5] >> (nr & 31)); }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + /** * ffz - find the first zero bit in a long word * @x: The long word to find the bit in Index: linux-stable/arch/m68k/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/m68k/include/asm/bitops.h 2022-10-17 19:38:32.000000000 +0200 +++ linux-stable/arch/m68k/include/asm/bitops.h 2022-10-17 19:38:32.000000000 +0200 @@ -153,6 +153,12 @@ static inline int test_bit(int nr, const return (vaddr[nr >> 5] & (1UL << (nr & 31))) != 0; }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +}
static inline int bset_reg_test_and_set_bit(int nr, volatile unsigned long *vaddr) Index: linux-stable/arch/s390/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/s390/include/asm/bitops.h 2022-10-17 19:38:32.000000000 +0200 +++ linux-stable/arch/s390/include/asm/bitops.h 2022-10-17 19:38:32.000000000 +0200 @@ -219,6 +219,13 @@ static inline bool arch_test_bit(unsigne return (*addr >> (nr & 7)) & 1; }
+static __always_inline bool +arch_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + static inline bool arch_test_and_set_bit_lock(unsigned long nr, volatile unsigned long *ptr) { Index: linux-stable/arch/sh/include/asm/bitops-op32.h =================================================================== --- linux-stable.orig/arch/sh/include/asm/bitops-op32.h 2022-10-17 19:38:32.000000000 +0200 +++ linux-stable/arch/sh/include/asm/bitops-op32.h 2022-10-17 19:38:32.000000000 +0200 @@ -138,4 +138,11 @@ static inline int test_bit(int nr, const return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + #endif /* __ASM_SH_BITOPS_OP32_H */ Index: linux-stable/arch/h8300/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/h8300/include/asm/bitops.h 2022-10-17 19:38:32.000000000 +0200 +++ linux-stable/arch/h8300/include/asm/bitops.h 2022-10-17 19:38:32.000000000 +0200 @@ -83,7 +83,8 @@ static inline int test_bit(int nr, const return ret; }
-#define __test_bit(nr, addr) test_bit(nr, addr) +#define __test_bit(nr, addr) test_bit(nr, addr) +#define test_bit_acquire(nr, addr) test_bit(nr, addr)
#define H8300_GEN_TEST_BITOP(FNNAME, OP) \ static inline int FNNAME(int nr, void *addr) \ Index: linux-stable/arch/arc/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/arc/include/asm/bitops.h 2022-10-17 19:35:36.000000000 +0200 +++ linux-stable/arch/arc/include/asm/bitops.h 2022-10-17 19:41:07.000000000 +0200 @@ -197,6 +197,13 @@ test_bit(unsigned int nr, const volatile return ((mask & *addr) != 0); }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + #ifdef CONFIG_ISA_ARCOMPACT
/*
This is backport of the upstream patch 8238b4579866b7c1bb99883cfe102a43db5506ff for the stable branch 5.4
wait_on_bit: add an acquire memory barrier
There are several places in the kernel where wait_on_bit is not followed by a memory barrier (for example, in drivers/md/dm-bufio.c:new_read).
On architectures with weak memory ordering, it may happen that memory accesses that follow wait_on_bit are reordered before wait_on_bit and they may return invalid data.
Fix this class of bugs by introducing a new function "test_bit_acquire" that works like test_bit, but has acquire memory ordering semantics.
Signed-off-by: Mikulas Patocka mpatocka@redhat.com Acked-by: Will Deacon will@kernel.org Cc: stable@vger.kernel.org Signed-off-by: Linus Torvalds torvalds@linux-foundation.org
--- arch/alpha/include/asm/bitops.h | 7 +++++++ arch/arc/include/asm/bitops.h | 7 +++++++ arch/h8300/include/asm/bitops.h | 3 ++- arch/hexagon/include/asm/bitops.h | 15 +++++++++++++++ arch/ia64/include/asm/bitops.h | 7 +++++++ arch/m68k/include/asm/bitops.h | 6 ++++++ arch/s390/include/asm/bitops.h | 7 +++++++ arch/sh/include/asm/bitops-op32.h | 7 +++++++ arch/x86/include/asm/bitops.h | 21 +++++++++++++++++++++ include/asm-generic/bitops-instrumented.h | 6 ++++++ include/asm-generic/bitops/non-atomic.h | 14 ++++++++++++++ include/linux/buffer_head.h | 2 +- include/linux/wait_bit.h | 8 ++++---- kernel/sched/wait_bit.c | 2 +- 14 files changed, 105 insertions(+), 7 deletions(-)
Index: linux-stable/arch/x86/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/x86/include/asm/bitops.h 2022-10-17 19:50:18.000000000 +0200 +++ linux-stable/arch/x86/include/asm/bitops.h 2022-10-17 19:50:18.000000000 +0200 @@ -207,6 +207,20 @@ static __always_inline bool constant_tes (addr[nr >> _BITOPS_LONG_SHIFT])) != 0; }
+static __always_inline bool constant_test_bit_acquire(long nr, const volatile unsigned long *addr) +{ + bool oldbit; + + asm volatile("testb %2,%1" + CC_SET(nz) + : CC_OUT(nz) (oldbit) + : "m" (((unsigned char *)addr)[nr >> 3]), + "i" (1 << (nr & 7)) + :"memory"); + + return oldbit; +} + static __always_inline bool variable_test_bit(long nr, volatile const unsigned long *addr) { bool oldbit; @@ -224,6 +238,13 @@ static __always_inline bool variable_tes ? constant_test_bit((nr), (addr)) \ : variable_test_bit((nr), (addr)))
+static __always_inline bool +arch_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + return __builtin_constant_p(nr) ? constant_test_bit_acquire(nr, addr) : + variable_test_bit(nr, addr); +} + /** * __ffs - find first set bit in word * @word: The word to search Index: linux-stable/include/asm-generic/bitops/non-atomic.h =================================================================== --- linux-stable.orig/include/asm-generic/bitops/non-atomic.h 2022-10-17 19:50:18.000000000 +0200 +++ linux-stable/include/asm-generic/bitops/non-atomic.h 2022-10-17 19:50:18.000000000 +0200 @@ -3,6 +3,7 @@ #define _ASM_GENERIC_BITOPS_NON_ATOMIC_H_
#include <asm/types.h> +#include <asm/barrier.h>
/** * __set_bit - Set a bit in memory @@ -106,4 +107,17 @@ static inline int test_bit(int nr, const return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); }
+/** + * arch_test_bit_acquire - Determine, with acquire semantics, whether a bit is set + * @nr: bit number to test + * @addr: Address to start counting from + */ +static __always_inline bool +arch_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} +#define test_bit_acquire arch_test_bit_acquire + #endif /* _ASM_GENERIC_BITOPS_NON_ATOMIC_H_ */ Index: linux-stable/include/linux/buffer_head.h =================================================================== --- linux-stable.orig/include/linux/buffer_head.h 2022-10-17 19:50:18.000000000 +0200 +++ linux-stable/include/linux/buffer_head.h 2022-10-17 19:50:18.000000000 +0200 @@ -166,7 +166,7 @@ static __always_inline int buffer_uptoda * make it consistent with folio_test_uptodate * pairs with smp_mb__before_atomic in set_buffer_uptodate */ - return (smp_load_acquire(&bh->b_state) & (1UL << BH_Uptodate)) != 0; + return test_bit_acquire(BH_Uptodate, &bh->b_state); }
#define bh_offset(bh) ((unsigned long)(bh)->b_data & ~PAGE_MASK) Index: linux-stable/include/linux/wait_bit.h =================================================================== --- linux-stable.orig/include/linux/wait_bit.h 2022-10-17 19:50:18.000000000 +0200 +++ linux-stable/include/linux/wait_bit.h 2022-10-17 19:50:18.000000000 +0200 @@ -71,7 +71,7 @@ static inline int wait_on_bit(unsigned long *word, int bit, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, bit_wait, @@ -96,7 +96,7 @@ static inline int wait_on_bit_io(unsigned long *word, int bit, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, bit_wait_io, @@ -123,7 +123,7 @@ wait_on_bit_timeout(unsigned long *word, unsigned long timeout) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit_timeout(word, bit, bit_wait_timeout, @@ -151,7 +151,7 @@ wait_on_bit_action(unsigned long *word, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, action, mode); } Index: linux-stable/kernel/sched/wait_bit.c =================================================================== --- linux-stable.orig/kernel/sched/wait_bit.c 2022-10-17 19:50:18.000000000 +0200 +++ linux-stable/kernel/sched/wait_bit.c 2022-10-17 19:50:18.000000000 +0200 @@ -47,7 +47,7 @@ __wait_on_bit(struct wait_queue_head *wq prepare_to_wait(wq_head, &wbq_entry->wq_entry, mode); if (test_bit(wbq_entry->key.bit_nr, wbq_entry->key.flags)) ret = (*action)(&wbq_entry->key, mode); - } while (test_bit(wbq_entry->key.bit_nr, wbq_entry->key.flags) && !ret); + } while (test_bit_acquire(wbq_entry->key.bit_nr, wbq_entry->key.flags) && !ret);
finish_wait(wq_head, &wbq_entry->wq_entry);
Index: linux-stable/include/asm-generic/bitops-instrumented.h =================================================================== --- linux-stable.orig/include/asm-generic/bitops-instrumented.h 2022-10-17 19:50:18.000000000 +0200 +++ linux-stable/include/asm-generic/bitops-instrumented.h 2022-10-17 19:50:18.000000000 +0200 @@ -238,6 +238,12 @@ static inline bool test_bit(long nr, con return arch_test_bit(nr, addr); }
+static inline bool test_bit_acquire(long nr, const volatile unsigned long *addr) +{ + kasan_check_read(addr + BIT_WORD(nr), sizeof(long)); + return arch_test_bit_acquire(nr, addr); +} + #if defined(arch_clear_bit_unlock_is_negative_byte) /** * clear_bit_unlock_is_negative_byte - Clear a bit in memory and test if bottom Index: linux-stable/arch/alpha/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/alpha/include/asm/bitops.h 2022-10-17 19:50:18.000000000 +0200 +++ linux-stable/arch/alpha/include/asm/bitops.h 2022-10-17 19:50:18.000000000 +0200 @@ -289,6 +289,13 @@ test_bit(int nr, const volatile void * a return (1UL & (((const int *) addr)[nr >> 5] >> (nr & 31))) != 0UL; }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + /* * ffz = Find First Zero in word. Undefined if no zero exists, * so code should check against ~0UL first.. Index: linux-stable/arch/hexagon/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/hexagon/include/asm/bitops.h 2022-10-17 19:50:18.000000000 +0200 +++ linux-stable/arch/hexagon/include/asm/bitops.h 2022-10-17 19:50:18.000000000 +0200 @@ -172,7 +172,22 @@ static inline int __test_bit(int nr, con return retval; }
+static inline int __test_bit_acquire(int nr, const volatile unsigned long *addr) +{ + int retval; + + asm volatile( + "{P0 = tstbit(%1,%2); if (P0.new) %0 = #1; if (!P0.new) %0 = #0;}\n" + : "=&r" (retval) + : "r" (addr[BIT_WORD(nr)]), "r" (nr % BITS_PER_LONG) + : "p0", "memory" + ); + + return retval; +} + #define test_bit(nr, addr) __test_bit(nr, addr) +#define test_bit_acquire(nr, addr) __test_bit_acquire(nr, addr)
/* * ffz - find first zero in word. Index: linux-stable/arch/ia64/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/ia64/include/asm/bitops.h 2022-10-17 19:50:18.000000000 +0200 +++ linux-stable/arch/ia64/include/asm/bitops.h 2022-10-17 19:50:18.000000000 +0200 @@ -337,6 +337,13 @@ test_bit (int nr, const volatile void *a return 1 & (((const volatile __u32 *) addr)[nr >> 5] >> (nr & 31)); }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + /** * ffz - find the first zero bit in a long word * @x: The long word to find the bit in Index: linux-stable/arch/m68k/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/m68k/include/asm/bitops.h 2022-10-17 19:50:18.000000000 +0200 +++ linux-stable/arch/m68k/include/asm/bitops.h 2022-10-17 19:50:18.000000000 +0200 @@ -153,6 +153,12 @@ static inline int test_bit(int nr, const return (vaddr[nr >> 5] & (1UL << (nr & 31))) != 0; }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +}
static inline int bset_reg_test_and_set_bit(int nr, volatile unsigned long *vaddr) Index: linux-stable/arch/s390/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/s390/include/asm/bitops.h 2022-10-17 19:50:18.000000000 +0200 +++ linux-stable/arch/s390/include/asm/bitops.h 2022-10-17 19:50:18.000000000 +0200 @@ -219,6 +219,13 @@ static inline bool arch_test_bit(unsigne return (*addr >> (nr & 7)) & 1; }
+static __always_inline bool +arch_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + static inline bool arch_test_and_set_bit_lock(unsigned long nr, volatile unsigned long *ptr) { Index: linux-stable/arch/sh/include/asm/bitops-op32.h =================================================================== --- linux-stable.orig/arch/sh/include/asm/bitops-op32.h 2022-10-17 19:50:18.000000000 +0200 +++ linux-stable/arch/sh/include/asm/bitops-op32.h 2022-10-17 19:50:18.000000000 +0200 @@ -140,4 +140,11 @@ static inline int test_bit(int nr, const return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + #endif /* __ASM_SH_BITOPS_OP32_H */ Index: linux-stable/arch/arc/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/arc/include/asm/bitops.h 2022-10-17 19:50:18.000000000 +0200 +++ linux-stable/arch/arc/include/asm/bitops.h 2022-10-17 19:50:18.000000000 +0200 @@ -251,6 +251,13 @@ test_bit(unsigned int nr, const volatile return ((mask & *addr) != 0); }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + #ifdef CONFIG_ISA_ARCOMPACT
/* Index: linux-stable/arch/h8300/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/h8300/include/asm/bitops.h 2022-10-17 19:46:50.000000000 +0200 +++ linux-stable/arch/h8300/include/asm/bitops.h 2022-10-17 19:54:41.000000000 +0200 @@ -83,7 +83,8 @@ static inline int test_bit(int nr, const return ret; }
-#define __test_bit(nr, addr) test_bit(nr, addr) +#define __test_bit(nr, addr) test_bit(nr, addr) +#define test_bit_acquire(nr, addr) test_bit(nr, addr)
#define H8300_GEN_TEST_BITOP(FNNAME, OP) \ static inline int FNNAME(int nr, void *addr) \
This is backport of the upstream patch 8238b4579866b7c1bb99883cfe102a43db5506ff for the stable branch 4.19
wait_on_bit: add an acquire memory barrier
There are several places in the kernel where wait_on_bit is not followed by a memory barrier (for example, in drivers/md/dm-bufio.c:new_read).
On architectures with weak memory ordering, it may happen that memory accesses that follow wait_on_bit are reordered before wait_on_bit and they may return invalid data.
Fix this class of bugs by introducing a new function "test_bit_acquire" that works like test_bit, but has acquire memory ordering semantics.
Signed-off-by: Mikulas Patocka mpatocka@redhat.com Acked-by: Will Deacon will@kernel.org Cc: stable@vger.kernel.org Signed-off-by: Linus Torvalds torvalds@linux-foundation.org
--- arch/alpha/include/asm/bitops.h | 7 +++++++ arch/arc/include/asm/bitops.h | 7 +++++++ arch/h8300/include/asm/bitops.h | 3 ++- arch/hexagon/include/asm/bitops.h | 15 +++++++++++++++ arch/ia64/include/asm/bitops.h | 7 +++++++ arch/m68k/include/asm/bitops.h | 6 ++++++ arch/s390/include/asm/bitops.h | 7 +++++++ arch/sh/include/asm/bitops-op32.h | 7 +++++++ arch/x86/include/asm/bitops.h | 21 +++++++++++++++++++++ include/asm-generic/bitops/non-atomic.h | 14 ++++++++++++++ include/linux/buffer_head.h | 2 +- include/linux/wait_bit.h | 8 ++++---- kernel/sched/wait_bit.c | 2 +- 13 files changed, 99 insertions(+), 7 deletions(-)
Index: linux-stable/arch/x86/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/x86/include/asm/bitops.h 2022-10-17 20:04:40.000000000 +0200 +++ linux-stable/arch/x86/include/asm/bitops.h 2022-10-17 20:04:40.000000000 +0200 @@ -317,6 +317,20 @@ static __always_inline bool constant_tes (addr[nr >> _BITOPS_LONG_SHIFT])) != 0; }
+static __always_inline bool constant_test_bit_acquire(long nr, const volatile unsigned long *addr) +{ + bool oldbit; + + asm volatile("testb %2,%1" + CC_SET(nz) + : CC_OUT(nz) (oldbit) + : "m" (((unsigned char *)addr)[nr >> 3]), + "i" (1 << (nr & 7)) + :"memory"); + + return oldbit; +} + static __always_inline bool variable_test_bit(long nr, volatile const unsigned long *addr) { bool oldbit; @@ -343,6 +357,13 @@ static bool test_bit(int nr, const volat ? constant_test_bit((nr), (addr)) \ : variable_test_bit((nr), (addr)))
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + return __builtin_constant_p(nr) ? constant_test_bit_acquire(nr, addr) : + variable_test_bit(nr, addr); +} + /** * __ffs - find first set bit in word * @word: The word to search Index: linux-stable/include/asm-generic/bitops/non-atomic.h =================================================================== --- linux-stable.orig/include/asm-generic/bitops/non-atomic.h 2022-10-17 20:04:40.000000000 +0200 +++ linux-stable/include/asm-generic/bitops/non-atomic.h 2022-10-17 20:04:40.000000000 +0200 @@ -3,6 +3,7 @@ #define _ASM_GENERIC_BITOPS_NON_ATOMIC_H_
#include <asm/types.h> +#include <asm/barrier.h>
/** * __set_bit - Set a bit in memory @@ -106,4 +107,17 @@ static inline int test_bit(int nr, const return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); }
+/** + * arch_test_bit_acquire - Determine, with acquire semantics, whether a bit is set + * @nr: bit number to test + * @addr: Address to start counting from + */ +static __always_inline bool +arch_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} +#define test_bit_acquire arch_test_bit_acquire + #endif /* _ASM_GENERIC_BITOPS_NON_ATOMIC_H_ */ Index: linux-stable/include/linux/buffer_head.h =================================================================== --- linux-stable.orig/include/linux/buffer_head.h 2022-10-17 20:04:40.000000000 +0200 +++ linux-stable/include/linux/buffer_head.h 2022-10-17 20:04:40.000000000 +0200 @@ -166,7 +166,7 @@ static __always_inline int buffer_uptoda * make it consistent with folio_test_uptodate * pairs with smp_mb__before_atomic in set_buffer_uptodate */ - return (smp_load_acquire(&bh->b_state) & (1UL << BH_Uptodate)) != 0; + return test_bit_acquire(BH_Uptodate, &bh->b_state); }
#define bh_offset(bh) ((unsigned long)(bh)->b_data & ~PAGE_MASK) Index: linux-stable/include/linux/wait_bit.h =================================================================== --- linux-stable.orig/include/linux/wait_bit.h 2022-10-17 20:04:40.000000000 +0200 +++ linux-stable/include/linux/wait_bit.h 2022-10-17 20:04:40.000000000 +0200 @@ -71,7 +71,7 @@ static inline int wait_on_bit(unsigned long *word, int bit, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, bit_wait, @@ -96,7 +96,7 @@ static inline int wait_on_bit_io(unsigned long *word, int bit, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, bit_wait_io, @@ -123,7 +123,7 @@ wait_on_bit_timeout(unsigned long *word, unsigned long timeout) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit_timeout(word, bit, bit_wait_timeout, @@ -151,7 +151,7 @@ wait_on_bit_action(unsigned long *word, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, action, mode); } Index: linux-stable/kernel/sched/wait_bit.c =================================================================== --- linux-stable.orig/kernel/sched/wait_bit.c 2022-10-17 20:04:40.000000000 +0200 +++ linux-stable/kernel/sched/wait_bit.c 2022-10-17 20:04:40.000000000 +0200 @@ -46,7 +46,7 @@ __wait_on_bit(struct wait_queue_head *wq prepare_to_wait(wq_head, &wbq_entry->wq_entry, mode); if (test_bit(wbq_entry->key.bit_nr, wbq_entry->key.flags)) ret = (*action)(&wbq_entry->key, mode); - } while (test_bit(wbq_entry->key.bit_nr, wbq_entry->key.flags) && !ret); + } while (test_bit_acquire(wbq_entry->key.bit_nr, wbq_entry->key.flags) && !ret);
finish_wait(wq_head, &wbq_entry->wq_entry);
Index: linux-stable/arch/alpha/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/alpha/include/asm/bitops.h 2022-10-17 20:04:40.000000000 +0200 +++ linux-stable/arch/alpha/include/asm/bitops.h 2022-10-17 20:04:40.000000000 +0200 @@ -289,6 +289,13 @@ test_bit(int nr, const volatile void * a return (1UL & (((const int *) addr)[nr >> 5] >> (nr & 31))) != 0UL; }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + /* * ffz = Find First Zero in word. Undefined if no zero exists, * so code should check against ~0UL first.. Index: linux-stable/arch/hexagon/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/hexagon/include/asm/bitops.h 2022-10-17 20:04:40.000000000 +0200 +++ linux-stable/arch/hexagon/include/asm/bitops.h 2022-10-17 20:04:40.000000000 +0200 @@ -186,7 +186,22 @@ static inline int __test_bit(int nr, con return retval; }
+static inline int __test_bit_acquire(int nr, const volatile unsigned long *addr) +{ + int retval; + + asm volatile( + "{P0 = tstbit(%1,%2); if (P0.new) %0 = #1; if (!P0.new) %0 = #0;}\n" + : "=&r" (retval) + : "r" (addr[BIT_WORD(nr)]), "r" (nr % BITS_PER_LONG) + : "p0", "memory" + ); + + return retval; +} + #define test_bit(nr, addr) __test_bit(nr, addr) +#define test_bit_acquire(nr, addr) __test_bit_acquire(nr, addr)
/* * ffz - find first zero in word. Index: linux-stable/arch/ia64/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/ia64/include/asm/bitops.h 2022-10-17 20:04:40.000000000 +0200 +++ linux-stable/arch/ia64/include/asm/bitops.h 2022-10-17 20:04:40.000000000 +0200 @@ -337,6 +337,13 @@ test_bit (int nr, const volatile void *a return 1 & (((const volatile __u32 *) addr)[nr >> 5] >> (nr & 31)); }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + /** * ffz - find the first zero bit in a long word * @x: The long word to find the bit in Index: linux-stable/arch/m68k/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/m68k/include/asm/bitops.h 2022-10-17 20:04:40.000000000 +0200 +++ linux-stable/arch/m68k/include/asm/bitops.h 2022-10-17 20:04:40.000000000 +0200 @@ -153,6 +153,12 @@ static inline int test_bit(int nr, const return (vaddr[nr >> 5] & (1UL << (nr & 31))) != 0; }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +}
static inline int bset_reg_test_and_set_bit(int nr, volatile unsigned long *vaddr) Index: linux-stable/arch/s390/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/s390/include/asm/bitops.h 2022-10-17 20:04:40.000000000 +0200 +++ linux-stable/arch/s390/include/asm/bitops.h 2022-10-17 20:04:40.000000000 +0200 @@ -215,6 +215,13 @@ static inline int test_bit(unsigned long return (*addr >> (nr & 7)) & 1; }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + static inline int test_and_set_bit_lock(unsigned long nr, volatile unsigned long *ptr) { Index: linux-stable/arch/sh/include/asm/bitops-op32.h =================================================================== --- linux-stable.orig/arch/sh/include/asm/bitops-op32.h 2022-10-17 20:04:40.000000000 +0200 +++ linux-stable/arch/sh/include/asm/bitops-op32.h 2022-10-17 20:04:40.000000000 +0200 @@ -140,4 +140,11 @@ static inline int test_bit(int nr, const return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + #endif /* __ASM_SH_BITOPS_OP32_H */ Index: linux-stable/arch/arc/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/arc/include/asm/bitops.h 2022-10-17 20:04:40.000000000 +0200 +++ linux-stable/arch/arc/include/asm/bitops.h 2022-10-17 20:04:40.000000000 +0200 @@ -254,6 +254,13 @@ test_bit(unsigned int nr, const volatile return ((mask & *addr) != 0); }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + #ifdef CONFIG_ISA_ARCOMPACT
/* Index: linux-stable/arch/h8300/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/h8300/include/asm/bitops.h 2022-10-17 20:04:40.000000000 +0200 +++ linux-stable/arch/h8300/include/asm/bitops.h 2022-10-17 20:04:40.000000000 +0200 @@ -89,7 +89,8 @@ static inline int test_bit(int nr, const return ret; }
-#define __test_bit(nr, addr) test_bit(nr, addr) +#define __test_bit(nr, addr) test_bit(nr, addr) +#define test_bit_acquire(nr, addr) test_bit(nr, addr)
#define H8300_GEN_TEST_BITOP(FNNAME, OP) \ static inline int FNNAME(int nr, void *addr) \
This is backport of the upstream patch 8238b4579866b7c1bb99883cfe102a43db5506ff for the stable branch 4.14
wait_on_bit: add an acquire memory barrier
There are several places in the kernel where wait_on_bit is not followed by a memory barrier (for example, in drivers/md/dm-bufio.c:new_read).
On architectures with weak memory ordering, it may happen that memory accesses that follow wait_on_bit are reordered before wait_on_bit and they may return invalid data.
Fix this class of bugs by introducing a new function "test_bit_acquire" that works like test_bit, but has acquire memory ordering semantics.
Signed-off-by: Mikulas Patocka mpatocka@redhat.com Acked-by: Will Deacon will@kernel.org Cc: stable@vger.kernel.org Signed-off-by: Linus Torvalds torvalds@linux-foundation.org
--- arch/alpha/include/asm/bitops.h | 7 +++++++ arch/arc/include/asm/bitops.h | 7 +++++++ arch/frv/include/asm/bitops.h | 7 +++++++ arch/h8300/include/asm/bitops.h | 3 ++- arch/hexagon/include/asm/bitops.h | 15 +++++++++++++++ arch/ia64/include/asm/bitops.h | 7 +++++++ arch/m68k/include/asm/bitops.h | 6 ++++++ arch/mn10300/include/asm/bitops.h | 7 +++++++ arch/s390/include/asm/bitops.h | 7 +++++++ arch/sh/include/asm/bitops-op32.h | 7 +++++++ arch/x86/include/asm/bitops.h | 21 +++++++++++++++++++++ include/asm-generic/bitops/non-atomic.h | 14 ++++++++++++++ include/linux/buffer_head.h | 2 +- include/linux/wait_bit.h | 8 ++++---- kernel/sched/wait_bit.c | 2 +- 15 files changed, 113 insertions(+), 7 deletions(-)
Index: linux-stable/arch/x86/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/x86/include/asm/bitops.h 2022-10-17 20:39:55.000000000 +0200 +++ linux-stable/arch/x86/include/asm/bitops.h 2022-10-17 20:39:55.000000000 +0200 @@ -328,6 +328,20 @@ static __always_inline bool constant_tes (addr[nr >> _BITOPS_LONG_SHIFT])) != 0; }
+static __always_inline bool constant_test_bit_acquire(long nr, const volatile unsigned long *addr) +{ + bool oldbit; + + asm volatile("testb %2,%1" + CC_SET(nz) + : CC_OUT(nz) (oldbit) + : "m" (((unsigned char *)addr)[nr >> 3]), + "i" (1 << (nr & 7)) + :"memory"); + + return oldbit; +} + static __always_inline bool variable_test_bit(long nr, volatile const unsigned long *addr) { bool oldbit; @@ -354,6 +368,13 @@ static bool test_bit(int nr, const volat ? constant_test_bit((nr), (addr)) \ : variable_test_bit((nr), (addr)))
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + return __builtin_constant_p(nr) ? constant_test_bit_acquire(nr, addr) : + variable_test_bit(nr, addr); +} + /** * __ffs - find first set bit in word * @word: The word to search Index: linux-stable/include/asm-generic/bitops/non-atomic.h =================================================================== --- linux-stable.orig/include/asm-generic/bitops/non-atomic.h 2022-10-17 20:39:55.000000000 +0200 +++ linux-stable/include/asm-generic/bitops/non-atomic.h 2022-10-17 20:39:55.000000000 +0200 @@ -3,6 +3,7 @@ #define _ASM_GENERIC_BITOPS_NON_ATOMIC_H_
#include <asm/types.h> +#include <asm/barrier.h>
/** * __set_bit - Set a bit in memory @@ -106,4 +107,17 @@ static inline int test_bit(int nr, const return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); }
+/** + * arch_test_bit_acquire - Determine, with acquire semantics, whether a bit is set + * @nr: bit number to test + * @addr: Address to start counting from + */ +static __always_inline bool +arch_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} +#define test_bit_acquire arch_test_bit_acquire + #endif /* _ASM_GENERIC_BITOPS_NON_ATOMIC_H_ */ Index: linux-stable/include/linux/buffer_head.h =================================================================== --- linux-stable.orig/include/linux/buffer_head.h 2022-10-17 20:39:55.000000000 +0200 +++ linux-stable/include/linux/buffer_head.h 2022-10-17 20:39:55.000000000 +0200 @@ -163,7 +163,7 @@ static __always_inline int buffer_uptoda * make it consistent with folio_test_uptodate * pairs with smp_mb__before_atomic in set_buffer_uptodate */ - return (smp_load_acquire(&bh->b_state) & (1UL << BH_Uptodate)) != 0; + return test_bit_acquire(BH_Uptodate, &bh->b_state); }
#define bh_offset(bh) ((unsigned long)(bh)->b_data & ~PAGE_MASK) Index: linux-stable/include/linux/wait_bit.h =================================================================== --- linux-stable.orig/include/linux/wait_bit.h 2022-10-17 20:39:55.000000000 +0200 +++ linux-stable/include/linux/wait_bit.h 2022-10-17 20:39:55.000000000 +0200 @@ -76,7 +76,7 @@ static inline int wait_on_bit(unsigned long *word, int bit, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, bit_wait, @@ -101,7 +101,7 @@ static inline int wait_on_bit_io(unsigned long *word, int bit, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, bit_wait_io, @@ -128,7 +128,7 @@ wait_on_bit_timeout(unsigned long *word, unsigned long timeout) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit_timeout(word, bit, bit_wait_timeout, @@ -156,7 +156,7 @@ wait_on_bit_action(unsigned long *word, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, action, mode); } Index: linux-stable/kernel/sched/wait_bit.c =================================================================== --- linux-stable.orig/kernel/sched/wait_bit.c 2022-10-17 20:39:55.000000000 +0200 +++ linux-stable/kernel/sched/wait_bit.c 2022-10-17 20:39:55.000000000 +0200 @@ -49,7 +49,7 @@ __wait_on_bit(struct wait_queue_head *wq prepare_to_wait(wq_head, &wbq_entry->wq_entry, mode); if (test_bit(wbq_entry->key.bit_nr, wbq_entry->key.flags)) ret = (*action)(&wbq_entry->key, mode); - } while (test_bit(wbq_entry->key.bit_nr, wbq_entry->key.flags) && !ret); + } while (test_bit_acquire(wbq_entry->key.bit_nr, wbq_entry->key.flags) && !ret); finish_wait(wq_head, &wbq_entry->wq_entry); return ret; } Index: linux-stable/arch/alpha/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/alpha/include/asm/bitops.h 2022-10-17 20:39:55.000000000 +0200 +++ linux-stable/arch/alpha/include/asm/bitops.h 2022-10-17 20:39:55.000000000 +0200 @@ -289,6 +289,13 @@ test_bit(int nr, const volatile void * a return (1UL & (((const int *) addr)[nr >> 5] >> (nr & 31))) != 0UL; }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + /* * ffz = Find First Zero in word. Undefined if no zero exists, * so code should check against ~0UL first.. Index: linux-stable/arch/hexagon/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/hexagon/include/asm/bitops.h 2022-10-17 20:39:55.000000000 +0200 +++ linux-stable/arch/hexagon/include/asm/bitops.h 2022-10-17 20:39:55.000000000 +0200 @@ -186,7 +186,22 @@ static inline int __test_bit(int nr, con return retval; }
+static inline int __test_bit_acquire(int nr, const volatile unsigned long *addr) +{ + int retval; + + asm volatile( + "{P0 = tstbit(%1,%2); if (P0.new) %0 = #1; if (!P0.new) %0 = #0;}\n" + : "=&r" (retval) + : "r" (addr[BIT_WORD(nr)]), "r" (nr % BITS_PER_LONG) + : "p0", "memory" + ); + + return retval; +} + #define test_bit(nr, addr) __test_bit(nr, addr) +#define test_bit_acquire(nr, addr) __test_bit_acquire(nr, addr)
/* * ffz - find first zero in word. Index: linux-stable/arch/ia64/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/ia64/include/asm/bitops.h 2022-10-17 20:39:55.000000000 +0200 +++ linux-stable/arch/ia64/include/asm/bitops.h 2022-10-17 20:39:55.000000000 +0200 @@ -337,6 +337,13 @@ test_bit (int nr, const volatile void *a return 1 & (((const volatile __u32 *) addr)[nr >> 5] >> (nr & 31)); }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + /** * ffz - find the first zero bit in a long word * @x: The long word to find the bit in Index: linux-stable/arch/m68k/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/m68k/include/asm/bitops.h 2022-10-17 20:39:55.000000000 +0200 +++ linux-stable/arch/m68k/include/asm/bitops.h 2022-10-17 20:39:55.000000000 +0200 @@ -153,6 +153,12 @@ static inline int test_bit(int nr, const return (vaddr[nr >> 5] & (1UL << (nr & 31))) != 0; }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +}
static inline int bset_reg_test_and_set_bit(int nr, volatile unsigned long *vaddr) Index: linux-stable/arch/s390/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/s390/include/asm/bitops.h 2022-10-17 20:39:55.000000000 +0200 +++ linux-stable/arch/s390/include/asm/bitops.h 2022-10-17 20:39:55.000000000 +0200 @@ -215,6 +215,13 @@ static inline int test_bit(unsigned long return (*addr >> (nr & 7)) & 1; }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + static inline int test_and_set_bit_lock(unsigned long nr, volatile unsigned long *ptr) { Index: linux-stable/arch/sh/include/asm/bitops-op32.h =================================================================== --- linux-stable.orig/arch/sh/include/asm/bitops-op32.h 2022-10-17 20:39:55.000000000 +0200 +++ linux-stable/arch/sh/include/asm/bitops-op32.h 2022-10-17 20:39:55.000000000 +0200 @@ -140,4 +140,11 @@ static inline int test_bit(int nr, const return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + #endif /* __ASM_SH_BITOPS_OP32_H */ Index: linux-stable/arch/arc/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/arc/include/asm/bitops.h 2022-10-17 20:39:55.000000000 +0200 +++ linux-stable/arch/arc/include/asm/bitops.h 2022-10-17 20:39:55.000000000 +0200 @@ -254,6 +254,13 @@ test_bit(unsigned int nr, const volatile return ((mask & *addr) != 0); }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + #ifdef CONFIG_ISA_ARCOMPACT
/* Index: linux-stable/arch/h8300/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/h8300/include/asm/bitops.h 2022-10-17 20:39:55.000000000 +0200 +++ linux-stable/arch/h8300/include/asm/bitops.h 2022-10-17 20:39:55.000000000 +0200 @@ -89,7 +89,8 @@ static inline int test_bit(int nr, const return ret; }
-#define __test_bit(nr, addr) test_bit(nr, addr) +#define __test_bit(nr, addr) test_bit(nr, addr) +#define test_bit_acquire(nr, addr) test_bit(nr, addr)
#define H8300_GEN_TEST_BITOP(FNNAME, OP) \ static inline int FNNAME(int nr, void *addr) \ Index: linux-stable/arch/frv/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/frv/include/asm/bitops.h 2022-10-17 20:39:55.000000000 +0200 +++ linux-stable/arch/frv/include/asm/bitops.h 2022-10-17 20:39:55.000000000 +0200 @@ -156,6 +156,13 @@ static inline int __test_bit(unsigned lo __constant_test_bit((nr),(addr)) : \ __test_bit((nr),(addr)))
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + #include <asm-generic/bitops/find.h>
/** Index: linux-stable/arch/mn10300/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/mn10300/include/asm/bitops.h 2022-10-17 20:39:46.000000000 +0200 +++ linux-stable/arch/mn10300/include/asm/bitops.h 2022-10-17 20:30:50.000000000 +0200 @@ -73,6 +73,13 @@ static inline int test_bit(unsigned long return 1UL & (((const volatile unsigned int *) addr)[nr >> 5] >> (nr & 31)); }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + /* * change bit */
This is backport of the upstream patch 8238b4579866b7c1bb99883cfe102a43db5506ff for the stable branch 4.9
wait_on_bit: add an acquire memory barrier
There are several places in the kernel where wait_on_bit is not followed by a memory barrier (for example, in drivers/md/dm-bufio.c:new_read).
On architectures with weak memory ordering, it may happen that memory accesses that follow wait_on_bit are reordered before wait_on_bit and they may return invalid data.
Fix this class of bugs by introducing a new function "test_bit_acquire" that works like test_bit, but has acquire memory ordering semantics.
Signed-off-by: Mikulas Patocka mpatocka@redhat.com Acked-by: Will Deacon will@kernel.org Cc: stable@vger.kernel.org Signed-off-by: Linus Torvalds torvalds@linux-foundation.org
--- arch/alpha/include/asm/bitops.h | 7 +++++++ arch/arc/include/asm/bitops.h | 7 +++++++ arch/frv/include/asm/bitops.h | 7 +++++++ arch/h8300/include/asm/bitops.h | 3 ++- arch/hexagon/include/asm/bitops.h | 15 +++++++++++++++ arch/ia64/include/asm/bitops.h | 7 +++++++ arch/m68k/include/asm/bitops.h | 6 ++++++ arch/mn10300/include/asm/bitops.h | 7 +++++++ arch/s390/include/asm/bitops.h | 7 +++++++ arch/sh/include/asm/bitops-op32.h | 7 +++++++ arch/x86/include/asm/bitops.h | 21 +++++++++++++++++++++ include/asm-generic/bitops/non-atomic.h | 14 ++++++++++++++ include/linux/buffer_head.h | 2 +- include/linux/wait.h | 8 ++++---- kernel/sched/wait.c | 2 +- 15 files changed, 113 insertions(+), 7 deletions(-)
Index: linux-stable/arch/x86/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/x86/include/asm/bitops.h 2022-10-17 20:43:20.000000000 +0200 +++ linux-stable/arch/x86/include/asm/bitops.h 2022-10-17 20:43:20.000000000 +0200 @@ -314,6 +314,20 @@ static __always_inline bool constant_tes (addr[nr >> _BITOPS_LONG_SHIFT])) != 0; }
+static __always_inline bool constant_test_bit_acquire(long nr, const volatile unsigned long *addr) +{ + bool oldbit; + + asm volatile("testb %2,%1" + CC_SET(nz) + : CC_OUT(nz) (oldbit) + : "m" (((unsigned char *)addr)[nr >> 3]), + "i" (1 << (nr & 7)) + :"memory"); + + return oldbit; +} + static __always_inline bool variable_test_bit(long nr, volatile const unsigned long *addr) { bool oldbit; @@ -340,6 +354,13 @@ static bool test_bit(int nr, const volat ? constant_test_bit((nr), (addr)) \ : variable_test_bit((nr), (addr)))
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + return __builtin_constant_p(nr) ? constant_test_bit_acquire(nr, addr) : + variable_test_bit(nr, addr); +} + /** * __ffs - find first set bit in word * @word: The word to search Index: linux-stable/include/asm-generic/bitops/non-atomic.h =================================================================== --- linux-stable.orig/include/asm-generic/bitops/non-atomic.h 2022-10-17 20:43:20.000000000 +0200 +++ linux-stable/include/asm-generic/bitops/non-atomic.h 2022-10-17 20:43:20.000000000 +0200 @@ -2,6 +2,7 @@ #define _ASM_GENERIC_BITOPS_NON_ATOMIC_H_
#include <asm/types.h> +#include <asm/barrier.h>
/** * __set_bit - Set a bit in memory @@ -105,4 +106,17 @@ static inline int test_bit(int nr, const return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); }
+/** + * arch_test_bit_acquire - Determine, with acquire semantics, whether a bit is set + * @nr: bit number to test + * @addr: Address to start counting from + */ +static __always_inline bool +arch_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} +#define test_bit_acquire arch_test_bit_acquire + #endif /* _ASM_GENERIC_BITOPS_NON_ATOMIC_H_ */ Index: linux-stable/include/linux/buffer_head.h =================================================================== --- linux-stable.orig/include/linux/buffer_head.h 2022-10-17 20:43:20.000000000 +0200 +++ linux-stable/include/linux/buffer_head.h 2022-10-17 20:43:20.000000000 +0200 @@ -162,7 +162,7 @@ static __always_inline int buffer_uptoda * make it consistent with folio_test_uptodate * pairs with smp_mb__before_atomic in set_buffer_uptodate */ - return (smp_load_acquire(&bh->b_state) & (1UL << BH_Uptodate)) != 0; + return test_bit_acquire(BH_Uptodate, &bh->b_state); }
#define bh_offset(bh) ((unsigned long)(bh)->b_data & ~PAGE_MASK) Index: linux-stable/include/linux/wait.h =================================================================== --- linux-stable.orig/include/linux/wait.h 2022-10-17 20:43:20.000000000 +0200 +++ linux-stable/include/linux/wait.h 2022-10-17 20:43:20.000000000 +0200 @@ -1066,7 +1066,7 @@ static inline int wait_on_bit(unsigned long *word, int bit, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, bit_wait, @@ -1091,7 +1091,7 @@ static inline int wait_on_bit_io(unsigned long *word, int bit, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, bit_wait_io, @@ -1118,7 +1118,7 @@ wait_on_bit_timeout(unsigned long *word, unsigned long timeout) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit_timeout(word, bit, bit_wait_timeout, @@ -1146,7 +1146,7 @@ wait_on_bit_action(unsigned long *word, unsigned mode) { might_sleep(); - if (!test_bit(bit, word)) + if (!test_bit_acquire(bit, word)) return 0; return out_of_line_wait_on_bit(word, bit, action, mode); } Index: linux-stable/kernel/sched/wait.c =================================================================== --- linux-stable.orig/kernel/sched/wait.c 2022-10-17 20:43:20.000000000 +0200 +++ linux-stable/kernel/sched/wait.c 2022-10-17 20:43:20.000000000 +0200 @@ -389,7 +389,7 @@ __wait_on_bit(wait_queue_head_t *wq, str prepare_to_wait(wq, &q->wait, mode); if (test_bit(q->key.bit_nr, q->key.flags)) ret = (*action)(&q->key, mode); - } while (test_bit(q->key.bit_nr, q->key.flags) && !ret); + } while (test_bit_acquire(q->key.bit_nr, q->key.flags) && !ret); finish_wait(wq, &q->wait); return ret; } Index: linux-stable/arch/alpha/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/alpha/include/asm/bitops.h 2022-10-17 20:43:20.000000000 +0200 +++ linux-stable/arch/alpha/include/asm/bitops.h 2022-10-17 20:43:20.000000000 +0200 @@ -288,6 +288,13 @@ test_bit(int nr, const volatile void * a return (1UL & (((const int *) addr)[nr >> 5] >> (nr & 31))) != 0UL; }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + /* * ffz = Find First Zero in word. Undefined if no zero exists, * so code should check against ~0UL first.. Index: linux-stable/arch/hexagon/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/hexagon/include/asm/bitops.h 2022-10-17 20:43:20.000000000 +0200 +++ linux-stable/arch/hexagon/include/asm/bitops.h 2022-10-17 20:43:20.000000000 +0200 @@ -186,7 +186,22 @@ static inline int __test_bit(int nr, con return retval; }
+static inline int __test_bit_acquire(int nr, const volatile unsigned long *addr) +{ + int retval; + + asm volatile( + "{P0 = tstbit(%1,%2); if (P0.new) %0 = #1; if (!P0.new) %0 = #0;}\n" + : "=&r" (retval) + : "r" (addr[BIT_WORD(nr)]), "r" (nr % BITS_PER_LONG) + : "p0", "memory" + ); + + return retval; +} + #define test_bit(nr, addr) __test_bit(nr, addr) +#define test_bit_acquire(nr, addr) __test_bit_acquire(nr, addr)
/* * ffz - find first zero in word. Index: linux-stable/arch/ia64/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/ia64/include/asm/bitops.h 2022-10-17 20:43:20.000000000 +0200 +++ linux-stable/arch/ia64/include/asm/bitops.h 2022-10-17 20:43:20.000000000 +0200 @@ -336,6 +336,13 @@ test_bit (int nr, const volatile void *a return 1 & (((const volatile __u32 *) addr)[nr >> 5] >> (nr & 31)); }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + /** * ffz - find the first zero bit in a long word * @x: The long word to find the bit in Index: linux-stable/arch/m68k/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/m68k/include/asm/bitops.h 2022-10-17 20:43:20.000000000 +0200 +++ linux-stable/arch/m68k/include/asm/bitops.h 2022-10-17 20:43:20.000000000 +0200 @@ -153,6 +153,12 @@ static inline int test_bit(int nr, const return (vaddr[nr >> 5] & (1UL << (nr & 31))) != 0; }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +}
static inline int bset_reg_test_and_set_bit(int nr, volatile unsigned long *vaddr) Index: linux-stable/arch/s390/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/s390/include/asm/bitops.h 2022-10-17 20:43:20.000000000 +0200 +++ linux-stable/arch/s390/include/asm/bitops.h 2022-10-17 20:43:20.000000000 +0200 @@ -270,6 +270,13 @@ static inline int test_bit(unsigned long return (*addr >> (nr & 7)) & 1; }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + static inline int test_and_set_bit_lock(unsigned long nr, volatile unsigned long *ptr) { Index: linux-stable/arch/sh/include/asm/bitops-op32.h =================================================================== --- linux-stable.orig/arch/sh/include/asm/bitops-op32.h 2022-10-17 20:43:20.000000000 +0200 +++ linux-stable/arch/sh/include/asm/bitops-op32.h 2022-10-17 20:43:20.000000000 +0200 @@ -139,4 +139,11 @@ static inline int test_bit(int nr, const return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + #endif /* __ASM_SH_BITOPS_OP32_H */ Index: linux-stable/arch/arc/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/arc/include/asm/bitops.h 2022-10-17 20:43:20.000000000 +0200 +++ linux-stable/arch/arc/include/asm/bitops.h 2022-10-17 20:43:20.000000000 +0200 @@ -254,6 +254,13 @@ test_bit(unsigned int nr, const volatile return ((mask & *addr) != 0); }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + #ifdef CONFIG_ISA_ARCOMPACT
/* Index: linux-stable/arch/h8300/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/h8300/include/asm/bitops.h 2022-10-17 20:43:20.000000000 +0200 +++ linux-stable/arch/h8300/include/asm/bitops.h 2022-10-17 20:43:20.000000000 +0200 @@ -88,7 +88,8 @@ static inline int test_bit(int nr, const return ret; }
-#define __test_bit(nr, addr) test_bit(nr, addr) +#define __test_bit(nr, addr) test_bit(nr, addr) +#define test_bit_acquire(nr, addr) test_bit(nr, addr)
#define H8300_GEN_TEST_BITOP(FNNAME, OP) \ static inline int FNNAME(int nr, void *addr) \ Index: linux-stable/arch/frv/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/frv/include/asm/bitops.h 2022-10-17 20:43:20.000000000 +0200 +++ linux-stable/arch/frv/include/asm/bitops.h 2022-10-17 20:43:20.000000000 +0200 @@ -156,6 +156,13 @@ static inline int __test_bit(unsigned lo __constant_test_bit((nr),(addr)) : \ __test_bit((nr),(addr)))
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + #include <asm-generic/bitops/find.h>
/** Index: linux-stable/arch/mn10300/include/asm/bitops.h =================================================================== --- linux-stable.orig/arch/mn10300/include/asm/bitops.h 2022-10-17 20:43:20.000000000 +0200 +++ linux-stable/arch/mn10300/include/asm/bitops.h 2022-10-17 20:43:20.000000000 +0200 @@ -73,6 +73,13 @@ static inline int test_bit(unsigned long return 1UL & (((const volatile unsigned int *) addr)[nr >> 5] >> (nr & 31)); }
+static __always_inline bool +test_bit_acquire(unsigned long nr, const volatile unsigned long *addr) +{ + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + return 1UL & (smp_load_acquire(p) >> (nr & (BITS_PER_LONG-1))); +} + /* * change bit */
On Tue, Oct 18, 2022 at 07:36:22AM -0400, Mikulas Patocka wrote:
On Tue, 11 Oct 2022, Greg KH wrote:
On Tue, Oct 11, 2022 at 05:48:26AM -0400, Mikulas Patocka wrote:
On Mon, 10 Oct 2022, Greg KH wrote:
Nope, these cause loads of breakages. See https://lore.kernel.org/r/09eca44e-4d91-a060-d48c-d0aa41ac5045@roeck-us.net for one such example, and I know kbuild sent you other build problems. I'll drop all of these from the stable trees now. Please feel free to resend them when you have the build issues worked out.
thanks,
greg k-h
I don't have cross compilers for all the architectures that Linux supports. Is there some way how to have the patch compile-tested before I send it to you?
You can download those compilers from kernel.org, they are all available there.
OK. I downloaded cross compilers from https://mirrors.edge.kernel.org/pub/tools/crosstool/ and compile-tested the patches with all possible architectures.
Here I'm sending new versions.
But don't you need 2 patches, not just 1, to be applied?
Please resend a set of series, one series per stable kernel branch, to make it more obvious what to do. Your thread here is very confusing.
See the stable mailing list archives for lots of examples of how to do this properly, here are 2 good examples: https://lore.kernel.org/r/20221019125303.2845522-1-conor.dooley@microchip.co... https://lore.kernel.org/r/20221019125209.2844943-1-conor.dooley@microchip.co...
thanks,
greg k-h
On Wed, 26 Oct 2022, Greg KH wrote:
On Tue, Oct 18, 2022 at 07:36:22AM -0400, Mikulas Patocka wrote:
On Tue, 11 Oct 2022, Greg KH wrote:
On Tue, Oct 11, 2022 at 05:48:26AM -0400, Mikulas Patocka wrote:
On Mon, 10 Oct 2022, Greg KH wrote:
Nope, these cause loads of breakages. See https://lore.kernel.org/r/09eca44e-4d91-a060-d48c-d0aa41ac5045@roeck-us.net for one such example, and I know kbuild sent you other build problems. I'll drop all of these from the stable trees now. Please feel free to resend them when you have the build issues worked out.
thanks,
greg k-h
I don't have cross compilers for all the architectures that Linux supports. Is there some way how to have the patch compile-tested before I send it to you?
You can download those compilers from kernel.org, they are all available there.
OK. I downloaded cross compilers from https://mirrors.edge.kernel.org/pub/tools/crosstool/ and compile-tested the patches with all possible architectures.
Here I'm sending new versions.
But don't you need 2 patches, not just 1, to be applied?
Just one patch is sufficient.
The upstream patch 8238b4579866b7c1bb99883cfe102a43db5506ff fixes a bug and the patch d6ffe6067a54972564552ea45d320fb98db1ac5e fixes compile failures triggered by 8238b4579866b7c1bb99883cfe102a43db5506ff on some architectures.
For simplicity of making and testing the stable branch patches I folded these changes into just one patch - that fixes the bug and fixes compile failures as well.
Please resend a set of series, one series per stable kernel branch, to make it more obvious what to do. Your thread here is very confusing.
I'll resend it, but except for the subject line I don't know what have I done wrong.
Mikulas
See the stable mailing list archives for lots of examples of how to do this properly, here are 2 good examples: https://lore.kernel.org/r/20221019125303.2845522-1-conor.dooley@microchip.co... https://lore.kernel.org/r/20221019125209.2844943-1-conor.dooley@microchip.co...
thanks,
greg k-h
On Thu, Oct 27, 2022 at 07:45:52AM -0400, Mikulas Patocka wrote:
On Wed, 26 Oct 2022, Greg KH wrote:
On Tue, Oct 18, 2022 at 07:36:22AM -0400, Mikulas Patocka wrote:
On Tue, 11 Oct 2022, Greg KH wrote:
On Tue, Oct 11, 2022 at 05:48:26AM -0400, Mikulas Patocka wrote:
On Mon, 10 Oct 2022, Greg KH wrote:
Nope, these cause loads of breakages. See https://lore.kernel.org/r/09eca44e-4d91-a060-d48c-d0aa41ac5045@roeck-us.net for one such example, and I know kbuild sent you other build problems. I'll drop all of these from the stable trees now. Please feel free to resend them when you have the build issues worked out.
thanks,
greg k-h
I don't have cross compilers for all the architectures that Linux supports. Is there some way how to have the patch compile-tested before I send it to you?
You can download those compilers from kernel.org, they are all available there.
OK. I downloaded cross compilers from https://mirrors.edge.kernel.org/pub/tools/crosstool/ and compile-tested the patches with all possible architectures.
Here I'm sending new versions.
But don't you need 2 patches, not just 1, to be applied?
Just one patch is sufficient.
The upstream patch 8238b4579866b7c1bb99883cfe102a43db5506ff fixes a bug and the patch d6ffe6067a54972564552ea45d320fb98db1ac5e fixes compile failures triggered by 8238b4579866b7c1bb99883cfe102a43db5506ff on some architectures.
For simplicity of making and testing the stable branch patches I folded these changes into just one patch - that fixes the bug and fixes compile failures as well.
No, please do not do that. We want both commits at once, not a "fixed up" change, right? Otherwise our tools will want to apply the second one as it is insisting that a fix is still needed.
Please resend a set of series, one series per stable kernel branch, to make it more obvious what to do. Your thread here is very confusing.
I'll resend it, but except for the subject line I don't know what have I done wrong.
Subject line is everything :)
As is the text in the body, I would have had to remove that from your last one. See the examples on the list for how to make this easy for us to apply.
thanks,
greg k-h
On Thu, 27 Oct 2022, Greg KH wrote:
For simplicity of making and testing the stable branch patches I folded these changes into just one patch - that fixes the bug and fixes compile failures as well.
No, please do not do that. We want both commits at once, not a "fixed up" change, right? Otherwise our tools will want to apply the second one as it is insisting that a fix is still needed.
OK - so I split the patches in two and resent them.
Mikulas
linux-stable-mirror@lists.linaro.org