diff options
author | Al Viro <viro@ftp.linux.org.uk> | 2011-08-18 20:00:49 +0100 |
---|---|---|
committer | Richard Weinberger <richard@nod.at> | 2011-11-02 14:14:42 +0100 |
commit | a955bd611d6426bf7b61cab01f8ddee9cc169736 (patch) | |
tree | f2f42f996bbb757e6f8ebd805fe1e975893dcc32 | |
parent | 3d72210bdc1ef67b72ffbd3e74873cae7287f2c6 (diff) | |
download | op-kernel-dev-a955bd611d6426bf7b61cab01f8ddee9cc169736.zip op-kernel-dev-a955bd611d6426bf7b61cab01f8ddee9cc169736.tar.gz |
um: series of __get_user() is costly in sigframe handling
It's not x86, where __get_user() is a single dereference; here it's
a single ptrace(2) call in host, which obviously costs a lot more.
IOW, it's cheaper to do copy_{to,from}_user() once than bother with
fields one by one...
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Richard Weinberger <richard@nod.at>
-rw-r--r-- | arch/um/sys-i386/signal.c | 48 | ||||
-rw-r--r-- | arch/um/sys-x86_64/signal.c | 118 |
2 files changed, 80 insertions, 86 deletions
diff --git a/arch/um/sys-i386/signal.c b/arch/um/sys-i386/signal.c index b87195b..bcbfb0d 100644 --- a/arch/um/sys-i386/signal.c +++ b/arch/um/sys-i386/signal.c @@ -10,28 +10,6 @@ #include "frame_kern.h" #include "skas.h" -static void copy_sc(struct uml_pt_regs *regs, void *from) -{ - struct sigcontext *sc = from; - - REGS_GS(regs->gp) = sc->gs; - REGS_FS(regs->gp) = sc->fs; - REGS_ES(regs->gp) = sc->es; - REGS_DS(regs->gp) = sc->ds; - REGS_EDI(regs->gp) = sc->di; - REGS_ESI(regs->gp) = sc->si; - REGS_EBP(regs->gp) = sc->bp; - REGS_SP(regs->gp) = sc->sp; - REGS_EBX(regs->gp) = sc->bx; - REGS_EDX(regs->gp) = sc->dx; - REGS_ECX(regs->gp) = sc->cx; - REGS_EAX(regs->gp) = sc->ax; - REGS_IP(regs->gp) = sc->ip; - REGS_CS(regs->gp) = sc->cs; - REGS_EFLAGS(regs->gp) = sc->flags; - REGS_SS(regs->gp) = sc->ss; -} - /* * FPU tag word conversions. */ @@ -175,7 +153,27 @@ static int copy_sc_from_user(struct pt_regs *regs, return err; pid = userspace_pid[current_thread_info()->cpu]; - copy_sc(®s->regs, &sc); + +#define GETREG(regno, regname) regs->regs.gp[HOST_##regno] = sc.regname + + GETREG(GS, gs); + GETREG(FS, fs); + GETREG(ES, es); + GETREG(DS, ds); + GETREG(EDI, di); + GETREG(ESI, si); + GETREG(EBP, bp); + GETREG(SP, sp); + GETREG(EBX, bx); + GETREG(EDX, dx); + GETREG(ECX, cx); + GETREG(EAX, ax); + GETREG(IP, ip); + GETREG(CS, cs); + GETREG(EFLAGS, flags); + GETREG(SS, ss); + +#undef GETREG if (have_fpx_regs) { struct user_fxsr_struct fpx; @@ -196,8 +194,7 @@ static int copy_sc_from_user(struct pt_regs *regs, -err); return 1; } - } - else { + } else { struct user_i387_struct fp; err = copy_from_user(&fp, sc.fpstate, @@ -224,6 +221,7 @@ static int copy_sc_to_user(struct sigcontext __user *to, struct sigcontext sc; struct faultinfo * fi = ¤t->thread.arch.faultinfo; int err, pid; + memset(&sc, 0, sizeof(struct sigcontext)); sc.gs = REGS_GS(regs->regs.gp); sc.fs = REGS_FS(regs->regs.gp); diff --git a/arch/um/sys-x86_64/signal.c b/arch/um/sys-x86_64/signal.c index 61ad980..255b2ca 100644 --- a/arch/um/sys-x86_64/signal.c +++ b/arch/um/sys-x86_64/signal.c @@ -16,41 +16,39 @@ static int copy_sc_from_user(struct pt_regs *regs, struct sigcontext __user *from) { + struct sigcontext sc; struct user_i387_struct fp; void __user *buf; - int err = 0; + int err; -#define GETREG(regs, regno, sc, regname) \ - __get_user((regs)->regs.gp[(regno) / sizeof(unsigned long)], \ - &(sc)->regname) - - err |= GETREG(regs, R8, from, r8); - err |= GETREG(regs, R9, from, r9); - err |= GETREG(regs, R10, from, r10); - err |= GETREG(regs, R11, from, r11); - err |= GETREG(regs, R12, from, r12); - err |= GETREG(regs, R13, from, r13); - err |= GETREG(regs, R14, from, r14); - err |= GETREG(regs, R15, from, r15); - err |= GETREG(regs, RDI, from, di); - err |= GETREG(regs, RSI, from, si); - err |= GETREG(regs, RBP, from, bp); - err |= GETREG(regs, RBX, from, bx); - err |= GETREG(regs, RDX, from, dx); - err |= GETREG(regs, RAX, from, ax); - err |= GETREG(regs, RCX, from, cx); - err |= GETREG(regs, RSP, from, sp); - err |= GETREG(regs, RIP, from, ip); - err |= GETREG(regs, EFLAGS, from, flags); - err |= GETREG(regs, CS, from, cs); + err = copy_from_user(&sc, from, sizeof(sc)); if (err) - return 1; - + return err; + +#define GETREG(regno, regname) regs->regs.gp[HOST_##regno] = sc.regname + + GETREG(R8, r8); + GETREG(R9, r9); + GETREG(R10, r10); + GETREG(R11, r11); + GETREG(R12, r12); + GETREG(R13, r13); + GETREG(R14, r14); + GETREG(R15, r15); + GETREG(RDI, di); + GETREG(RSI, si); + GETREG(RBP, bp); + GETREG(RBX, bx); + GETREG(RDX, dx); + GETREG(RAX, ax); + GETREG(RCX, cx); + GETREG(SP, sp); + GETREG(IP, ip); + GETREG(EFLAGS, flags); + GETREG(CS, cs); #undef GETREG - err = __get_user(buf, &from->fpstate); - if (err) - return 1; + buf = sc.fpstate; err = copy_from_user(&fp, buf, sizeof(struct user_i387_struct)); if (err) @@ -73,48 +71,46 @@ static int copy_sc_to_user(struct sigcontext __user *to, unsigned long mask, unsigned long sp) { struct faultinfo * fi = ¤t->thread.arch.faultinfo; + struct sigcontext sc; struct user_i387_struct fp; int err = 0; + memset(&sc, 0, sizeof(struct sigcontext)); - err |= __put_user(0, &to->gs); - err |= __put_user(0, &to->fs); - -#define PUTREG(regs, regno, sc, regname) \ - __put_user((regs)->regs.gp[(regno) / sizeof(unsigned long)], \ - &(sc)->regname) +#define PUTREG(regno, regname) sc.regname = regs->regs.gp[HOST_##regno] - err |= PUTREG(regs, RDI, to, di); - err |= PUTREG(regs, RSI, to, si); - err |= PUTREG(regs, RBP, to, bp); + PUTREG(RDI, di); + PUTREG(RSI, si); + PUTREG(RBP, bp); /* * Must use original RSP, which is passed in, rather than what's in - * the pt_regs, because that's already been updated to point at the * signal frame. */ - err |= __put_user(sp, &to->sp); - err |= PUTREG(regs, RBX, to, bx); - err |= PUTREG(regs, RDX, to, dx); - err |= PUTREG(regs, RCX, to, cx); - err |= PUTREG(regs, RAX, to, ax); - err |= PUTREG(regs, R8, to, r8); - err |= PUTREG(regs, R9, to, r9); - err |= PUTREG(regs, R10, to, r10); - err |= PUTREG(regs, R11, to, r11); - err |= PUTREG(regs, R12, to, r12); - err |= PUTREG(regs, R13, to, r13); - err |= PUTREG(regs, R14, to, r14); - err |= PUTREG(regs, R15, to, r15); - err |= PUTREG(regs, CS, to, cs); /* XXX x86_64 doesn't do this */ - - err |= __put_user(fi->cr2, &to->cr2); - err |= __put_user(fi->error_code, &to->err); - err |= __put_user(fi->trap_no, &to->trapno); - - err |= PUTREG(regs, RIP, to, ip); - err |= PUTREG(regs, EFLAGS, to, flags); + sc.sp = sp; + PUTREG(RBX, bx); + PUTREG(RDX, dx); + PUTREG(RCX, cx); + PUTREG(RAX, ax); + PUTREG(R8, r8); + PUTREG(R9, r9); + PUTREG(R10, r10); + PUTREG(R11, r11); + PUTREG(R12, r12); + PUTREG(R13, r13); + PUTREG(R14, r14); + PUTREG(R15, r15); + PUTREG(CS, cs); /* XXX x86_64 doesn't do this */ + + sc.cr2 = fi->cr2; + sc.err = fi->error_code; + sc.trapno = fi->trap_no; + + PUTREG(IP, ip); + PUTREG(EFLAGS, flags); #undef PUTREG - err |= __put_user(mask, &to->oldmask); + sc.oldmask = mask; + + err = copy_to_user(to, &sc, sizeof(struct sigcontext)); if (err) return 1; |