Re: [PATCH net-next] vhost: use "checked" versions of get_user() and put_user()

Linus Torvalds
2025-11-14T17:48:22Z

On Fri, 14 Nov 2025 at 06:53, Jon Kohler <jon@nutanix.com> wrote:
>
> > On Nov 12, 2025, at 8:09 PM, Jason Wang <jasowang@redhat.com> wrote:
> >
> > It has been used even before this commit.
>
> Ah, thanks for the pointer. I’d have to go dig to find its genesis, but
> its more to say, this existed prior to the LFENCE commit.

It might still be worth pointing out that the LFENCE is what made
__get_user() and friends much slower, but the *real* issue is that
__get_user() and friends became *pointless* before that due to SMAP.

Because the whole - and only - point of the __get_user() interface is
the historical issue of "it translates to a single load instruction
and gets inlined".

So back in the dark ages before SMAP, a regular "get_user()" was a
function call and maybe six instructions worth over code. But a
"__get_user()" was inlined to be a single instruction, and the
difference between the two was quite noticeable if you did things in a
loop.

End result: we have a number of old historic __get_user() calls
because people cared and it was noticeable.

But then SMAP happens, and user space accesses aren't just a simple
single load instruction, but a "enable user space access, do the
access, then disable user space accesses" for safety and robustness
reasons.

That's actually true on non-x86 architectures too: on arm64 you also
have TTBR0_PAN, and user space accesses can be quite the mess of
instructions.

And in that whole change, now __get_user() is not only no longer
inlined, the performance advantage isn't relevant any more. Sure, it
still avoided the user address space range check, but that check just
is no longer relevant. It's a couple of (very cheap) instructions, but
the big reason to use __get_user() has simply gone away. The real
costs of user space accesses are elsewhere, and __get_user() and
get_user() are basically the same performance in reality.

But the historical uses of __get_user() remain, even though now they
are pretty much pointless.

Then LFENCE comes around due to the whole speculation issue, and
initially __get_user() and get_user() *both* get it, and it only
reinforces the whole "the address check is not the most expensive part
of the operation" thing, but __get_user() is still technically a cycle
or two faster.

But then get_user() gets optimized to do the address space check using
a data dependency instead of the "access_ok()" control dependency, and
so get_user() doesn't need LFENCE at all, and now get_user() is
*faster* than __get_user().

End result: __get_user() has been a historical artifact for a long
time. It's been discouraged because it's pointless. But with the
LFENCE it's not only pointless, it's actively detrimental not just for
safety but even for performance.

So __get_user() should die. The LFENCE is not the primary reason it
should be retired, it's only the last nail in the coffin.

Linus