summaryrefslogtreecommitdiff
path: root/sys/kern
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>2013-01-15 01:34:28 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>2013-01-15 01:34:28 +0000
commit54e04668b72a7e51fa97923d740f133acbd11e9e (patch)
treef8b12c4c9fe63c3fd86f3bf2ac1631e7bb86b6a2 /sys/kern
parent888aa04d8ccf18050c96bb942d1317bf51df2613 (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.c5
-rw-r--r--sys/kern/kern_sig.c63
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 */
/*