linux-um archives
 help / color / mirror / Atom feed
* [uml-devel] Subject: [PATCH 11/91] um: series of __get_user() is costly in sigframe handling
@ 2011-08-18 19:00 Al Viro
  0 siblings, 0 replies; only message in thread
From: Al Viro @ 2011-08-18 19:00 UTC (permalink / raw)
  To: richard; +Cc: linux-kernel, user-mode-linux-devel


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>
---
 arch/um/sys-i386/signal.c   |   48 ++++++++---------
 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(&regs->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 = &current->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 = &current->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;
 
-- 
1.7.2.5



------------------------------------------------------------------------------
Get a FREE DOWNLOAD! and learn more about uberSVN rich system, 
user administration capabilities and model configuration. Take 
the hassle out of deploying and managing Subversion and the 
tools developers use with it. http://p.sf.net/sfu/wandisco-d2d-2
_______________________________________________
User-mode-linux-devel mailing list
User-mode-linux-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/user-mode-linux-devel


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2011-08-18 19:00 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-08-18 19:00 [uml-devel] Subject: [PATCH 11/91] um: series of __get_user() is costly in sigframe handling Al Viro

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox