Re: [RFC PATCH 4/6] mm: provide generic compat_sys_readahead() implementation

Linus Torvalds
2018-03-18T18:06:44Z

On Sun, Mar 18, 2018 at 10:40 AM, Al Viro <viro@zeniv.linux.org.uk> wrote:
>
> *UGH*
>
> static inline compat_to_u64(u32 w0, u32 w1)
> {
> #ifdef __BIG_ENDIAN
> return ((u64)w0 << 32) | w1;
> #else
> return ((u64)w1 << 32) | w0;
> #endif
> }
>
> in compat.h, then this turns into
>
> #ifdef __ARCH_WANT_COMPAT_SYS_WITH_PADDING
> COMPAT_SYSCALL_DEFINE5(readahead, int, fd, unsigned int, padding,
> u32, off0, u32 off1,
> compat_size_t, count)
> #else
> COMPAT_SYSCALL_DEFINE4(readahead, int, fd,
> u32, off0, u32 off1,
> compat_size_t, count)
> #endif

No. This is still too ugly to live.

What *may* be acceptable is if architectures defined something like this:

x86:

/* Little endian registers - low bits first, no padding for odd
register numbers necessary */
#define COMPAT_ARG_64BIT(x) unsigned int x##_lo, unsigned int x##_hi
#define COMPAT_ARG_64BIT_ODD(x) COMPAT_ARG_64BIT(x)

ppc BE:

/* Big-endian registers - high bits first, odd argument pairs
padded up to the next even register */
#define COMPAT_ARG_64BIT(x) unsigned int x##_hi, unsigned int x##_lo
#define COMPAT_ARG_64BIT_ODD(x) unsigned int x##_padding,
COMPAT_ARG_64BIT(x)

and then we can do

COMPAT_SYSCALL_DEFINE5(readahead, int, fd,
COMPAT_ARG_64BIT_ODD(off), compat_size_t, count)
{
return do_readahead(fd, off_lo + ((u64)off_hi << 64), count);
}

which at least looks reasonably legible, and has *zero* ifdef's anywhere.

I do *not* want to see those disgusting __ARCH_WANT_LE_COMPAT_SYS
things and crazy #ifdef's in code.

So either let the architectures do their own trivial wrappers
entirely, or do something clean like the above. Do *not* do
#ifdef'fery at the system call declaration time.

Also note that the "ODD" arguments may not be the ones that need
padding. I could easily see a system call argument numbering scheme
like

r0 - system call number
r1 - first argument
r2 - second argument
...

and then it's the *EVEN* 64-bit arguments that would need the padding
(because they are actually odd in the register numbers). The above
COMPAT_ARG_64BIT[_ODD]() model allows for that too.

Of course, if some architecture then has some other arbitrary rules (I
could see register pairing rules that aren't the usual "even register"
ones), then such an architecture would really have to have its own
wrapper, but the above at least would handle the simple cases, and
doesn't look disgusting to use.

Linus

PS. It is possible that we should then add a

#define COMPAT_ARG_64BIT_VAL(x) (x_##lo + ((u64)x_##hi << 32))

and then do

COMPAT_SYSCALL_DEFINE5(readahead, int, fd,
COMPAT_ARG_64BIT_ODD(off), compat_size_t, count)
{
return do_readahead(fd, COMPAT_ARG_64BIT_VAL(off), count);
}

because then we could perhaps generate the *non*compat system calls
this way too, just using

#define COMPAT_ARG_64BIT(x) unsigned long x
#define COMPAT_ARG_64BIT_VAL(x) (x)

instead (there might also be a "compat" mode that actually has access
to 64-bit registers, like x32 does, but I suspect it would have other
issues).