diff options
author | Al Viro <viro@ftp.linux.org.uk> | 2011-08-18 15:00:49 -0400 |
---|---|---|
committer | Richard Weinberger <richard@nod.at> | 2011-11-02 09:14:42 -0400 |
commit | a955bd611d6426bf7b61cab01f8ddee9cc169736 (patch) | |
tree | f2f42f996bbb757e6f8ebd805fe1e975893dcc32 | |
parent | 3d72210bdc1ef67b72ffbd3e74873cae7287f2c6 (diff) |
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 b87195b92fcc..bcbfb0d64813 100644 --- a/arch/um/sys-i386/signal.c +++ b/arch/um/sys-i386/signal.c | |||
@@ -10,28 +10,6 @@ | |||
10 | #include "frame_kern.h" | 10 | #include "frame_kern.h" |
11 | #include "skas.h" | 11 | #include "skas.h" |
12 | 12 | ||
13 | static void copy_sc(struct uml_pt_regs *regs, void *from) | ||
14 | { | ||
15 | struct sigcontext *sc = from; | ||
16 | |||
17 | REGS_GS(regs->gp) = sc->gs; | ||
18 | REGS_FS(regs->gp) = sc->fs; | ||
19 | REGS_ES(regs->gp) = sc->es; | ||
20 | REGS_DS(regs->gp) = sc->ds; | ||
21 | REGS_EDI(regs->gp) = sc->di; | ||
22 | REGS_ESI(regs->gp) = sc->si; | ||
23 | REGS_EBP(regs->gp) = sc->bp; | ||
24 | REGS_SP(regs->gp) = sc->sp; | ||
25 | REGS_EBX(regs->gp) = sc->bx; | ||
26 | REGS_EDX(regs->gp) = sc->dx; | ||
27 | REGS_ECX(regs->gp) = sc->cx; | ||
28 | REGS_EAX(regs->gp) = sc->ax; | ||
29 | REGS_IP(regs->gp) = sc->ip; | ||
30 | REGS_CS(regs->gp) = sc->cs; | ||
31 | REGS_EFLAGS(regs->gp) = sc->flags; | ||
32 | REGS_SS(regs->gp) = sc->ss; | ||
33 | } | ||
34 | |||
35 | /* | 13 | /* |
36 | * FPU tag word conversions. | 14 | * FPU tag word conversions. |
37 | */ | 15 | */ |
@@ -175,7 +153,27 @@ static int copy_sc_from_user(struct pt_regs *regs, | |||
175 | return err; | 153 | return err; |
176 | 154 | ||
177 | pid = userspace_pid[current_thread_info()->cpu]; | 155 | pid = userspace_pid[current_thread_info()->cpu]; |
178 | copy_sc(®s->regs, &sc); | 156 | |
157 | #define GETREG(regno, regname) regs->regs.gp[HOST_##regno] = sc.regname | ||
158 | |||
159 | GETREG(GS, gs); | ||
160 | GETREG(FS, fs); | ||
161 | GETREG(ES, es); | ||
162 | GETREG(DS, ds); | ||
163 | GETREG(EDI, di); | ||
164 | GETREG(ESI, si); | ||
165 | GETREG(EBP, bp); | ||
166 | GETREG(SP, sp); | ||
167 | GETREG(EBX, bx); | ||
168 | GETREG(EDX, dx); | ||
169 | GETREG(ECX, cx); | ||
170 | GETREG(EAX, ax); | ||
171 | GETREG(IP, ip); | ||
172 | GETREG(CS, cs); | ||
173 | GETREG(EFLAGS, flags); | ||
174 | GETREG(SS, ss); | ||
175 | |||
176 | #undef GETREG | ||
179 | if (have_fpx_regs) { | 177 | if (have_fpx_regs) { |
180 | struct user_fxsr_struct fpx; | 178 | struct user_fxsr_struct fpx; |
181 | 179 | ||
@@ -196,8 +194,7 @@ static int copy_sc_from_user(struct pt_regs *regs, | |||
196 | -err); | 194 | -err); |
197 | return 1; | 195 | return 1; |
198 | } | 196 | } |
199 | } | 197 | } else { |
200 | else { | ||
201 | struct user_i387_struct fp; | 198 | struct user_i387_struct fp; |
202 | 199 | ||
203 | err = copy_from_user(&fp, sc.fpstate, | 200 | err = copy_from_user(&fp, sc.fpstate, |
@@ -224,6 +221,7 @@ static int copy_sc_to_user(struct sigcontext __user *to, | |||
224 | struct sigcontext sc; | 221 | struct sigcontext sc; |
225 | struct faultinfo * fi = ¤t->thread.arch.faultinfo; | 222 | struct faultinfo * fi = ¤t->thread.arch.faultinfo; |
226 | int err, pid; | 223 | int err, pid; |
224 | memset(&sc, 0, sizeof(struct sigcontext)); | ||
227 | 225 | ||
228 | sc.gs = REGS_GS(regs->regs.gp); | 226 | sc.gs = REGS_GS(regs->regs.gp); |
229 | sc.fs = REGS_FS(regs->regs.gp); | 227 | 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 61ad980890c7..255b2ca0ce67 100644 --- a/arch/um/sys-x86_64/signal.c +++ b/arch/um/sys-x86_64/signal.c | |||
@@ -16,41 +16,39 @@ | |||
16 | static int copy_sc_from_user(struct pt_regs *regs, | 16 | static int copy_sc_from_user(struct pt_regs *regs, |
17 | struct sigcontext __user *from) | 17 | struct sigcontext __user *from) |
18 | { | 18 | { |
19 | struct sigcontext sc; | ||
19 | struct user_i387_struct fp; | 20 | struct user_i387_struct fp; |
20 | void __user *buf; | 21 | void __user *buf; |
21 | int err = 0; | 22 | int err; |
22 | 23 | ||
23 | #define GETREG(regs, regno, sc, regname) \ | 24 | err = copy_from_user(&sc, from, sizeof(sc)); |
24 | __get_user((regs)->regs.gp[(regno) / sizeof(unsigned long)], \ | ||
25 | &(sc)->regname) | ||
26 | |||
27 | err |= GETREG(regs, R8, from, r8); | ||
28 | err |= GETREG(regs, R9, from, r9); | ||
29 | err |= GETREG(regs, R10, from, r10); | ||
30 | err |= GETREG(regs, R11, from, r11); | ||
31 | err |= GETREG(regs, R12, from, r12); | ||
32 | err |= GETREG(regs, R13, from, r13); | ||
33 | err |= GETREG(regs, R14, from, r14); | ||
34 | err |= GETREG(regs, R15, from, r15); | ||
35 | err |= GETREG(regs, RDI, from, di); | ||
36 | err |= GETREG(regs, RSI, from, si); | ||
37 | err |= GETREG(regs, RBP, from, bp); | ||
38 | err |= GETREG(regs, RBX, from, bx); | ||
39 | err |= GETREG(regs, RDX, from, dx); | ||
40 | err |= GETREG(regs, RAX, from, ax); | ||
41 | err |= GETREG(regs, RCX, from, cx); | ||
42 | err |= GETREG(regs, RSP, from, sp); | ||
43 | err |= GETREG(regs, RIP, from, ip); | ||
44 | err |= GETREG(regs, EFLAGS, from, flags); | ||
45 | err |= GETREG(regs, CS, from, cs); | ||
46 | if (err) | 25 | if (err) |
47 | return 1; | 26 | return err; |
48 | 27 | ||
28 | #define GETREG(regno, regname) regs->regs.gp[HOST_##regno] = sc.regname | ||
29 | |||
30 | GETREG(R8, r8); | ||
31 | GETREG(R9, r9); | ||
32 | GETREG(R10, r10); | ||
33 | GETREG(R11, r11); | ||
34 | GETREG(R12, r12); | ||
35 | GETREG(R13, r13); | ||
36 | GETREG(R14, r14); | ||
37 | GETREG(R15, r15); | ||
38 | GETREG(RDI, di); | ||
39 | GETREG(RSI, si); | ||
40 | GETREG(RBP, bp); | ||
41 | GETREG(RBX, bx); | ||
42 | GETREG(RDX, dx); | ||
43 | GETREG(RAX, ax); | ||
44 | GETREG(RCX, cx); | ||
45 | GETREG(SP, sp); | ||
46 | GETREG(IP, ip); | ||
47 | GETREG(EFLAGS, flags); | ||
48 | GETREG(CS, cs); | ||
49 | #undef GETREG | 49 | #undef GETREG |
50 | 50 | ||
51 | err = __get_user(buf, &from->fpstate); | 51 | buf = sc.fpstate; |
52 | if (err) | ||
53 | return 1; | ||
54 | 52 | ||
55 | err = copy_from_user(&fp, buf, sizeof(struct user_i387_struct)); | 53 | err = copy_from_user(&fp, buf, sizeof(struct user_i387_struct)); |
56 | if (err) | 54 | if (err) |
@@ -73,48 +71,46 @@ static int copy_sc_to_user(struct sigcontext __user *to, | |||
73 | unsigned long mask, unsigned long sp) | 71 | unsigned long mask, unsigned long sp) |
74 | { | 72 | { |
75 | struct faultinfo * fi = ¤t->thread.arch.faultinfo; | 73 | struct faultinfo * fi = ¤t->thread.arch.faultinfo; |
74 | struct sigcontext sc; | ||
76 | struct user_i387_struct fp; | 75 | struct user_i387_struct fp; |
77 | int err = 0; | 76 | int err = 0; |
77 | memset(&sc, 0, sizeof(struct sigcontext)); | ||
78 | 78 | ||
79 | err |= __put_user(0, &to->gs); | 79 | #define PUTREG(regno, regname) sc.regname = regs->regs.gp[HOST_##regno] |
80 | err |= __put_user(0, &to->fs); | ||
81 | |||
82 | #define PUTREG(regs, regno, sc, regname) \ | ||
83 | __put_user((regs)->regs.gp[(regno) / sizeof(unsigned long)], \ | ||
84 | &(sc)->regname) | ||
85 | 80 | ||
86 | err |= PUTREG(regs, RDI, to, di); | 81 | PUTREG(RDI, di); |
87 | err |= PUTREG(regs, RSI, to, si); | 82 | PUTREG(RSI, si); |
88 | err |= PUTREG(regs, RBP, to, bp); | 83 | PUTREG(RBP, bp); |
89 | /* | 84 | /* |
90 | * Must use original RSP, which is passed in, rather than what's in | 85 | * Must use original RSP, which is passed in, rather than what's in |
91 | * the pt_regs, because that's already been updated to point at the | ||
92 | * signal frame. | 86 | * signal frame. |
93 | */ | 87 | */ |
94 | err |= __put_user(sp, &to->sp); | 88 | sc.sp = sp; |
95 | err |= PUTREG(regs, RBX, to, bx); | 89 | PUTREG(RBX, bx); |
96 | err |= PUTREG(regs, RDX, to, dx); | 90 | PUTREG(RDX, dx); |
97 | err |= PUTREG(regs, RCX, to, cx); | 91 | PUTREG(RCX, cx); |
98 | err |= PUTREG(regs, RAX, to, ax); | 92 | PUTREG(RAX, ax); |
99 | err |= PUTREG(regs, R8, to, r8); | 93 | PUTREG(R8, r8); |
100 | err |= PUTREG(regs, R9, to, r9); | 94 | PUTREG(R9, r9); |
101 | err |= PUTREG(regs, R10, to, r10); | 95 | PUTREG(R10, r10); |
102 | err |= PUTREG(regs, R11, to, r11); | 96 | PUTREG(R11, r11); |
103 | err |= PUTREG(regs, R12, to, r12); | 97 | PUTREG(R12, r12); |
104 | err |= PUTREG(regs, R13, to, r13); | 98 | PUTREG(R13, r13); |
105 | err |= PUTREG(regs, R14, to, r14); | 99 | PUTREG(R14, r14); |
106 | err |= PUTREG(regs, R15, to, r15); | 100 | PUTREG(R15, r15); |
107 | err |= PUTREG(regs, CS, to, cs); /* XXX x86_64 doesn't do this */ | 101 | PUTREG(CS, cs); /* XXX x86_64 doesn't do this */ |
108 | 102 | ||
109 | err |= __put_user(fi->cr2, &to->cr2); | 103 | sc.cr2 = fi->cr2; |
110 | err |= __put_user(fi->error_code, &to->err); | 104 | sc.err = fi->error_code; |
111 | err |= __put_user(fi->trap_no, &to->trapno); | 105 | sc.trapno = fi->trap_no; |
112 | 106 | ||
113 | err |= PUTREG(regs, RIP, to, ip); | 107 | PUTREG(IP, ip); |
114 | err |= PUTREG(regs, EFLAGS, to, flags); | 108 | PUTREG(EFLAGS, flags); |
115 | #undef PUTREG | 109 | #undef PUTREG |
116 | 110 | ||
117 | err |= __put_user(mask, &to->oldmask); | 111 | sc.oldmask = mask; |
112 | |||
113 | err = copy_to_user(to, &sc, sizeof(struct sigcontext)); | ||
118 | if (err) | 114 | if (err) |
119 | return 1; | 115 | return 1; |
120 | 116 | ||