Re: get_user()

Linus Torvalds (
Mon, 28 Oct 1996 21:27:20 +0200 (EET)

On Sun, 20 Oct 1996, Kai Schulte wrote:
> Is getting rid of all the get_fs_...() macros really an improvement?

Note that when it comes to the "get_fs_xxx()" and "put_fs_xxx()", the new
setup just changes the names of those to something saner. The old names were
really very implementation-specific, and only made sense on an x86 as long as
we really used the %fs segment register for user space access.

So there is really two issues here:
- changing the name to something saner
- getting "automatic" validity checking (ie getting rid of "verify_area()")

The name change actually started even before Linux-1.2, I just made it final
now (so that the old names don't exist any more: they used to exist in
parallell with the new ones).

So don't think of the change as "getting rid of get_fs...()", think of it as
"renaming get_fs..() and getting rid of verify_area()".

> I don't know whether the get_user() macro really hides any ugliness, because
> 1. you have to be aware of the fact that it's a macro because it alters one
> of its parameters and

Yes. I'd _love_ to have more of a function-call interface, but I didn't find
any way to do that efficiently. The problem withg get_user() is that it
really needs to return two values: the error return and the actual value
it got from user space. Now, the "normal" way to handle this in C is to
do something like

error = get_user(&val, address);

but sadly that is rather inefficient (it adds two memory accesses: the store
and the load to access the value, but more importantly it makes it much
harder for gcc to optimize due to the damn C pointer-aliasing problem).

So I decided I had to make it a macro that returns a value and sets the first
argument, and no, I don't like it. It's ugly, and it also makes for a rather
complicated implementation of the macro (especially as we still want to allow
side effects in the address: stuff like "p++" etc).

On x86, we could have returned two return variables in a structure, but on
other architectures the structure return approach will just result in
allocating memory on the stack. With this kind of macro the different
architectures can pretty much decide what they want to do about this all, and
it should map reasonably well into inline __asm__ which is what most (all?)
architectures will use.

> 2. you _should_ probably remain aware that performance may be
> type-dependent.
> Or are there other aspects that are more important?

There is one all-important reason why we hide all the type information, and
let the macro take care of it automatically.

Type portability.

For example, "uid_t" is a "short" in x86, and a "int" on alpha. So when
there is something that wants to store a uid_t into user space, the old
code would have had to do something like this:

#ifdef uid_is_short
put_fs_short(uid, uid_ptr);
put_fs_int(uid, uid_ptr);

Contrast this to the current code:

put_user(uid, uid_ptr);

which automatically does the right thing by looking at the "sizeof(*uid_ptr)".

So the complexity in the access macros is certainly needed. The actual macro
definitions look ugly, and I can't say I enjoy writing them, but at least all
the complexity and ugliness is hidden in a few machine-specific header files,
and using the macros shouldn't be too hard.