Re: [PATCH] block: switch to atomic_t for request references
From: Peter Zijlstra <peterz@infradead.org>
Date: 2021-12-07 16:52:21
Also in:
lkml
Subsystem:
atomic infrastructure, the rest, x86 architecture (32-bit and 64-bit) · Maintainers:
Will Deacon, Peter Zijlstra, Boqun Feng, Linus Torvalds, Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen
On Tue, Dec 07, 2021 at 08:13:38AM -0800, Linus Torvalds wrote:
On Tue, Dec 7, 2021 at 5:28 AM Peter Zijlstra [off-list ref] wrote:quoted
+#define refcount_dec_and_test refcount_dec_and_test +static inline bool refcount_dec_and_test(refcount_t *r) +{ + asm_volatile_goto (LOCK_PREFIX "decl %[var]\n\t" + "jz %l[cc_zero]\n\t" + "jl %l[cc_error]" + : : [var] "m" (r->refs.counter) + : "memory" + : cc_zero, cc_error); + return false; + +cc_zero: + return true; + +cc_error: + refcount_warn_saturate(r, REFCOUNT_SUB_UAF); + return false; +}Please don't add broken arch-specific helpers that are useless for anything else than the broken refcount_t use.
I take issue with the broken, but I concede the point.
Make it return three return values, call it atomic_dec_and_test_ref() or something like that, and now people can use it without having to use a refcount_t. Nobody really wants two different error cases anyway. The fact that refcount_warn_saturate() has different cases is only an annoyance.
How about we do something like the unsafe_ uaccess functions and do it like so? It's a bit gross, and there seems to be a problem with macro expansion of __ofl, but it 'works'. ---
diff --git a/arch/x86/include/asm/atomic.h b/arch/x86/include/asm/atomic.h
index 5e754e895767..921ecfd5a40b 100644
--- a/arch/x86/include/asm/atomic.h
+++ b/arch/x86/include/asm/atomic.h@@ -263,6 +263,22 @@ static __always_inline int arch_atomic_fetch_xor(int i, atomic_t *v) } #define arch_atomic_fetch_xor arch_atomic_fetch_xor +#define atomic_dec_and_test_ofl(_v, __ofl) \ +({ \ + __label__ __zero; \ + __label__ __out; \ + bool __ret = false; \ + asm_volatile_goto (LOCK_PREFIX "decl %[var]\n\t" \ + "jz %l[__zero]\n\t" \ + "jl %l[__ofl]" \ + : : [var] "m" ((_v)->counter) \ + : "memory" \ + : __zero, __ofl); \ + goto __out; \ +__zero: __ret = true; \ +__out: __ret; \ +}) + #ifdef CONFIG_X86_32 # include <asm/atomic64_32.h> #else
diff --git a/include/linux/refcount.h b/include/linux/refcount.h
index b8a6e387f8f9..f11ce70de2da 100644
--- a/include/linux/refcount.h
+++ b/include/linux/refcount.h@@ -330,7 +330,15 @@ static inline __must_check bool __refcount_dec_and_test(refcount_t *r, int *oldp */ static inline __must_check bool refcount_dec_and_test(refcount_t *r) { +#ifdef atomic_dec_and_test_ofl + return atomic_dec_and_test_ofl(&r->refs, __ofl); + +__ofl: + refcount_warn_saturate(r, REFCOUNT_SUB_UAF); + return false; +#else return __refcount_dec_and_test(r, NULL); +#endif } static inline void __refcount_dec(refcount_t *r, int *oldp)