diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 2013-01-15 01:34:28 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 2013-01-15 01:34:28 +0000 |
commit | 54e04668b72a7e51fa97923d740f133acbd11e9e (patch) | |
tree | f8b12c4c9fe63c3fd86f3bf2ac1631e7bb86b6a2 /sys/kern | |
parent | 888aa04d8ccf18050c96bb942d1317bf51df2613 (diff) |
Slice & dice coredump write requests into MAXPHYS blocks, and
yield between operations. Re-grab the vnode every operation,
so that multiple coredumps can be saved at the same time.
ok guenther beck etc
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/exec_elf.c | 5 | ||||
-rw-r--r-- | sys/kern/kern_sig.c | 63 |
2 files changed, 49 insertions, 19 deletions
diff --git a/sys/kern/exec_elf.c b/sys/kern/exec_elf.c index 1550478c8a7..0322e7c2b47 100644 --- a/sys/kern/exec_elf.c +++ b/sys/kern/exec_elf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: exec_elf.c,v 1.89 2012/09/17 17:11:49 matthew Exp $ */ +/* $OpenBSD: exec_elf.c,v 1.90 2013/01/15 01:34:27 deraadt Exp $ */ /* * Copyright (c) 1996 Per Fogelstrom @@ -1072,6 +1072,9 @@ ELFNAMEEND(coredump)(struct proc *p, void *cookie) if (error) goto out; + coredump_unmap(cookie, (vaddr_t)psections[i].p_vaddr, + (vaddr_t)psections[i].p_vaddr + psections[i].p_filesz); + #ifdef DIAGNOSTIC offset += psections[i].p_filesz; #endif diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index 4cf0c268468..0820b9c0501 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_sig.c,v 1.145 2012/12/02 07:03:32 guenther Exp $ */ +/* $OpenBSD: kern_sig.c,v 1.146 2013/01/15 01:34:27 deraadt Exp $ */ /* $NetBSD: kern_sig.c,v 1.54 1996/04/22 01:38:32 christos Exp $ */ /* @@ -1410,7 +1410,7 @@ coredump(struct proc *p) struct nameidata nd; struct vattr vattr; struct coredump_iostate io; - int error, error1, len; + int error, len; char name[sizeof("/var/crash/") + MAXCOMLEN + sizeof(".core")]; char *dir = ""; @@ -1474,14 +1474,18 @@ coredump(struct proc *p) io.io_vp = vp; io.io_cred = cred; io.io_offset = 0; + VOP_UNLOCK(vp, 0, p); + vref(vp); + error = vn_close(vp, FWRITE, cred, p); + if (error) { + vrele(vp); + return (error); + } error = (*p->p_emul->e_coredump)(p, &io); out: - VOP_UNLOCK(vp, 0, p); - error1 = vn_close(vp, FWRITE, cred, p); crfree(cred); - if (error == 0) - error = error1; + vrele(vp); return (error); #endif } @@ -1520,7 +1524,7 @@ coredump_trad(struct proc *p, void *cookie) return (error); error = vn_rdwr(UIO_WRITE, vp, (caddr_t)&core, (int)core.c_hdrsize, (off_t)0, - UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, NULL, p); + UIO_SYSSPACE, IO_UNIT, cred, NULL, p); return (error); #endif } @@ -1530,22 +1534,45 @@ int coredump_write(void *cookie, enum uio_seg segflg, const void *data, size_t len) { struct coredump_iostate *io = cookie; - int error; + off_t coffset = 0; + size_t csize; + int chunk, error; + + csize = len; + do { + /* Rest of the loop sleeps with lock held, so... */ + yield(); + + chunk = MIN(csize, MAXPHYS); + error = vn_rdwr(UIO_WRITE, io->io_vp, + (caddr_t)data + coffset, chunk, + io->io_offset + coffset, segflg, + IO_UNIT, io->io_cred, NULL, io->io_proc); + if (error) { + printf("pid %d (%s): %s write of %lu@%p" + " at %lld failed: %d\n", + io->io_proc->p_pid, io->io_proc->p_comm, + segflg == UIO_USERSPACE ? "user" : "system", + len, data, (long long) io->io_offset, error); + return (error); + } - error = vn_rdwr(UIO_WRITE, io->io_vp, (void *)data, len, - io->io_offset, segflg, - IO_NODELOCKED|IO_UNIT, io->io_cred, NULL, io->io_proc); - if (error) { - printf("pid %d (%s): %s write of %lu@%p at %lld failed: %d\n", - io->io_proc->p_pid, io->io_proc->p_comm, - segflg == UIO_USERSPACE ? "user" : "system", - len, data, (long long) io->io_offset, error); - return (error); - } + coffset += chunk; + csize -= chunk; + } while (csize > 0); io->io_offset += len; return (0); } + +void +coredump_unmap(void *cookie, vaddr_t start, vaddr_t end) +{ + struct coredump_iostate *io = cookie; + + uvm_unmap(&io->io_proc->p_vmspace->vm_map, start, end); +} + #endif /* !SMALL_KERNEL */ /* |