Re: [PATCH 1/5] Split wait_noreap_copyout()

Ingo Molnar
2009-05-11T12:18:55Z

* Christoph Hellwig <hch@infradead.org> wrote:

> On Mon, May 11, 2009 at 12:12:40PM +0200, Vitaly Mayatskikh wrote:
> > +static int wait_copyout(struct wait_opts *wo, struct task_struct *p,
> > + pid_t pid, uid_t uid, int why, int status, int signal)
> > {
> > - struct siginfo __user *infop;
> > + struct siginfo __user *infop = wo->wo_info;
> > int retval = wo->wo_rusage
> > ? getrusage(p, RUSAGE_BOTH, wo->wo_rusage) : 0;
> >
> > + if (!retval && infop) {
> > + retval = put_user(signal, &infop->si_signo);
> > + if (!retval)
> > + retval = put_user(0, &infop->si_errno);
> > + if (!retval)
> > + retval = put_user((short)why, &infop->si_code);
> > + if (!retval)
> > + retval = put_user(pid, &infop->si_pid);
> > + if (!retval)
> > + retval = put_user(uid, &infop->si_uid);
> > + if (!retval)
> > + retval = put_user(status, &infop->si_status);
> > + }
> > + return retval;
>
> wouldn't this better be written as:
>
> static int wait_copyout(struct wait_opts *wo, struct task_struct *p,
> pid_t pid, uid_t uid, int why, int status, int signal)
> {
> struct siginfo __user *infop = wo->wo_info;
>
> if (wo->wo_rusage) {
> int retval = getrusage(p, RUSAGE_BOTH, wo->wo_rusage);
> if (retval)
> return retval;
> }
>
> if (!infop)
> return 0;
>
> if (put_user(signal, &infop->si_signo) ||
> put_user(0, &infop->si_errno) ||
> put_user((short)why, &infop->si_code) ||
> put_user(pid, &infop->si_pid) ||
> put_user(uid, &infop->si_uid) ||
> put_user(status, &infop->si_status))
> return -EFAULT;

For best assembly code this should generally be written as a series
of:

__uaccess_err |= __put_user(x, ptr);
__uaccess_err |= __put_user(y, ptr);
__uaccess_err |= __put_user(z, ptr);

As this generates non-dependent, compressed, branch-less code.

See the (new) put_user_try / put_user_ex() / put_user_catch()
abstraction in arch/x86/include/asm/uaccess.h, and how all the x86
signal code makes use of that to optimize such patterns of per field
user copies.

Ingo