summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorBryan Cantrill <bryan@joyent.com>2015-10-22 15:34:32 +0000
committerBryan Cantrill <bryan@joyent.com>2015-10-22 15:34:32 +0000
commita7ccdb59b0dda2db3327038c36abe575d9a76d10 (patch)
treef1678426e2d2cfa3724089d9e22fd1a0477ad67f /usr/src
parent8fb0bbb41f1ca2e8d76f2593f394aa062713fd63 (diff)
downloadillumos-joyent-a7ccdb59b0dda2db3327038c36abe575d9a76d10.tar.gz
OS-4869 writes to /dev/kmem should be logged to a ring buffer
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/mdb/Makefile.common2
-rw-r--r--usr/src/cmd/mdb/common/modules/mm/mm.c140
-rw-r--r--usr/src/cmd/mdb/intel/amd64/mm/Makefile24
-rw-r--r--usr/src/cmd/mdb/intel/ia32/mm/Makefile24
-rw-r--r--usr/src/cmd/mdb/sparc/v9/mm/Makefile25
-rw-r--r--usr/src/pkg/manifests/developer-debug-mdb.mf2
-rw-r--r--usr/src/uts/common/io/mem.c50
-rw-r--r--usr/src/uts/common/sys/mem.h13
8 files changed, 280 insertions, 0 deletions
diff --git a/usr/src/cmd/mdb/Makefile.common b/usr/src/cmd/mdb/Makefile.common
index 6644e8bc25..9b8d438a88 100644
--- a/usr/src/cmd/mdb/Makefile.common
+++ b/usr/src/cmd/mdb/Makefile.common
@@ -20,6 +20,7 @@
#
# Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
# Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+# Copyright (c) 2015, Joyent, Inc. All rights reserved.
#
# MDB modules used for debugging user processes that every ISA's build
# subdirectory will need to build.
@@ -75,6 +76,7 @@ COMMON_MODULES_KVM = \
logindmux \
mac \
md \
+ mm \
mpt_sas \
mr_sas \
nca \
diff --git a/usr/src/cmd/mdb/common/modules/mm/mm.c b/usr/src/cmd/mdb/common/modules/mm/mm.c
new file mode 100644
index 0000000000..08b6aac770
--- /dev/null
+++ b/usr/src/cmd/mdb/common/modules/mm/mm.c
@@ -0,0 +1,140 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2015, Joyent, Inc. All rights reserved.
+ */
+
+#include <sys/mdb_modapi.h>
+#include <sys/time.h>
+#include <sys/mem.h>
+
+typedef struct kmemlog_walk {
+ uintptr_t kmlw_addr;
+ mm_logentry_t *kmlw_entries;
+ int kmlw_nentries;
+ int kmlw_entry;
+ int kmlw_oldest;
+} kmemlog_walk_t;
+
+static int
+kmemlog_walk_init(mdb_walk_state_t *wsp)
+{
+ kmemlog_walk_t *kw;
+ GElf_Sym sym;
+
+ if (mdb_lookup_by_name("mm_kmemlog", &sym) != 0) {
+ mdb_warn("couldn't find symbol 'mm_kmemlog'");
+ return (WALK_ERR);
+ }
+
+ kw = mdb_zalloc(sizeof (kmemlog_walk_t), UM_SLEEP);
+ kw->kmlw_entries = mdb_zalloc(sym.st_size, UM_SLEEP);
+ kw->kmlw_addr = sym.st_value;
+
+ if (mdb_vread(kw->kmlw_entries, sym.st_size, sym.st_value) == -1) {
+ mdb_warn("couldn't read log at %p", sym.st_value);
+ mdb_free(kw->kmlw_entries, sym.st_size);
+ mdb_free(kw, sizeof (kmemlog_walk_t));
+ return (WALK_ERR);
+ }
+
+ kw->kmlw_nentries = sym.st_size / sizeof (mm_logentry_t);
+
+ mdb_readvar(&kw->kmlw_entry, "mm_kmemlogent");
+ kw->kmlw_oldest = kw->kmlw_entry;
+ wsp->walk_data = kw;
+
+ return (WALK_NEXT);
+}
+
+static int
+kmemlog_walk_step(mdb_walk_state_t *wsp)
+{
+ kmemlog_walk_t *kw = wsp->walk_data;
+ mm_logentry_t *ent;
+ int rval = WALK_NEXT;
+
+ ent = &kw->kmlw_entries[kw->kmlw_entry];
+
+ if (++kw->kmlw_entry == kw->kmlw_nentries)
+ kw->kmlw_entry = 0;
+
+ if (ent->mle_hrtime != 0) {
+ rval = wsp->walk_callback(kw->kmlw_addr + ((uintptr_t)ent -
+ (uintptr_t)kw->kmlw_entries), ent, wsp->walk_cbdata);
+ }
+
+ if (rval == WALK_NEXT && kw->kmlw_entry == kw->kmlw_oldest)
+ return (WALK_DONE);
+
+ return (rval);
+}
+
+static void
+kmemlog_walk_fini(mdb_walk_state_t *wsp)
+{
+ kmemlog_walk_t *kw = wsp->walk_data;
+
+ mdb_free(kw->kmlw_entries, kw->kmlw_nentries * sizeof (mm_logentry_t));
+ mdb_free(kw, sizeof (kmemlog_walk_t));
+}
+
+static int
+kmemlog(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+ mm_logentry_t ent;
+
+ if (!(flags & DCMD_ADDRSPEC)) {
+ if (mdb_walk_dcmd("kmemlog", "kmemlog", argc, argv) == -1) {
+ mdb_warn("can't walk 'kmemlog'");
+ return (DCMD_ERR);
+ }
+ return (DCMD_OK);
+ }
+
+ if (DCMD_HDRSPEC(flags)) {
+ mdb_printf("%?s %-20s %?s %5s %s\n",
+ "ADDR", "TIME", "VADDR", "PID", "PSARGS");
+ }
+
+ if (mdb_vread(&ent, sizeof (ent), addr) == -1) {
+ mdb_warn("can't read mm_logentry_t at %p", addr);
+ return (DCMD_ERR);
+ }
+
+ mdb_printf("%?p %-20Y %?p %5d %s\n",
+ addr, ent.mle_hrestime.tv_sec, ent.mle_vaddr, ent.mle_pid,
+ ent.mle_psargs);
+
+ return (DCMD_OK);
+}
+
+static const mdb_dcmd_t dcmds[] = {
+ { "kmemlog", NULL, "print log of writes via /dev/kmem", kmemlog },
+ { NULL }
+};
+
+static const mdb_walker_t walkers[] = {
+ { "kmemlog", "walk entries in /dev/kmem write log",
+ kmemlog_walk_init, kmemlog_walk_step, kmemlog_walk_fini },
+ { NULL }
+};
+
+static const mdb_modinfo_t modinfo = {
+ MDB_API_VERSION, dcmds, walkers
+};
+
+const mdb_modinfo_t *
+_mdb_init(void)
+{
+ return (&modinfo);
+}
diff --git a/usr/src/cmd/mdb/intel/amd64/mm/Makefile b/usr/src/cmd/mdb/intel/amd64/mm/Makefile
new file mode 100644
index 0000000000..216385a60c
--- /dev/null
+++ b/usr/src/cmd/mdb/intel/amd64/mm/Makefile
@@ -0,0 +1,24 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2015, Joyent, Inc. All rights reserved.
+#
+
+MODULE = mm.so
+MDBTGT = kvm
+
+MODSRCS = mm.c
+
+include ../../../../Makefile.cmd
+include ../../../../Makefile.cmd.64
+include ../../Makefile.amd64
+include ../../../Makefile.module
diff --git a/usr/src/cmd/mdb/intel/ia32/mm/Makefile b/usr/src/cmd/mdb/intel/ia32/mm/Makefile
new file mode 100644
index 0000000000..e37ee86753
--- /dev/null
+++ b/usr/src/cmd/mdb/intel/ia32/mm/Makefile
@@ -0,0 +1,24 @@
+#
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2015, Joyent, Inc. All rights reserved.
+#
+
+MODULE = mm.so
+MDBTGT = kvm
+
+MODSRCS = mm.c
+
+include ../../../../Makefile.cmd
+include ../../Makefile.ia32
+include ../../../Makefile.module
diff --git a/usr/src/cmd/mdb/sparc/v9/mm/Makefile b/usr/src/cmd/mdb/sparc/v9/mm/Makefile
new file mode 100644
index 0000000000..c49f4f4484
--- /dev/null
+++ b/usr/src/cmd/mdb/sparc/v9/mm/Makefile
@@ -0,0 +1,25 @@
+#
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2015, Joyent, Inc. All rights reserved.
+#
+
+MODULE = mm.so
+MDBTGT = kvm
+
+MODSRCS = mm.c
+
+include ../../../../Makefile.cmd
+include ../../../../Makefile.cmd.64
+include ../../Makefile.sparcv9
+include ../../../Makefile.module
diff --git a/usr/src/pkg/manifests/developer-debug-mdb.mf b/usr/src/pkg/manifests/developer-debug-mdb.mf
index 926e63d69f..b7d6bb4630 100644
--- a/usr/src/pkg/manifests/developer-debug-mdb.mf
+++ b/usr/src/pkg/manifests/developer-debug-mdb.mf
@@ -225,6 +225,7 @@ file path=usr/lib/mdb/kvm/$(ARCH64)/mac.so group=sys mode=0555
file path=usr/lib/mdb/kvm/$(ARCH64)/md.so group=sys mode=0555
$(i386_ONLY)file path=usr/lib/mdb/kvm/$(ARCH64)/mdb_kb.so group=sys mode=0555
file path=usr/lib/mdb/kvm/$(ARCH64)/mdb_ks.so group=sys mode=0555
+file path=usr/lib/mdb/kvm/$(ARCH64)/mm.so group=sys mode=0555
file path=usr/lib/mdb/kvm/$(ARCH64)/mpt.so group=sys mode=0555
file path=usr/lib/mdb/kvm/$(ARCH64)/mpt_sas.so group=sys mode=0555
file path=usr/lib/mdb/kvm/$(ARCH64)/mr_sas.so group=sys mode=0555
@@ -263,6 +264,7 @@ $(i386_ONLY)file path=usr/lib/mdb/kvm/mac.so group=sys mode=0555
$(i386_ONLY)file path=usr/lib/mdb/kvm/md.so group=sys mode=0555
$(i386_ONLY)file path=usr/lib/mdb/kvm/mdb_kb.so group=sys mode=0555
$(i386_ONLY)file path=usr/lib/mdb/kvm/mdb_ks.so group=sys mode=0555
+$(i386_ONLY)file path=usr/lib/mdb/kvm/mm.so group=sys mode=0555
$(i386_ONLY)file path=usr/lib/mdb/kvm/mpt.so group=sys mode=0555
$(i386_ONLY)file path=usr/lib/mdb/kvm/mpt_sas.so group=sys mode=0555
$(i386_ONLY)file path=usr/lib/mdb/kvm/mr_sas.so group=sys mode=0555
diff --git a/usr/src/uts/common/io/mem.c b/usr/src/uts/common/io/mem.c
index 7a703c5750..c0173a6f42 100644
--- a/usr/src/uts/common/io/mem.c
+++ b/usr/src/uts/common/io/mem.c
@@ -24,6 +24,10 @@
*/
/*
+ * Copyright (c) 2015, Joyent, Inc. All rights reserved.
+ */
+
+/*
* Memory special file
*/
@@ -95,6 +99,49 @@ static int mm_kstat_snapshot(kstat_t *ksp, void *buf, int rw);
static int mm_read_mem_name(intptr_t data, mem_name_t *mem_name);
+#define MM_KMEMLOG_NENTRIES 64
+
+static int mm_kmemlogent;
+static mm_logentry_t mm_kmemlog[MM_KMEMLOG_NENTRIES];
+
+/*
+ * On kmem/allmem writes, we log information that might be useful in the event
+ * that a write is errant (that is, due to operator error) and induces a later
+ * problem. Note that (in particular) in the event of such operator-induced
+ * corruption, a search over the kernel address space for the corrupted
+ * address will yield the ring buffer entry that recorded the write. And
+ * should it seem baroque or otherwise unnecessary, yes, we need this kind of
+ * auditing facility and yes, we learned that the hard way: disturbingly,
+ * there exist recommendations for "tuning" the system that involve writing to
+ * kernel memory addresses via the kernel debugger, and -- as we discovered --
+ * these can easily be applied incorrectly or unsafely, yielding an entirely
+ * undebuggable "can't happen" kind of panic.
+ */
+static void
+mm_logkmem(struct uio *uio)
+{
+ mm_logentry_t *ent;
+ proc_t *p = curthread->t_procp;
+
+ mutex_enter(&mm_lock);
+
+ ent = &mm_kmemlog[mm_kmemlogent++];
+
+ if (mm_kmemlogent == MM_KMEMLOG_NENTRIES)
+ mm_kmemlogent = 0;
+
+ ent->mle_vaddr = (uintptr_t)uio->uio_loffset;
+ ent->mle_len = uio->uio_resid;
+ gethrestime(&ent->mle_hrestime);
+ ent->mle_hrtime = gethrtime();
+ ent->mle_pid = p->p_pidp->pid_id;
+
+ (void) strncpy(ent->mle_psargs,
+ p->p_user.u_psargs, sizeof (ent->mle_psargs));
+
+ mutex_exit(&mm_lock);
+}
+
/*ARGSUSED1*/
static int
mm_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
@@ -354,6 +401,9 @@ mmrw(dev_t dev, struct uio *uio, enum uio_rw rw, cred_t *cred)
if ((error = plat_mem_do_mmio(uio, rw)) != ENOTSUP)
break;
+ if (rw == UIO_WRITE)
+ mm_logkmem(uio);
+
/*
* If vaddr does not map a valid page, as_pagelock()
* will return failure. Hence we can't check the
diff --git a/usr/src/uts/common/sys/mem.h b/usr/src/uts/common/sys/mem.h
index d0ac1223fc..5101b3ec17 100644
--- a/usr/src/uts/common/sys/mem.h
+++ b/usr/src/uts/common/sys/mem.h
@@ -23,6 +23,10 @@
* Use is subject to license terms.
*/
+/*
+ * Copyright (c) 2015, Joyent, Inc. All rights reserved.
+ */
+
#ifndef _SYS_MEM_H
#define _SYS_MEM_H
@@ -128,6 +132,15 @@ extern pfn_t impl_obmem_pfnum(pfn_t);
extern int plat_mem_do_mmio(struct uio *, enum uio_rw);
+typedef struct mm_logentry {
+ uintptr_t mle_vaddr; /* vaddr being written to */
+ size_t mle_len; /* length of write */
+ timespec_t mle_hrestime; /* hrestime at time of write */
+ hrtime_t mle_hrtime; /* hrtime at time of write */
+ pid_t mle_pid; /* pid of writing process */
+ char mle_psargs[80]; /* psargs of writing process */
+} mm_logentry_t;
+
#endif /* _KERNEL */
#ifdef __cplusplus