aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorJustin Hibbits <chmeeedalf@gmail.com>2020-06-04 18:15:15 +0000
committerPiotr Kubaj <pkubaj@FreeBSD.org>2020-12-30 22:45:35 +0000
commit6260bfb0874280d3fb58ac52699e2aee6ecca8a8 (patch)
tree8b0936af791720090d077f7d779a37e3a72fa831 /sys
parentadf79abc35ff807644c5e43c3d4856b5a29e15ab (diff)
downloadsrc-6260bfb0874280d3fb58ac52699e2aee6ecca8a8.tar.gz
src-6260bfb0874280d3fb58ac52699e2aee6ecca8a8.zip
powerpc: Optimize copyinstr() to avoid repeatedly mapping user strings
Currently copyinstr() uses fubyte() to read each byte from userspace. However, this means that for each byte, it calls pmap_map_user_ptr() to map the string into memory. This is needlessly wasteful, since the string will rarely ever cross a segment boundary. Instead, map a segment at a time, and copy as much from that segment as possible at a time. Measured with the HPT pmap on powerpc64, this saves roughly 8% time on buildkernel, and 5% on buildworld, in wallclock time.
Diffstat (limited to 'sys')
-rw-r--r--sys/powerpc/powerpc/copyinout.c46
1 files changed, 33 insertions, 13 deletions
diff --git a/sys/powerpc/powerpc/copyinout.c b/sys/powerpc/powerpc/copyinout.c
index 76965ad996b8..1528accc0e0e 100644
--- a/sys/powerpc/powerpc/copyinout.c
+++ b/sys/powerpc/powerpc/copyinout.c
@@ -236,31 +236,51 @@ REMAP(copyin)(const void *udaddr, void *kaddr, size_t len)
int
REMAP(copyinstr)(const void *udaddr, void *kaddr, size_t len, size_t *done)
{
+ struct thread *td;
+ pmap_t pm;
+ jmp_buf env;
const char *up;
- char *kp;
- size_t l;
- int rv, c;
+ char *kp, *p;
+ size_t i, l, t;
+ int rv;
- kp = kaddr;
- up = udaddr;
+ td = curthread;
+ pm = &td->td_proc->p_vmspace->vm_pmap;
+ t = 0;
rv = ENAMETOOLONG;
- for (l = 0; len-- > 0; l++) {
- if ((c = fubyte(up++)) < 0) {
+ td->td_pcb->pcb_onfault = &env;
+ if (setjmp(env)) {
+ rv = EFAULT;
+ goto done;
+ }
+
+ kp = kaddr;
+ up = udaddr;
+
+ while (len > 0) {
+ if (pmap_map_user_ptr(pm, up, (void **)&p, len, &l)) {
rv = EFAULT;
- break;
+ goto done;
}
- if (!(*kp++ = c)) {
- l++;
- rv = 0;
- break;
+ for (i = 0; len > 0 && i < l; i++, t++, len--) {
+ if ((*kp++ = *p++) == 0) {
+ i++, t++;
+ rv = 0;
+ goto done;
+ }
}
+
+ up += l;
}
+done:
+ td->td_pcb->pcb_onfault = NULL;
+
if (done != NULL) {
- *done = l;
+ *done = t;
}
return (rv);