All of lore.kernel.org
 help / color / mirror / Atom feed
From: Al Viro <viro@zeniv.linux.org.uk>
To: Linus Torvalds <torvalds@linux-foundation.org>
Cc: linux-arch <linux-arch@vger.kernel.org>,
	Linux Kernel Mailing List <linux-kernel@vger.kernel.org>,
	Arnd Bergmann <arnd@arndb.de>
Subject: Re: [RFC] regset ->get() API
Date: Fri, 21 Feb 2020 03:30:16 +0000	[thread overview]
Message-ID: <20200221033016.GV23230@ZenIV.linux.org.uk> (raw)
In-Reply-To: <CAHk-=whdat=wfwKh5rF3MuCbTxhcFwaGqmdsCXXv=H=kDERTOw@mail.gmail.com>

On Thu, Feb 20, 2020 at 03:31:56PM -0800, Linus Torvalds wrote:
> On Thu, Feb 20, 2020 at 3:29 PM Al Viro <viro@zeniv.linux.org.uk> wrote:
> >
> > We do know that caller does not want more than the value it has passed in
> > 'size' argument, though.
> 
> Ok, fair enough. That's probably a good way to handle the "allocate in
> the caller".
> 
> So then I have no issues with that approach.

Turns out that "nobody uses those for userland destinations after that" is not
quite right - we have this:
int copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size)
{
        struct task_struct *tsk = current;
        int ia32_fxstate = (buf != buf_fx);
        int ret;

        ia32_fxstate &= (IS_ENABLED(CONFIG_X86_32) ||
                         IS_ENABLED(CONFIG_IA32_EMULATION));

        if (!access_ok(buf, size))
                return -EACCES;

        if (!static_cpu_has(X86_FEATURE_FPU))
                return fpregs_soft_get(current, NULL, 0,
                        sizeof(struct user_i387_ia32_struct), NULL,
                        (struct _fpstate_32 __user *) buf) ? -1 : 1;

... with fpregs_soft_get() behing the shared helper that does, in turn,
call user_regset_copyout().  OTOH, _that_ sure as hell is "fill local
variable, then copy_to_user()" case.

Sigh...  Wish we had a quick way to do something along the lines of
"find all callchains leading to <function> that would not come via
-><method>" - doing that manually stank to high heaven ;-/  And in
cases like that nothing along the lines of "simulate a build" is
practical - call chains are all over arch/*, and config-sensitive
as well (32bit vs. 64bit is only beginning of that fun).  Thankfully,
none of those involved token-pasting...

Anyway, one observation that came out of that is that we might
be better off with signature change done first; less boilerplate
that way, contrary to what I expected.

Alternatively, we could introduce a new method, with one-by-one
conversion to it.  Hmm...
	int (*get2)(struct task_struct *target,
		    const struct user_regset *regset,
		    struct membuf to);
returning -E... on error and amount left unfilled on success, perhaps?
That seems to generate decent code and is pretty easy on the instances,
especially if membuf_write() et.al. are made to return to->left...
Things like

static int evr_get(struct task_struct *target, const struct user_regset *regset,
                   struct membuf to)
{
        flush_spe_to_thread(target);

        membuf_write(&to, &target->thread.evr, sizeof(target->thread.evr));

        BUILD_BUG_ON(offsetof(struct thread_struct, acc) + sizeof(u64) !=
                     offsetof(struct thread_struct, spefscr));

        return membuf_write(&to, &target->thread.acc, sizeof(u64));
}

in place of current

static int evr_get(struct task_struct *target, const struct user_regset *regset,
                   unsigned int pos, unsigned int count,
                   void *kbuf, void __user *ubuf)
{
        int ret;

        flush_spe_to_thread(target);

        ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
                                  &target->thread.evr,
                                  0, sizeof(target->thread.evr));

        BUILD_BUG_ON(offsetof(struct thread_struct, acc) + sizeof(u64) !=
                     offsetof(struct thread_struct, spefscr));

        if (!ret)
                ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
                                          &target->thread.acc,
                                          sizeof(target->thread.evr), -1);

        return ret;
}

and

static int vr_get(struct task_struct *target, const struct user_regset *regset,
                  struct membuf to)
{
	union {
		elf_vrreg_t reg;
		u32 word;
	} vrsave;

        flush_altivec_to_thread(target);

        BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
                     offsetof(struct thread_vr_state, vr[32]));

        membuf_write(&to, &target->thread.vr_state, 33 * sizeof(vector128));
	/*
	 * Copy out only the low-order word of vrsave.
	 */
	memset(&vrsave, 0, sizeof(vrsave));
	vrsave.word = target->thread.vrsave;

	return membuf_write(&to, &vrsave, sizeof(vrsave);
}

instead of

static int vr_get(struct task_struct *target, const struct user_regset *regset,
                  unsigned int pos, unsigned int count,
                  void *kbuf, void __user *ubuf)
{
        int ret;

        flush_altivec_to_thread(target);

        BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
                     offsetof(struct thread_vr_state, vr[32]));

        ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
                                  &target->thread.vr_state, 0,
                                  33 * sizeof(vector128));
        if (!ret) {
                /*
                 * Copy out only the low-order word of vrsave.
                 */
                int start, end;
                union {
                        elf_vrreg_t reg;
                        u32 word;
                } vrsave;
                memset(&vrsave, 0, sizeof(vrsave));

                vrsave.word = target->thread.vrsave;

                start = 33 * sizeof(vector128);
                end = start + sizeof(vrsave);
                ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &vrsave,
                                          start, end);
        }

        return ret;
}

  reply	other threads:[~2020-02-21  3:30 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-02-17 18:33 [RFC] regset ->get() API Al Viro
2020-02-19 20:01 ` Linus Torvalds
2020-02-20 22:47   ` Al Viro
2020-02-20 22:56     ` Linus Torvalds
2020-02-20 23:29       ` Al Viro
2020-02-20 23:31         ` Linus Torvalds
2020-02-21  3:30           ` Al Viro [this message]
2020-02-21 18:59             ` Al Viro
2020-02-21 19:22               ` David Miller
2020-02-22  0:41                 ` Al Viro
2020-04-13  4:32                   ` David Miller

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200221033016.GV23230@ZenIV.linux.org.uk \
    --to=viro@zeniv.linux.org.uk \
    --cc=arnd@arndb.de \
    --cc=linux-arch@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=torvalds@linux-foundation.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.