Re: [PATCH] block: switch to atomic_t for request references

Peter Zijlstra
2021-12-07T16:52:21Z

On Tue, Dec 07, 2021 at 08:13:38AM -0800, Linus Torvalds wrote:
> On Tue, Dec 7, 2021 at 5:28 AM Peter Zijlstra <peterz@infradead.org> wrote:
> >
> > +#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)