Skip to content

Commit 415d832

Browse files
marcantorvalds
authored andcommitted
locking/atomic: Make test_and_*_bit() ordered on failure
These operations are documented as always ordered in include/asm-generic/bitops/instrumented-atomic.h, and producer-consumer type use cases where one side needs to ensure a flag is left pending after some shared data was updated rely on this ordering, even in the failure case. This is the case with the workqueue code, which currently suffers from a reproducible ordering violation on Apple M1 platforms (which are notoriously out-of-order) that ends up causing the TTY layer to fail to deliver data to userspace properly under the right conditions. This change fixes that bug. Change the documentation to restrict the "no order on failure" story to the _lock() variant (for which it makes sense), and remove the early-exit from the generic implementation, which is what causes the missing barrier semantics in that case. Without this, the remaining atomic op is fully ordered (including on ARM64 LSE, as of recent versions of the architecture spec). Suggested-by: Linus Torvalds <[email protected]> Cc: [email protected] Fixes: e986a0d ("locking/atomics, asm-generic/bitops/atomic.h: Rewrite using atomic_*() APIs") Fixes: 61e0239 ("locking/atomic/bitops: Document and clarify ordering semantics for failed test_and_{}_bit()") Signed-off-by: Hector Martin <[email protected]> Acked-by: Will Deacon <[email protected]> Reviewed-by: Arnd Bergmann <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 568035b commit 415d832

File tree

2 files changed

+1
-7
lines changed

2 files changed

+1
-7
lines changed

Documentation/atomic_bitops.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ Like with atomic_t, the rule of thumb is:
5959
- RMW operations that have a return value are fully ordered.
6060

6161
- RMW operations that are conditional are unordered on FAILURE,
62-
otherwise the above rules apply. In the case of test_and_{}_bit() operations,
62+
otherwise the above rules apply. In the case of test_and_set_bit_lock(),
6363
if the bit in memory is unchanged by the operation then it is deemed to have
6464
failed.
6565

include/asm-generic/bitops/atomic.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,6 @@ arch_test_and_set_bit(unsigned int nr, volatile unsigned long *p)
3939
unsigned long mask = BIT_MASK(nr);
4040

4141
p += BIT_WORD(nr);
42-
if (READ_ONCE(*p) & mask)
43-
return 1;
44-
4542
old = arch_atomic_long_fetch_or(mask, (atomic_long_t *)p);
4643
return !!(old & mask);
4744
}
@@ -53,9 +50,6 @@ arch_test_and_clear_bit(unsigned int nr, volatile unsigned long *p)
5350
unsigned long mask = BIT_MASK(nr);
5451

5552
p += BIT_WORD(nr);
56-
if (!(READ_ONCE(*p) & mask))
57-
return 0;
58-
5953
old = arch_atomic_long_fetch_andnot(mask, (atomic_long_t *)p);
6054
return !!(old & mask);
6155
}

0 commit comments

Comments
 (0)