Re: [RFC][PATCH 5/7] x86: convert arch_futex_atomic_op_inuser() to user_access_begin/user_access_end()

From: Al Viro
Date: Tue Mar 24 2020 - 16:42:58 EST


On Tue, Mar 24, 2020 at 09:19:15AM -0700, Linus Torvalds wrote:
> On Mon, Mar 23, 2020 at 7:08 PM Al Viro <viro@xxxxxxxxxxxxxxxxxx> wrote:
> >
> > > And wouldn't it be lovely to get rid of the error return thing, and
> > > pass in a label instead, the way "usafe_get/put_user()" works too?
> > > That might be a separate patch from the "reorg" thing, though.
> >
> > OK, ret wouldn't be in the list of outputs that way and
> > *uaddr could become an input (we only care about the address,
> > same as for put_user), but oldval is a genuine output -
>
> Yes, initially we'd have to do the "jump to label" inside the macro,
> because gcc doesn't support asm goto with outputs.
>
> But that's no different from "unsafe_get_user()". We still pass it a
> label, even though we can't use it in the inline asm.
>
> Yet.
>
> I have patches to make it work with newer versions of clang, and I
> hope that gcc will eventually also accept the semantics of "asm goto
> with outputs only has the output on the fallthrough".
>
> So _currently_ it would be only syntactic sugar: moving the error
> handling inside the macro, and making it syntactically match
> unsafe_get_user().
>
> But long term is would allow us to generate better code too.

OK... BTW, I'd been trying to recall the reasons for the way
__futex_atomic_op2() loop is done; ISTR some discussion along
the lines of cacheline ping-pong prevention, but I'd been unable
to reconstruct enough details to find it and I'm not sure it
hadn't been about some other code ;-/

What we have there (fault handling aside) is
loop: eax = *uaddr;
v = eax | oparg;
lock cmpxchg v, *uaddr
if (!zf)
goto loop;
oldval = eax;
Why do we bother with reload? That cmpxchg is, after all,
t = *uaddr;
zf = (t == eax);
*uaddr = zf ? v : t;
eax = t;
so what would be wrong with doing
eax = *uaddr;
loop: v = eax | oparg;
lock cmpxchg v, *uaddr
if (!zf)
goto loop;
oldval = eax;
instead?