Page MenuHomeFreeBSD

D33813.id101217.diff
No OneTemporary

D33813.id101217.diff

Index: sys/conf/files
===================================================================
--- sys/conf/files
+++ sys/conf/files
@@ -3834,6 +3834,7 @@
kern/kern_ubsan.c optional kubsan
kern/kern_umtx.c standard
kern/kern_uuid.c standard
+kern/kern_vnodedumper.c standard
kern/kern_xxx.c standard
kern/link_elf.c standard
kern/linker_if.m standard
Index: sys/kern/kern_shutdown.c
===================================================================
--- sys/kern/kern_shutdown.c
+++ sys/kern/kern_shutdown.c
@@ -383,6 +383,17 @@
printf("%lds\n", (long)ts.tv_sec);
}
+/*
+ * Set up a context that can be extracted from the dump.
+ */
+void
+dump_savectx(void)
+{
+
+ savectx(&dumppcb);
+ dumptid = curthread->td_tid;
+}
+
int
doadump(boolean_t textdump)
{
@@ -395,8 +406,7 @@
if (TAILQ_EMPTY(&dumper_configs))
return (ENXIO);
- savectx(&dumppcb);
- dumptid = curthread->td_tid;
+ dump_savectx();
dumping++;
coredump = TRUE;
Index: sys/kern/kern_vnodedumper.c
===================================================================
--- /dev/null
+++ sys/kern/kern_vnodedumper.c
@@ -0,0 +1,225 @@
+/*-
+ * Copyright (c) 2021 Juniper Networks
+ *
+ * This software was developed by Mitchell Horne <mhorne@FreeBSD.org>
+ * under sponsorship from Juniper Networks and Klara Systems.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/disk.h>
+#include <sys/fcntl.h>
+#include <sys/kerneldump.h>
+#include <sys/malloc.h>
+#include <sys/namei.h>
+#include <sys/proc.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/vnode.h>
+
+#include <machine/vmparam.h>
+
+static dumper_t vnode_dump;
+static dumper_start_t vnode_dumper_start;
+static dumper_hdr_t vnode_write_headers;
+
+static int livedump_running;
+
+/*
+ * Invoke a live minidump on the system.
+ */
+static int
+sysctl_live_dump(SYSCTL_HANDLER_ARGS)
+{
+#if MINIDUMP_PAGE_TRACKING == 1
+ struct dumperinfo di;
+ char *pathbuf;
+ int error;
+
+ if (req->newptr == NULL)
+ return (EINVAL);
+ if (req->newlen == 0)
+ return (EINVAL);
+ if (req->newlen >= PATH_MAX)
+ return (ENAMETOOLONG);
+
+ pathbuf = malloc(PATH_MAX, M_TEMP, M_WAITOK);
+ error = SYSCTL_IN(req, pathbuf, req->newlen);
+ if (error != 0)
+ return (error);
+ pathbuf[req->newlen] = '\0';
+
+ /* Set up dumper */
+ bzero(&di, sizeof(di));
+ di.dumper_start = vnode_dumper_start;
+ di.dumper = vnode_dump;
+ di.dumper_hdr = vnode_write_headers;
+ di.blocksize = PAGE_SIZE; /* Arbitrary. */
+ di.maxiosize = MAXDUMPPGS * PAGE_SIZE;
+ di.mediasize = 0;
+ di.mediaoffset = 0;
+ di.priv = pathbuf; /* pass path via priv */
+
+ /* Only allow one livedump to proceed at a time. */
+ while (!atomic_cmpset_int(&livedump_running, 0, 1))
+ pause("livedump", hz / 2);
+
+ dump_savectx();
+ error = minidumpsys(&di, true);
+ livedump_running = 0;
+
+ return (error);
+#else
+ return (EOPNOTSUPP);
+#endif /* MINIDUMP_PAGE_TRACKING == 1 */
+}
+
+SYSCTL_PROC(_kern, OID_AUTO, livedump,
+ CTLTYPE_STRING | CTLFLAG_WR | CTLFLAG_MPSAFE | CTLFLAG_CAPWR,
+ NULL, 0, sysctl_live_dump, "A",
+ "Start live dump of system");
+
+/*
+ * Perform any initialization needed prior to transmitting the kernel core.
+ *
+ * Namely, this routine opens/creates the vnode for the file path provided in
+ * di->priv. If successful di->priv is reused to hold the vnode pointer.
+ */
+int
+vnode_dumper_start(struct dumperinfo *di, void *key, uint32_t keysize)
+{
+ struct nameidata nd;
+ struct vnode *vp;
+ struct vattr vattr;
+ struct ucred *cred;
+ char *path;
+ int flags;
+ int error;
+
+ MPASS(di->priv != NULL);
+ path = di->priv;
+
+ if (keysize > 0) {
+ /* TODO ? */
+ printf("%s: keysize > 0 unhandled\n", __func__);
+ return (EINVAL);
+ }
+
+ /* Instantiate a vnode for provided path. */
+ flags = FWRITE | O_NOFOLLOW | O_CREAT;
+ NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_SYSSPACE, path);
+ error = vn_open_cred(&nd, &flags, S_IRUSR | S_IWUSR,
+ VN_OPEN_NOAUDIT | VN_OPEN_NAMECACHE, curthread->td_ucred, NULL);
+ if (error != 0)
+ return (error);
+
+ /* Replace priv with the vnode pointer, now that we've obtained it. */
+ vp = nd.ni_vp;
+ di->priv = vp;
+ NDFREE(&nd, NDF_ONLY_PNBUF);
+
+ /*
+ * Don't dump to non-regular files or files with links.
+ * Do not dump into system files. Effective user must own the corefile.
+ */
+ cred = curthread->td_ucred;
+ if (vp->v_type != VREG || VOP_GETATTR(vp, &vattr, cred) != 0 ||
+ vattr.va_nlink != 1 || (vp->v_vflag & VV_SYSTEM) != 0 ||
+ vattr.va_uid != cred->cr_uid) {
+ VOP_UNLOCK(vp);
+ vn_close(vp, FWRITE, cred, curthread);
+ return (EFAULT);
+ }
+
+ return (0);
+}
+
+/*
+ * Callback from dumpsys() to dump a chunk of memory.
+ *
+ * Parameters:
+ * arg Opaque private pointer to vnode
+ * virtual Virtual address (where to read the data from)
+ * physical Physical memory address (unused)
+ * offset Offset from start of core file
+ * length Data length
+ *
+ * Return value:
+ * 0 on success
+ * errno on error
+ */
+int
+vnode_dump(void *arg, void *virtual, vm_offset_t physical __unused,
+ off_t offset, size_t length)
+{
+ struct vnode *vp;
+ int error = 0;
+
+ vp = arg;
+ MPASS(vp != NULL);
+ ASSERT_VOP_LOCKED(vp, __func__);
+
+ /* Done? */
+ if (virtual == NULL)
+ return (0);
+
+ error = vn_rdwr(UIO_WRITE, vp, virtual, length, offset, UIO_SYSSPACE,
+ IO_NODELOCKED, curthread->td_ucred, NOCRED, NULL, curthread);
+ if (error != 0) {
+ printf("%s: error writing to vnode %p: %d\n", __func__, vp,
+ error);
+ VOP_UNLOCK(vp);
+ vn_close(vp, FWRITE, curthread->td_ucred, curthread);
+ }
+
+ return (error);
+}
+
+/*
+ * Callback from dumpsys() to write out the dump header, placed at the end.
+ */
+int
+vnode_write_headers(struct dumperinfo *di, struct kerneldumpheader *kdh)
+{
+ struct vnode *vp;
+ int error;
+
+ vp = di->priv;
+ MPASS(vp != NULL);
+ ASSERT_VOP_LOCKED(vp, __func__);
+
+ /* Write the kernel dump header to the end of the file. */
+ error = vn_rdwr(UIO_WRITE, vp, kdh, sizeof(*kdh), di->dumpoff,
+ UIO_SYSSPACE, IO_NODELOCKED, curthread->td_ucred, NOCRED, NULL,
+ curthread);
+ if (error != 0)
+ printf("%s: error writing to vnode %p: %d\n", __func__, vp,
+ error);
+
+ /* Unconditionally close the vnode; we are finished with it. */
+ VOP_UNLOCK(vp);
+ vn_close(vp, FWRITE, curthread->td_ucred, curthread);
+ return (error);
+}
Index: sys/sys/conf.h
===================================================================
--- sys/sys/conf.h
+++ sys/sys/conf.h
@@ -362,6 +362,7 @@
extern int dumping; /* system is dumping */
+void dump_savectx(void);
int doadump(boolean_t);
struct diocskerneldump_arg;
int dumper_insert(const struct dumperinfo *di_template, const char *devname,

File Metadata

Mime Type
text/plain
Expires
Wed, Apr 22, 2:21 AM (16 h, 31 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31947034
Default Alt Text
D33813.id101217.diff (7 KB)

Event Timeline