1ad4240feSJulian Elischer /*- 251369649SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 351369649SPedro F. Giffuni * 4ad4240feSJulian Elischer * Copyright (c) 1986, 1988, 1991, 1993 5ad4240feSJulian Elischer * The Regents of the University of California. All rights reserved. 6ad4240feSJulian Elischer * (c) UNIX System Laboratories, Inc. 7ad4240feSJulian Elischer * All or some portions of this file are derived from material licensed 8ad4240feSJulian Elischer * to the University of California by American Telephone and Telegraph 9ad4240feSJulian Elischer * Co. or Unix System Laboratories, Inc. and are reproduced herein with 10ad4240feSJulian Elischer * the permission of UNIX System Laboratories, Inc. 11ad4240feSJulian Elischer * 12ad4240feSJulian Elischer * Redistribution and use in source and binary forms, with or without 13ad4240feSJulian Elischer * modification, are permitted provided that the following conditions 14ad4240feSJulian Elischer * are met: 15ad4240feSJulian Elischer * 1. Redistributions of source code must retain the above copyright 16ad4240feSJulian Elischer * notice, this list of conditions and the following disclaimer. 17ad4240feSJulian Elischer * 2. Redistributions in binary form must reproduce the above copyright 18ad4240feSJulian Elischer * notice, this list of conditions and the following disclaimer in the 19ad4240feSJulian Elischer * documentation and/or other materials provided with the distribution. 2069a28758SEd Maste * 3. Neither the name of the University nor the names of its contributors 21ad4240feSJulian Elischer * may be used to endorse or promote products derived from this software 22ad4240feSJulian Elischer * without specific prior written permission. 23ad4240feSJulian Elischer * 24ad4240feSJulian Elischer * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25ad4240feSJulian Elischer * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26ad4240feSJulian Elischer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27ad4240feSJulian Elischer * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28ad4240feSJulian Elischer * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29ad4240feSJulian Elischer * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30ad4240feSJulian Elischer * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31ad4240feSJulian Elischer * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32ad4240feSJulian Elischer * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33ad4240feSJulian Elischer * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34ad4240feSJulian Elischer * SUCH DAMAGE. 35ad4240feSJulian Elischer * 36ad4240feSJulian Elischer * @(#)kern_shutdown.c 8.3 (Berkeley) 1/21/94 37ad4240feSJulian Elischer */ 38ad4240feSJulian Elischer 39677b542eSDavid E. O'Brien #include <sys/cdefs.h> 40677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 41677b542eSDavid E. O'Brien 42618c7db3SRobert Watson #include "opt_ddb.h" 43480f31c2SKonrad Witaszczyk #include "opt_ekcd.h" 442d50560aSMarcel Moolenaar #include "opt_kdb.h" 456d58e6cbSBruce Evans #include "opt_panic.h" 466b6e2954SConrad Meyer #include "opt_printf.h" 479923b511SScott Long #include "opt_sched.h" 482be767e0SAttilio Rao #include "opt_watchdog.h" 49ad4240feSJulian Elischer 50ad4240feSJulian Elischer #include <sys/param.h> 51ad4240feSJulian Elischer #include <sys/systm.h> 529626b608SPoul-Henning Kamp #include <sys/bio.h> 535a8fceb3SMitchell Horne #include <sys/boottrace.h> 54fc8f7066SBruce Evans #include <sys/buf.h> 551d79f1bbSJohn Baldwin #include <sys/conf.h> 5678f57a9cSMark Johnston #include <sys/compressor.h> 571d79f1bbSJohn Baldwin #include <sys/cons.h> 586b6e2954SConrad Meyer #include <sys/disk.h> 591d79f1bbSJohn Baldwin #include <sys/eventhandler.h> 600d3d0cc3SEdward Tomasz Napierala #include <sys/filedesc.h> 6176ca6f88SJamie Gritton #include <sys/jail.h> 622d50560aSMarcel Moolenaar #include <sys/kdb.h> 63ad4240feSJulian Elischer #include <sys/kernel.h> 64e6592ee5SPeter Wemm #include <sys/kerneldump.h> 655e950839SLuoqi Chen #include <sys/kthread.h> 663945a964SAlfred Perlstein #include <sys/ktr.h> 67dcd7d9b7SMaxim Sobolev #include <sys/malloc.h> 68bd92e6b6SMark Johnston #include <sys/mbuf.h> 69ac0ad63fSBruce Evans #include <sys/mount.h> 70acd3428bSRobert Watson #include <sys/priv.h> 711d79f1bbSJohn Baldwin #include <sys/proc.h> 721d79f1bbSJohn Baldwin #include <sys/reboot.h> 731d79f1bbSJohn Baldwin #include <sys/resourcevar.h> 7489f6b863SAttilio Rao #include <sys/rwlock.h> 756b6e2954SConrad Meyer #include <sys/sbuf.h> 7620e25d7dSPeter Wemm #include <sys/sched.h> 77248bb937SAttilio Rao #include <sys/smp.h> 78ad4240feSJulian Elischer #include <sys/sysctl.h> 79ad4240feSJulian Elischer #include <sys/sysproto.h> 80c3982007SKonstantin Belousov #include <sys/taskqueue.h> 81fa2b39a1SAttilio Rao #include <sys/vnode.h> 822be767e0SAttilio Rao #include <sys/watchdog.h> 83ad4240feSJulian Elischer 8482985292SConrad Meyer #include <crypto/chacha20/chacha.h> 85480f31c2SKonrad Witaszczyk #include <crypto/rijndael/rijndael-api-fst.h> 86480f31c2SKonrad Witaszczyk #include <crypto/sha2/sha256.h> 87480f31c2SKonrad Witaszczyk 88618c7db3SRobert Watson #include <ddb/ddb.h> 89618c7db3SRobert Watson 9026502503SMarcel Moolenaar #include <machine/cpu.h> 91bdb9ab0dSMark Johnston #include <machine/dump.h> 92d39e457bSPoul-Henning Kamp #include <machine/pcb.h> 93752dff3dSJake Burkholder #include <machine/smp.h> 94ad4240feSJulian Elischer 95aed55708SRobert Watson #include <security/mac/mac_framework.h> 96aed55708SRobert Watson 970909f38aSPawel Jakub Dawidek #include <vm/vm.h> 980909f38aSPawel Jakub Dawidek #include <vm/vm_object.h> 990909f38aSPawel Jakub Dawidek #include <vm/vm_page.h> 1000909f38aSPawel Jakub Dawidek #include <vm/vm_pager.h> 1010909f38aSPawel Jakub Dawidek #include <vm/swap_pager.h> 1020909f38aSPawel Jakub Dawidek 103ad4240feSJulian Elischer #include <sys/signalvar.h> 104ad4240feSJulian Elischer 1055dc5dab6SConrad Meyer static MALLOC_DEFINE(M_DUMPER, "dumper", "dumper block buffer"); 1065dc5dab6SConrad Meyer 107ad4240feSJulian Elischer #ifndef PANIC_REBOOT_WAIT_TIME 108ad4240feSJulian Elischer #define PANIC_REBOOT_WAIT_TIME 15 /* default to 15 seconds */ 109ad4240feSJulian Elischer #endif 1103b251028SColin Percival static int panic_reboot_wait_time = PANIC_REBOOT_WAIT_TIME; 111af3b2549SHans Petter Selasky SYSCTL_INT(_kern, OID_AUTO, panic_reboot_wait_time, CTLFLAG_RWTUN, 1121cdbb9edSColin Percival &panic_reboot_wait_time, 0, 1131cdbb9edSColin Percival "Seconds to wait before rebooting after a panic"); 114*84ec7df0SColin Percival static int reboot_wait_time = 0; 115*84ec7df0SColin Percival SYSCTL_INT(_kern, OID_AUTO, reboot_wait_time, CTLFLAG_RWTUN, 116*84ec7df0SColin Percival &reboot_wait_time, 0, 117*84ec7df0SColin Percival "Seconds to wait before rebooting"); 118ad4240feSJulian Elischer 119ad4240feSJulian Elischer /* 120ad4240feSJulian Elischer * Note that stdarg.h and the ANSI style va_start macro is used for both 121ad4240feSJulian Elischer * ANSI and traditional C compilers. 122ad4240feSJulian Elischer */ 123ad4240feSJulian Elischer #include <machine/stdarg.h> 124ad4240feSJulian Elischer 1252d50560aSMarcel Moolenaar #ifdef KDB 1262d50560aSMarcel Moolenaar #ifdef KDB_UNATTENDED 127ba0ced82SEric van Gyzen int debugger_on_panic = 0; 128ad4240feSJulian Elischer #else 129ba0ced82SEric van Gyzen int debugger_on_panic = 1; 130ad4240feSJulian Elischer #endif 1313d7618d8SDavid E. O'Brien SYSCTL_INT(_debug, OID_AUTO, debugger_on_panic, 132af3b2549SHans Petter Selasky CTLFLAG_RWTUN | CTLFLAG_SECURE, 1331c5151f3SDavid E. O'Brien &debugger_on_panic, 0, "Run debugger on kernel panic"); 134e485b64bSJohn Baldwin 135c8a96cdcSMitchell Horne static bool debugger_on_recursive_panic = false; 136c8a96cdcSMitchell Horne SYSCTL_BOOL(_debug, OID_AUTO, debugger_on_recursive_panic, 137c8a96cdcSMitchell Horne CTLFLAG_RWTUN | CTLFLAG_SECURE, 138c8a96cdcSMitchell Horne &debugger_on_recursive_panic, 0, "Run debugger on recursive kernel panic"); 139c8a96cdcSMitchell Horne 140b317cfd4SJohn Baldwin int debugger_on_trap = 0; 141b317cfd4SJohn Baldwin SYSCTL_INT(_debug, OID_AUTO, debugger_on_trap, 142b317cfd4SJohn Baldwin CTLFLAG_RWTUN | CTLFLAG_SECURE, 143b317cfd4SJohn Baldwin &debugger_on_trap, 0, "Run debugger on kernel trap before panic"); 144b317cfd4SJohn Baldwin 1452d50560aSMarcel Moolenaar #ifdef KDB_TRACE 14608a9c205SAndriy Gapon static int trace_on_panic = 1; 147ad1fc315SConrad Meyer static bool trace_all_panics = true; 148e485b64bSJohn Baldwin #else 14908a9c205SAndriy Gapon static int trace_on_panic = 0; 150ad1fc315SConrad Meyer static bool trace_all_panics = false; 151e485b64bSJohn Baldwin #endif 1523d7618d8SDavid E. O'Brien SYSCTL_INT(_debug, OID_AUTO, trace_on_panic, 153af3b2549SHans Petter Selasky CTLFLAG_RWTUN | CTLFLAG_SECURE, 1541c5151f3SDavid E. O'Brien &trace_on_panic, 0, "Print stack trace on kernel panic"); 155ad1fc315SConrad Meyer SYSCTL_BOOL(_debug, OID_AUTO, trace_all_panics, CTLFLAG_RWTUN, 156ad1fc315SConrad Meyer &trace_all_panics, 0, "Print stack traces on secondary kernel panics"); 1572d50560aSMarcel Moolenaar #endif /* KDB */ 158ad4240feSJulian Elischer 15908a9c205SAndriy Gapon static int sync_on_panic = 0; 160af3b2549SHans Petter Selasky SYSCTL_INT(_kern, OID_AUTO, sync_on_panic, CTLFLAG_RWTUN, 161259ed917SPeter Wemm &sync_on_panic, 0, "Do a sync before rebooting from a panic"); 162259ed917SPeter Wemm 16348f1a492SWarner Losh static bool poweroff_on_panic = 0; 16448f1a492SWarner Losh SYSCTL_BOOL(_kern, OID_AUTO, poweroff_on_panic, CTLFLAG_RWTUN, 16548f1a492SWarner Losh &poweroff_on_panic, 0, "Do a power off instead of a reboot on a panic"); 16648f1a492SWarner Losh 16748f1a492SWarner Losh static bool powercycle_on_panic = 0; 16848f1a492SWarner Losh SYSCTL_BOOL(_kern, OID_AUTO, powercycle_on_panic, CTLFLAG_RWTUN, 16948f1a492SWarner Losh &powercycle_on_panic, 0, "Do a power cycle instead of a reboot on a panic"); 17048f1a492SWarner Losh 1717029da5cSPawel Biernacki static SYSCTL_NODE(_kern, OID_AUTO, shutdown, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 1726472ac3dSEd Schouten "Shutdown environment"); 173db82a982SMike Smith 174fa2b39a1SAttilio Rao #ifndef DIAGNOSTIC 175fa2b39a1SAttilio Rao static int show_busybufs; 176fa2b39a1SAttilio Rao #else 177fa2b39a1SAttilio Rao static int show_busybufs = 1; 178fa2b39a1SAttilio Rao #endif 179fa2b39a1SAttilio Rao SYSCTL_INT(_kern_shutdown, OID_AUTO, show_busybufs, CTLFLAG_RW, 180b05ca429SPawel Biernacki &show_busybufs, 0, 181b05ca429SPawel Biernacki "Show busy buffers during shutdown"); 182fa2b39a1SAttilio Rao 1832eb0015aSColin Percival int suspend_blocked = 0; 1842eb0015aSColin Percival SYSCTL_INT(_kern, OID_AUTO, suspend_blocked, CTLFLAG_RW, 1852eb0015aSColin Percival &suspend_blocked, 0, "Block suspend due to a pending shutdown"); 1862eb0015aSColin Percival 187480f31c2SKonrad Witaszczyk #ifdef EKCD 188480f31c2SKonrad Witaszczyk FEATURE(ekcd, "Encrypted kernel crash dumps support"); 189480f31c2SKonrad Witaszczyk 190480f31c2SKonrad Witaszczyk MALLOC_DEFINE(M_EKCD, "ekcd", "Encrypted kernel crash dumps data"); 191480f31c2SKonrad Witaszczyk 192480f31c2SKonrad Witaszczyk struct kerneldumpcrypto { 193480f31c2SKonrad Witaszczyk uint8_t kdc_encryption; 194480f31c2SKonrad Witaszczyk uint8_t kdc_iv[KERNELDUMP_IV_MAX_SIZE]; 19582985292SConrad Meyer union { 19682985292SConrad Meyer struct { 19782985292SConrad Meyer keyInstance aes_ki; 19882985292SConrad Meyer cipherInstance aes_ci; 19982985292SConrad Meyer } u_aes; 20082985292SConrad Meyer struct chacha_ctx u_chacha; 20182985292SConrad Meyer } u; 20282985292SConrad Meyer #define kdc_ki u.u_aes.aes_ki 20382985292SConrad Meyer #define kdc_ci u.u_aes.aes_ci 20482985292SConrad Meyer #define kdc_chacha u.u_chacha 205480f31c2SKonrad Witaszczyk uint32_t kdc_dumpkeysize; 206480f31c2SKonrad Witaszczyk struct kerneldumpkey kdc_dumpkey[]; 207480f31c2SKonrad Witaszczyk }; 208480f31c2SKonrad Witaszczyk #endif 209480f31c2SKonrad Witaszczyk 21078f57a9cSMark Johnston struct kerneldumpcomp { 2116026dcd7SMark Johnston uint8_t kdc_format; 21278f57a9cSMark Johnston struct compressor *kdc_stream; 21378f57a9cSMark Johnston uint8_t *kdc_buf; 21478f57a9cSMark Johnston size_t kdc_resid; 21564a16434SMark Johnston }; 21664a16434SMark Johnston 21778f57a9cSMark Johnston static struct kerneldumpcomp *kerneldumpcomp_create(struct dumperinfo *di, 21864a16434SMark Johnston uint8_t compression); 21978f57a9cSMark Johnston static void kerneldumpcomp_destroy(struct dumperinfo *di); 22078f57a9cSMark Johnston static int kerneldumpcomp_write_cb(void *base, size_t len, off_t off, void *arg); 22164a16434SMark Johnston 22264a16434SMark Johnston static int kerneldump_gzlevel = 6; 22364a16434SMark Johnston SYSCTL_INT(_kern, OID_AUTO, kerneldump_gzlevel, CTLFLAG_RWTUN, 22464a16434SMark Johnston &kerneldump_gzlevel, 0, 22578f57a9cSMark Johnston "Kernel crash dump compression level"); 22664a16434SMark Johnston 2275230cfd2SJulian Elischer /* 228ad4240feSJulian Elischer * Variable panicstr contains argument to first call to panic; used as flag 229ad4240feSJulian Elischer * to indicate that the kernel has already called panic. 230ad4240feSJulian Elischer */ 231d199ad3bSMateusz Guzik const char *panicstr; 232d199ad3bSMateusz Guzik bool __read_frequently panicked; 233ad4240feSJulian Elischer 23461322a0aSAlexander Motin int __read_mostly dumping; /* system is dumping */ 23536a52c3cSJeff Roberson int rebooting; /* system is rebooting */ 2366b6e2954SConrad Meyer /* 2376b6e2954SConrad Meyer * Used to serialize between sysctl kern.shutdown.dumpdevname and list 2386b6e2954SConrad Meyer * modifications via ioctl. 2396b6e2954SConrad Meyer */ 2406b6e2954SConrad Meyer static struct mtx dumpconf_list_lk; 2416b6e2954SConrad Meyer MTX_SYSINIT(dumper_configs, &dumpconf_list_lk, "dumper config list", MTX_DEF); 2426b6e2954SConrad Meyer 2436b6e2954SConrad Meyer /* Our selected dumper(s). */ 2446b6e2954SConrad Meyer static TAILQ_HEAD(dumpconflist, dumperinfo) dumper_configs = 2456b6e2954SConrad Meyer TAILQ_HEAD_INITIALIZER(dumper_configs); 2462d50560aSMarcel Moolenaar 2472d50560aSMarcel Moolenaar /* Context information for dump-debuggers. */ 2482d50560aSMarcel Moolenaar static struct pcb dumppcb; /* Registers. */ 249ac6e25ecSHartmut Brandt lwpid_t dumptid; /* Thread ID. */ 25016a011f9SPaul Saab 2510d3d0cc3SEdward Tomasz Napierala static struct cdevsw reroot_cdevsw = { 2520d3d0cc3SEdward Tomasz Napierala .d_version = D_VERSION, 2530d3d0cc3SEdward Tomasz Napierala .d_name = "reroot", 2540d3d0cc3SEdward Tomasz Napierala }; 2550d3d0cc3SEdward Tomasz Napierala 25682acbcf5SPeter Wemm static void poweroff_wait(void *, int); 25782acbcf5SPeter Wemm static void shutdown_halt(void *junk, int howto); 25882acbcf5SPeter Wemm static void shutdown_panic(void *junk, int howto); 25982acbcf5SPeter Wemm static void shutdown_reset(void *junk, int howto); 2600d3d0cc3SEdward Tomasz Napierala static int kern_reroot(void); 261f06a54f0SPoul-Henning Kamp 262fcb893a8SMike Smith /* register various local shutdown events */ 263fcb893a8SMike Smith static void 264fcb893a8SMike Smith shutdown_conf(void *unused) 265fcb893a8SMike Smith { 266e95499bdSAlfred Perlstein 267e95499bdSAlfred Perlstein EVENTHANDLER_REGISTER(shutdown_final, poweroff_wait, NULL, 268fd104c15SRebecca Cran SHUTDOWN_PRI_FIRST); 269e95499bdSAlfred Perlstein EVENTHANDLER_REGISTER(shutdown_final, shutdown_halt, NULL, 270e95499bdSAlfred Perlstein SHUTDOWN_PRI_LAST + 100); 271e95499bdSAlfred Perlstein EVENTHANDLER_REGISTER(shutdown_final, shutdown_panic, NULL, 272e95499bdSAlfred Perlstein SHUTDOWN_PRI_LAST + 100); 273e95499bdSAlfred Perlstein EVENTHANDLER_REGISTER(shutdown_final, shutdown_reset, NULL, 274e95499bdSAlfred Perlstein SHUTDOWN_PRI_LAST + 200); 275fcb893a8SMike Smith } 276ad4240feSJulian Elischer 277237fdd78SRobert Watson SYSINIT(shutdown_conf, SI_SUB_INTRINSIC, SI_ORDER_ANY, shutdown_conf, NULL); 278fcb893a8SMike Smith 279ad4240feSJulian Elischer /* 2800d3d0cc3SEdward Tomasz Napierala * The only reason this exists is to create the /dev/reroot/ directory, 2810d3d0cc3SEdward Tomasz Napierala * used by reroot code in init(8) as a mountpoint for tmpfs. 2820d3d0cc3SEdward Tomasz Napierala */ 2830d3d0cc3SEdward Tomasz Napierala static void 2840d3d0cc3SEdward Tomasz Napierala reroot_conf(void *unused) 2850d3d0cc3SEdward Tomasz Napierala { 2860d3d0cc3SEdward Tomasz Napierala int error; 2870d3d0cc3SEdward Tomasz Napierala struct cdev *cdev; 2880d3d0cc3SEdward Tomasz Napierala 2890d3d0cc3SEdward Tomasz Napierala error = make_dev_p(MAKEDEV_CHECKNAME | MAKEDEV_WAITOK, &cdev, 2900d3d0cc3SEdward Tomasz Napierala &reroot_cdevsw, NULL, UID_ROOT, GID_WHEEL, 0600, "reroot/reroot"); 2910d3d0cc3SEdward Tomasz Napierala if (error != 0) { 2920d3d0cc3SEdward Tomasz Napierala printf("%s: failed to create device node, error %d", 2930d3d0cc3SEdward Tomasz Napierala __func__, error); 2940d3d0cc3SEdward Tomasz Napierala } 2950d3d0cc3SEdward Tomasz Napierala } 2960d3d0cc3SEdward Tomasz Napierala 2970d3d0cc3SEdward Tomasz Napierala SYSINIT(reroot_conf, SI_SUB_DEVFS, SI_ORDER_ANY, reroot_conf, NULL); 2980d3d0cc3SEdward Tomasz Napierala 2990d3d0cc3SEdward Tomasz Napierala /* 3000c14ff0eSRobert Watson * The system call that results in a reboot. 301ad4240feSJulian Elischer */ 302835a82eeSMatthew Dillon /* ARGSUSED */ 303ad4240feSJulian Elischer int 3048451d0ddSKip Macy sys_reboot(struct thread *td, struct reboot_args *uap) 305ad4240feSJulian Elischer { 306ad4240feSJulian Elischer int error; 307ad4240feSJulian Elischer 308a2ecb9b7SRobert Watson error = 0; 309a2ecb9b7SRobert Watson #ifdef MAC 31030d239bcSRobert Watson error = mac_system_check_reboot(td->td_ucred, uap->opt); 311a2ecb9b7SRobert Watson #endif 312a2ecb9b7SRobert Watson if (error == 0) 313acd3428bSRobert Watson error = priv_check(td, PRIV_REBOOT); 314a2ecb9b7SRobert Watson if (error == 0) { 315d5292812SWarner Losh if (uap->opt & RB_REROOT) 3160d3d0cc3SEdward Tomasz Napierala error = kern_reroot(); 317d5292812SWarner Losh else 31876e18b25SMarcel Moolenaar kern_reboot(uap->opt); 3190d3d0cc3SEdward Tomasz Napierala } 320835a82eeSMatthew Dillon return (error); 321ad4240feSJulian Elischer } 322ad4240feSJulian Elischer 323c3982007SKonstantin Belousov static void 324c3982007SKonstantin Belousov shutdown_nice_task_fn(void *arg, int pending __unused) 325ad4240feSJulian Elischer { 326c3982007SKonstantin Belousov int howto; 327e95499bdSAlfred Perlstein 328c3982007SKonstantin Belousov howto = (uintptr_t)arg; 329912d5937SEd Schouten /* Send a signal to init(8) and have it shutdown the world. */ 33087729a2bSJohn Baldwin PROC_LOCK(initproc); 3315a8fceb3SMitchell Horne if ((howto & RB_POWEROFF) != 0) { 3325a8fceb3SMitchell Horne BOOTTRACE("SIGUSR2 to init(8)"); 333912d5937SEd Schouten kern_psignal(initproc, SIGUSR2); 3345a8fceb3SMitchell Horne } else if ((howto & RB_POWERCYCLE) != 0) { 3355a8fceb3SMitchell Horne BOOTTRACE("SIGWINCH to init(8)"); 3367d41b6f0SWarner Losh kern_psignal(initproc, SIGWINCH); 3375a8fceb3SMitchell Horne } else if ((howto & RB_HALT) != 0) { 3385a8fceb3SMitchell Horne BOOTTRACE("SIGUSR1 to init(8)"); 339912d5937SEd Schouten kern_psignal(initproc, SIGUSR1); 3405a8fceb3SMitchell Horne } else { 3415a8fceb3SMitchell Horne BOOTTRACE("SIGINT to init(8)"); 3428451d0ddSKip Macy kern_psignal(initproc, SIGINT); 3435a8fceb3SMitchell Horne } 34487729a2bSJohn Baldwin PROC_UNLOCK(initproc); 345c3982007SKonstantin Belousov } 346c3982007SKonstantin Belousov 347c3982007SKonstantin Belousov static struct task shutdown_nice_task = TASK_INITIALIZER(0, 348c3982007SKonstantin Belousov &shutdown_nice_task_fn, NULL); 349c3982007SKonstantin Belousov 350c3982007SKonstantin Belousov /* 351c3982007SKonstantin Belousov * Called by events that want to shut down.. e.g <CTL><ALT><DEL> on a PC 352c3982007SKonstantin Belousov */ 353c3982007SKonstantin Belousov void 354c3982007SKonstantin Belousov shutdown_nice(int howto) 355c3982007SKonstantin Belousov { 356c3982007SKonstantin Belousov 357c3982007SKonstantin Belousov if (initproc != NULL && !SCHEDULER_STOPPED()) { 3585a8fceb3SMitchell Horne BOOTTRACE("shutdown initiated"); 359c3982007SKonstantin Belousov shutdown_nice_task.ta_context = (void *)(uintptr_t)howto; 360c3982007SKonstantin Belousov taskqueue_enqueue(taskqueue_fast, &shutdown_nice_task); 361ad4240feSJulian Elischer } else { 362c3982007SKonstantin Belousov /* 363c3982007SKonstantin Belousov * No init(8) running, or scheduler would not allow it 364c3982007SKonstantin Belousov * to run, so simply reboot. 365c3982007SKonstantin Belousov */ 3668f5b107bSEd Schouten kern_reboot(howto | RB_NOSYNC); 367ad4240feSJulian Elischer } 368ad4240feSJulian Elischer } 369ad4240feSJulian Elischer 37072dfe7a3SPoul-Henning Kamp static void 37182acbcf5SPeter Wemm print_uptime(void) 37272dfe7a3SPoul-Henning Kamp { 37372dfe7a3SPoul-Henning Kamp int f; 37472dfe7a3SPoul-Henning Kamp struct timespec ts; 37572dfe7a3SPoul-Henning Kamp 37672dfe7a3SPoul-Henning Kamp getnanouptime(&ts); 37772dfe7a3SPoul-Henning Kamp printf("Uptime: "); 37872dfe7a3SPoul-Henning Kamp f = 0; 37972dfe7a3SPoul-Henning Kamp if (ts.tv_sec >= 86400) { 3804a6404dfSJohn Baldwin printf("%ldd", (long)ts.tv_sec / 86400); 38172dfe7a3SPoul-Henning Kamp ts.tv_sec %= 86400; 38272dfe7a3SPoul-Henning Kamp f = 1; 38372dfe7a3SPoul-Henning Kamp } 38472dfe7a3SPoul-Henning Kamp if (f || ts.tv_sec >= 3600) { 3854a6404dfSJohn Baldwin printf("%ldh", (long)ts.tv_sec / 3600); 38672dfe7a3SPoul-Henning Kamp ts.tv_sec %= 3600; 38772dfe7a3SPoul-Henning Kamp f = 1; 38872dfe7a3SPoul-Henning Kamp } 38972dfe7a3SPoul-Henning Kamp if (f || ts.tv_sec >= 60) { 3904a6404dfSJohn Baldwin printf("%ldm", (long)ts.tv_sec / 60); 39172dfe7a3SPoul-Henning Kamp ts.tv_sec %= 60; 39272dfe7a3SPoul-Henning Kamp f = 1; 39372dfe7a3SPoul-Henning Kamp } 3944a6404dfSJohn Baldwin printf("%lds\n", (long)ts.tv_sec); 39572dfe7a3SPoul-Henning Kamp } 39672dfe7a3SPoul-Henning Kamp 397c9114f9fSMitchell Horne /* 398c9114f9fSMitchell Horne * Set up a context that can be extracted from the dump. 399c9114f9fSMitchell Horne */ 400c9114f9fSMitchell Horne void 401c9114f9fSMitchell Horne dump_savectx(void) 402c9114f9fSMitchell Horne { 403c9114f9fSMitchell Horne 404c9114f9fSMitchell Horne savectx(&dumppcb); 405c9114f9fSMitchell Horne dumptid = curthread->td_tid; 406c9114f9fSMitchell Horne } 407c9114f9fSMitchell Horne 408299cceefSMarcel Moolenaar int 409299cceefSMarcel Moolenaar doadump(boolean_t textdump) 410d39e457bSPoul-Henning Kamp { 411299cceefSMarcel Moolenaar boolean_t coredump; 412f6b4f5caSGavin Atkinson int error; 413e95499bdSAlfred Perlstein 414f6b4f5caSGavin Atkinson error = 0; 415299cceefSMarcel Moolenaar if (dumping) 416299cceefSMarcel Moolenaar return (EBUSY); 4176b6e2954SConrad Meyer if (TAILQ_EMPTY(&dumper_configs)) 418299cceefSMarcel Moolenaar return (ENXIO); 419f6449d9dSJulian Elischer 420c9114f9fSMitchell Horne dump_savectx(); 421d39e457bSPoul-Henning Kamp dumping++; 422299cceefSMarcel Moolenaar 423299cceefSMarcel Moolenaar coredump = TRUE; 424618c7db3SRobert Watson #ifdef DDB 425299cceefSMarcel Moolenaar if (textdump && textdump_pending) { 426299cceefSMarcel Moolenaar coredump = FALSE; 4276b6e2954SConrad Meyer textdump_dumpsys(TAILQ_FIRST(&dumper_configs)); 428299cceefSMarcel Moolenaar } 429618c7db3SRobert Watson #endif 4306b6e2954SConrad Meyer if (coredump) { 4316b6e2954SConrad Meyer struct dumperinfo *di; 4326b6e2954SConrad Meyer 4336b6e2954SConrad Meyer TAILQ_FOREACH(di, &dumper_configs, di_next) { 4346b6e2954SConrad Meyer error = dumpsys(di); 4356b6e2954SConrad Meyer if (error == 0) 4366b6e2954SConrad Meyer break; 4376b6e2954SConrad Meyer } 4386b6e2954SConrad Meyer } 439299cceefSMarcel Moolenaar 4409e473363SRuslan Ermilov dumping--; 441f6b4f5caSGavin Atkinson return (error); 442d39e457bSPoul-Henning Kamp } 443d39e457bSPoul-Henning Kamp 444ad4240feSJulian Elischer /* 4455a8fceb3SMitchell Horne * Trace the shutdown reason. 4465a8fceb3SMitchell Horne */ 4475a8fceb3SMitchell Horne static void 4485a8fceb3SMitchell Horne reboottrace(int howto) 4495a8fceb3SMitchell Horne { 4505a8fceb3SMitchell Horne if ((howto & RB_DUMP) != 0) { 4515a8fceb3SMitchell Horne if ((howto & RB_HALT) != 0) 4525a8fceb3SMitchell Horne BOOTTRACE("system panic: halting..."); 4535a8fceb3SMitchell Horne if ((howto & RB_POWEROFF) != 0) 4545a8fceb3SMitchell Horne BOOTTRACE("system panic: powering off..."); 4555a8fceb3SMitchell Horne if ((howto & (RB_HALT|RB_POWEROFF)) == 0) 4565a8fceb3SMitchell Horne BOOTTRACE("system panic: rebooting..."); 4575a8fceb3SMitchell Horne } else { 4585a8fceb3SMitchell Horne if ((howto & RB_HALT) != 0) 4595a8fceb3SMitchell Horne BOOTTRACE("system halting..."); 4605a8fceb3SMitchell Horne if ((howto & RB_POWEROFF) != 0) 4615a8fceb3SMitchell Horne BOOTTRACE("system powering off..."); 4625a8fceb3SMitchell Horne if ((howto & (RB_HALT|RB_POWEROFF)) == 0) 4635a8fceb3SMitchell Horne BOOTTRACE("system rebooting..."); 4645a8fceb3SMitchell Horne } 4655a8fceb3SMitchell Horne } 4665a8fceb3SMitchell Horne 4675a8fceb3SMitchell Horne /* 468800e7495SMitchell Horne * kern_reboot(9): Shut down the system cleanly to prepare for reboot, halt, or 469800e7495SMitchell Horne * power off. 470ad4240feSJulian Elischer */ 47176e18b25SMarcel Moolenaar void 47276e18b25SMarcel Moolenaar kern_reboot(int howto) 473ad4240feSJulian Elischer { 47498082691SJeff Roberson static int once = 0; 475ad4240feSJulian Elischer 4765a8fceb3SMitchell Horne if (initproc != NULL && curproc != initproc) 4775a8fceb3SMitchell Horne BOOTTRACE("kernel shutdown (dirty) started"); 4785a8fceb3SMitchell Horne else 4795a8fceb3SMitchell Horne BOOTTRACE("kernel shutdown (clean) started"); 4805a8fceb3SMitchell Horne 481f0d847afSWarner Losh /* 482f0d847afSWarner Losh * Normal paths here don't hold Giant, but we can wind up here 483f0d847afSWarner Losh * unexpectedly with it held. Drop it now so we don't have to 484f0d847afSWarner Losh * drop and pick it up elsewhere. The paths it is locking will 485f0d847afSWarner Losh * never be returned to, and it is preferable to preclude 486f0d847afSWarner Losh * deadlock than to lock against code that won't ever 487f0d847afSWarner Losh * continue. 488f0d847afSWarner Losh */ 489f0d847afSWarner Losh while (mtx_owned(&Giant)) 490f0d847afSWarner Losh mtx_unlock(&Giant); 491f0d847afSWarner Losh 492f7ebc7ceSMarcel Moolenaar #if defined(SMP) 49370ce93f4SNate Lawson /* 494efe67753SNathan Whitehorn * Bind us to the first CPU so that all shutdown code runs there. Some 49570ce93f4SNate Lawson * systems don't shutdown properly (i.e., ACPI power off) if we 49670ce93f4SNate Lawson * run on another processor. 49770ce93f4SNate Lawson */ 49835370593SAndriy Gapon if (!SCHEDULER_STOPPED()) { 499982d11f8SJeff Roberson thread_lock(curthread); 500efe67753SNathan Whitehorn sched_bind(curthread, CPU_FIRST()); 501982d11f8SJeff Roberson thread_unlock(curthread); 502efe67753SNathan Whitehorn KASSERT(PCPU_GET(cpuid) == CPU_FIRST(), 503800e7495SMitchell Horne ("%s: not running on cpu 0", __func__)); 50435370593SAndriy Gapon } 50520e25d7dSPeter Wemm #endif 50636a52c3cSJeff Roberson /* We're in the process of rebooting. */ 50736a52c3cSJeff Roberson rebooting = 1; 5085a8fceb3SMitchell Horne reboottrace(howto); 50920e25d7dSPeter Wemm 51061e96500SJohn Baldwin /* We are out of the debugger now. */ 5112d50560aSMarcel Moolenaar kdb_active = 0; 51261e96500SJohn Baldwin 5135230cfd2SJulian Elischer /* 5145230cfd2SJulian Elischer * Do any callouts that should be done BEFORE syncing the filesystems. 5155230cfd2SJulian Elischer */ 516fcb893a8SMike Smith EVENTHANDLER_INVOKE(shutdown_pre_sync, howto); 5175a8fceb3SMitchell Horne BOOTTRACE("shutdown pre sync complete"); 5185230cfd2SJulian Elischer 5195230cfd2SJulian Elischer /* 5205230cfd2SJulian Elischer * Now sync filesystems 5215230cfd2SJulian Elischer */ 52298082691SJeff Roberson if (!cold && (howto & RB_NOSYNC) == 0 && once == 0) { 52398082691SJeff Roberson once = 1; 5245a8fceb3SMitchell Horne BOOTTRACE("bufshutdown begin"); 52598082691SJeff Roberson bufshutdown(show_busybufs); 5265a8fceb3SMitchell Horne BOOTTRACE("bufshutdown end"); 527ad4240feSJulian Elischer } 5285230cfd2SJulian Elischer 52972dfe7a3SPoul-Henning Kamp print_uptime(); 53072dfe7a3SPoul-Henning Kamp 531bf8696b4SAndriy Gapon cngrab(); 532bf8696b4SAndriy Gapon 5335230cfd2SJulian Elischer /* 5345230cfd2SJulian Elischer * Ok, now do things that assume all filesystem activity has 5355230cfd2SJulian Elischer * been completed. 5365230cfd2SJulian Elischer */ 537fcb893a8SMike Smith EVENTHANDLER_INVOKE(shutdown_post_sync, howto); 5385a8fceb3SMitchell Horne BOOTTRACE("shutdown post sync complete"); 53970ce93f4SNate Lawson 540f6449d9dSJulian Elischer if ((howto & (RB_HALT|RB_DUMP)) == RB_DUMP && !cold && !dumping) 541299cceefSMarcel Moolenaar doadump(TRUE); 5422cfa0a03SJustin T. Gibbs 5432cfa0a03SJustin T. Gibbs /* Now that we're going to really halt the system... */ 5445a8fceb3SMitchell Horne BOOTTRACE("shutdown final begin"); 5455a8fceb3SMitchell Horne 5465a8fceb3SMitchell Horne if (shutdown_trace) 5475a8fceb3SMitchell Horne boottrace_dump_console(); 5485a8fceb3SMitchell Horne 549fcb893a8SMike Smith EVENTHANDLER_INVOKE(shutdown_final, howto); 5502cfa0a03SJustin T. Gibbs 551fcb893a8SMike Smith for(;;) ; /* safety against shutdown_reset not working */ 552fcb893a8SMike Smith /* NOTREACHED */ 553fcb893a8SMike Smith } 554fcb893a8SMike Smith 555fcb893a8SMike Smith /* 5560d3d0cc3SEdward Tomasz Napierala * The system call that results in changing the rootfs. 5570d3d0cc3SEdward Tomasz Napierala */ 5580d3d0cc3SEdward Tomasz Napierala static int 5590d3d0cc3SEdward Tomasz Napierala kern_reroot(void) 5600d3d0cc3SEdward Tomasz Napierala { 5610d3d0cc3SEdward Tomasz Napierala struct vnode *oldrootvnode, *vp; 5620d3d0cc3SEdward Tomasz Napierala struct mount *mp, *devmp; 5630d3d0cc3SEdward Tomasz Napierala int error; 5640d3d0cc3SEdward Tomasz Napierala 5650d3d0cc3SEdward Tomasz Napierala if (curproc != initproc) 5660d3d0cc3SEdward Tomasz Napierala return (EPERM); 5670d3d0cc3SEdward Tomasz Napierala 5680d3d0cc3SEdward Tomasz Napierala /* 5690d3d0cc3SEdward Tomasz Napierala * Mark the filesystem containing currently-running executable 5700d3d0cc3SEdward Tomasz Napierala * (the temporary copy of init(8)) busy. 5710d3d0cc3SEdward Tomasz Napierala */ 5720d3d0cc3SEdward Tomasz Napierala vp = curproc->p_textvp; 5730d3d0cc3SEdward Tomasz Napierala error = vn_lock(vp, LK_SHARED); 5740d3d0cc3SEdward Tomasz Napierala if (error != 0) 5750d3d0cc3SEdward Tomasz Napierala return (error); 5760d3d0cc3SEdward Tomasz Napierala mp = vp->v_mount; 5770d3d0cc3SEdward Tomasz Napierala error = vfs_busy(mp, MBF_NOWAIT); 5780d3d0cc3SEdward Tomasz Napierala if (error != 0) { 5790d3d0cc3SEdward Tomasz Napierala vfs_ref(mp); 580b249ce48SMateusz Guzik VOP_UNLOCK(vp); 5810d3d0cc3SEdward Tomasz Napierala error = vfs_busy(mp, 0); 5820d3d0cc3SEdward Tomasz Napierala vn_lock(vp, LK_SHARED | LK_RETRY); 5830d3d0cc3SEdward Tomasz Napierala vfs_rel(mp); 5840d3d0cc3SEdward Tomasz Napierala if (error != 0) { 585b249ce48SMateusz Guzik VOP_UNLOCK(vp); 5860d3d0cc3SEdward Tomasz Napierala return (ENOENT); 5870d3d0cc3SEdward Tomasz Napierala } 588abd80ddbSMateusz Guzik if (VN_IS_DOOMED(vp)) { 589b249ce48SMateusz Guzik VOP_UNLOCK(vp); 5900d3d0cc3SEdward Tomasz Napierala vfs_unbusy(mp); 5910d3d0cc3SEdward Tomasz Napierala return (ENOENT); 5920d3d0cc3SEdward Tomasz Napierala } 5930d3d0cc3SEdward Tomasz Napierala } 594b249ce48SMateusz Guzik VOP_UNLOCK(vp); 5950d3d0cc3SEdward Tomasz Napierala 5960d3d0cc3SEdward Tomasz Napierala /* 5970d3d0cc3SEdward Tomasz Napierala * Remove the filesystem containing currently-running executable 5980d3d0cc3SEdward Tomasz Napierala * from the mount list, to prevent it from being unmounted 5990d3d0cc3SEdward Tomasz Napierala * by vfs_unmountall(), and to avoid confusing vfs_mountroot(). 6000d3d0cc3SEdward Tomasz Napierala * 6010d3d0cc3SEdward Tomasz Napierala * Also preserve /dev - forcibly unmounting it could cause driver 6020d3d0cc3SEdward Tomasz Napierala * reinitialization. 6030d3d0cc3SEdward Tomasz Napierala */ 6040d3d0cc3SEdward Tomasz Napierala 6050d3d0cc3SEdward Tomasz Napierala vfs_ref(rootdevmp); 6060d3d0cc3SEdward Tomasz Napierala devmp = rootdevmp; 6070d3d0cc3SEdward Tomasz Napierala rootdevmp = NULL; 6080d3d0cc3SEdward Tomasz Napierala 6090d3d0cc3SEdward Tomasz Napierala mtx_lock(&mountlist_mtx); 6100d3d0cc3SEdward Tomasz Napierala TAILQ_REMOVE(&mountlist, mp, mnt_list); 6110d3d0cc3SEdward Tomasz Napierala TAILQ_REMOVE(&mountlist, devmp, mnt_list); 6120d3d0cc3SEdward Tomasz Napierala mtx_unlock(&mountlist_mtx); 6130d3d0cc3SEdward Tomasz Napierala 6140d3d0cc3SEdward Tomasz Napierala oldrootvnode = rootvnode; 6150d3d0cc3SEdward Tomasz Napierala 6160d3d0cc3SEdward Tomasz Napierala /* 6170d3d0cc3SEdward Tomasz Napierala * Unmount everything except for the two filesystems preserved above. 6180d3d0cc3SEdward Tomasz Napierala */ 6190d3d0cc3SEdward Tomasz Napierala vfs_unmountall(); 6200d3d0cc3SEdward Tomasz Napierala 6210d3d0cc3SEdward Tomasz Napierala /* 6220d3d0cc3SEdward Tomasz Napierala * Add /dev back; vfs_mountroot() will move it into its new place. 6230d3d0cc3SEdward Tomasz Napierala */ 6240d3d0cc3SEdward Tomasz Napierala mtx_lock(&mountlist_mtx); 6250d3d0cc3SEdward Tomasz Napierala TAILQ_INSERT_HEAD(&mountlist, devmp, mnt_list); 6260d3d0cc3SEdward Tomasz Napierala mtx_unlock(&mountlist_mtx); 6270d3d0cc3SEdward Tomasz Napierala rootdevmp = devmp; 6280d3d0cc3SEdward Tomasz Napierala vfs_rel(rootdevmp); 6290d3d0cc3SEdward Tomasz Napierala 6300d3d0cc3SEdward Tomasz Napierala /* 6310d3d0cc3SEdward Tomasz Napierala * Mount the new rootfs. 6320d3d0cc3SEdward Tomasz Napierala */ 6330d3d0cc3SEdward Tomasz Napierala vfs_mountroot(); 6340d3d0cc3SEdward Tomasz Napierala 6350d3d0cc3SEdward Tomasz Napierala /* 6360d3d0cc3SEdward Tomasz Napierala * Update all references to the old rootvnode. 6370d3d0cc3SEdward Tomasz Napierala */ 6380d3d0cc3SEdward Tomasz Napierala mountcheckdirs(oldrootvnode, rootvnode); 6390d3d0cc3SEdward Tomasz Napierala 6400d3d0cc3SEdward Tomasz Napierala /* 6410d3d0cc3SEdward Tomasz Napierala * Add the temporary filesystem back and unbusy it. 6420d3d0cc3SEdward Tomasz Napierala */ 6430d3d0cc3SEdward Tomasz Napierala mtx_lock(&mountlist_mtx); 6440d3d0cc3SEdward Tomasz Napierala TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); 6450d3d0cc3SEdward Tomasz Napierala mtx_unlock(&mountlist_mtx); 6460d3d0cc3SEdward Tomasz Napierala vfs_unbusy(mp); 6470d3d0cc3SEdward Tomasz Napierala 6480d3d0cc3SEdward Tomasz Napierala return (0); 6490d3d0cc3SEdward Tomasz Napierala } 6500d3d0cc3SEdward Tomasz Napierala 6510d3d0cc3SEdward Tomasz Napierala /* 652fcb893a8SMike Smith * If the shutdown was a clean halt, behave accordingly. 653fcb893a8SMike Smith */ 654fcb893a8SMike Smith static void 655fcb893a8SMike Smith shutdown_halt(void *junk, int howto) 656fcb893a8SMike Smith { 657e95499bdSAlfred Perlstein 658ad4240feSJulian Elischer if (howto & RB_HALT) { 659ad4240feSJulian Elischer printf("\n"); 660ad4240feSJulian Elischer printf("The operating system has halted.\n"); 661ad4240feSJulian Elischer printf("Please press any key to reboot.\n\n"); 662387df3b8SAndriy Gapon 663387df3b8SAndriy Gapon wdog_kern_pat(WD_TO_NEVER); 664387df3b8SAndriy Gapon 665d13d3630SJulian Elischer switch (cngetc()) { 666d13d3630SJulian Elischer case -1: /* No console, just die */ 667d13d3630SJulian Elischer cpu_halt(); 668d13d3630SJulian Elischer /* NOTREACHED */ 669d13d3630SJulian Elischer default: 670d13d3630SJulian Elischer break; 671d13d3630SJulian Elischer } 672fcb893a8SMike Smith } 673fcb893a8SMike Smith } 674ad4240feSJulian Elischer 675fcb893a8SMike Smith /* 676669d5ea4SGordon Bergling * Check to see if the system panicked, pause and then reboot 677fcb893a8SMike Smith * according to the specified delay. 678fcb893a8SMike Smith */ 679fcb893a8SMike Smith static void 680fcb893a8SMike Smith shutdown_panic(void *junk, int howto) 681fcb893a8SMike Smith { 682fcb893a8SMike Smith int loop; 683fcb893a8SMike Smith 684fcb893a8SMike Smith if (howto & RB_DUMP) { 6851cdbb9edSColin Percival if (panic_reboot_wait_time != 0) { 6861cdbb9edSColin Percival if (panic_reboot_wait_time != -1) { 6872cfa0a03SJustin T. Gibbs printf("Automatic reboot in %d seconds - " 6882cfa0a03SJustin T. Gibbs "press a key on the console to abort\n", 6891cdbb9edSColin Percival panic_reboot_wait_time); 6901cdbb9edSColin Percival for (loop = panic_reboot_wait_time * 10; 6912cfa0a03SJustin T. Gibbs loop > 0; --loop) { 692ad4240feSJulian Elischer DELAY(1000 * 100); /* 1/10th second */ 693a7f8f2abSBruce Evans /* Did user type a key? */ 694a7f8f2abSBruce Evans if (cncheckc() != -1) 695ad4240feSJulian Elischer break; 696ad4240feSJulian Elischer } 697ad4240feSJulian Elischer if (!loop) 698fcb893a8SMike Smith return; 699ad4240feSJulian Elischer } 700ad4240feSJulian Elischer } else { /* zero time specified - reboot NOW */ 701fcb893a8SMike Smith return; 702ad4240feSJulian Elischer } 703422702e9SNik Clayton printf("--> Press a key on the console to reboot,\n"); 704422702e9SNik Clayton printf("--> or switch off the system now.\n"); 705ad4240feSJulian Elischer cngetc(); 706ad4240feSJulian Elischer } 707fcb893a8SMike Smith } 708fcb893a8SMike Smith 709fcb893a8SMike Smith /* 710fcb893a8SMike Smith * Everything done, now reset 711fcb893a8SMike Smith */ 712fcb893a8SMike Smith static void 713fcb893a8SMike Smith shutdown_reset(void *junk, int howto) 714fcb893a8SMike Smith { 715e95499bdSAlfred Perlstein 716ad4240feSJulian Elischer printf("Rebooting...\n"); 717*84ec7df0SColin Percival DELAY(reboot_wait_time * 1000000); 718248bb937SAttilio Rao 719248bb937SAttilio Rao /* 720248bb937SAttilio Rao * Acquiring smp_ipi_mtx here has a double effect: 721248bb937SAttilio Rao * - it disables interrupts avoiding CPU0 preemption 722248bb937SAttilio Rao * by fast handlers (thus deadlocking against other CPUs) 723248bb937SAttilio Rao * - it avoids deadlocks against smp_rendezvous() or, more 724248bb937SAttilio Rao * generally, threads busy-waiting, with this spinlock held, 725248bb937SAttilio Rao * and waiting for responses by threads on other CPUs 726248bb937SAttilio Rao * (ie. smp_tlb_shootdown()). 7270a2d5feaSAttilio Rao * 7280a2d5feaSAttilio Rao * For the !SMP case it just needs to handle the former problem. 729248bb937SAttilio Rao */ 7300a2d5feaSAttilio Rao #ifdef SMP 731248bb937SAttilio Rao mtx_lock_spin(&smp_ipi_mtx); 7320a2d5feaSAttilio Rao #else 7330a2d5feaSAttilio Rao spinlock_enter(); 7340a2d5feaSAttilio Rao #endif 735248bb937SAttilio Rao 736ad4240feSJulian Elischer cpu_reset(); 737fcb893a8SMike Smith /* NOTREACHED */ /* assuming reset worked */ 738ad4240feSJulian Elischer } 739ad4240feSJulian Elischer 740a0d20ecbSGleb Smirnoff #if defined(WITNESS) || defined(INVARIANT_SUPPORT) 7413945a964SAlfred Perlstein static int kassert_warn_only = 0; 742a94053baSAlfred Perlstein #ifdef KDB 743a94053baSAlfred Perlstein static int kassert_do_kdb = 0; 744a94053baSAlfred Perlstein #endif 7453945a964SAlfred Perlstein #ifdef KTR 7463945a964SAlfred Perlstein static int kassert_do_ktr = 0; 7473945a964SAlfred Perlstein #endif 7483945a964SAlfred Perlstein static int kassert_do_log = 1; 7493945a964SAlfred Perlstein static int kassert_log_pps_limit = 4; 7503945a964SAlfred Perlstein static int kassert_log_mute_at = 0; 7513945a964SAlfred Perlstein static int kassert_log_panic_at = 0; 75218959b69SJonathan T. Looney static int kassert_suppress_in_panic = 0; 7533945a964SAlfred Perlstein static int kassert_warnings = 0; 7543945a964SAlfred Perlstein 7557029da5cSPawel Biernacki SYSCTL_NODE(_debug, OID_AUTO, kassert, CTLFLAG_RW | CTLFLAG_MPSAFE, NULL, 7567029da5cSPawel Biernacki "kassert options"); 7573945a964SAlfred Perlstein 7584ca8c1efSConrad Meyer #ifdef KASSERT_PANIC_OPTIONAL 7594ca8c1efSConrad Meyer #define KASSERT_RWTUN CTLFLAG_RWTUN 7604ca8c1efSConrad Meyer #else 7614ca8c1efSConrad Meyer #define KASSERT_RWTUN CTLFLAG_RDTUN 7624ca8c1efSConrad Meyer #endif 7634ca8c1efSConrad Meyer 7644ca8c1efSConrad Meyer SYSCTL_INT(_debug_kassert, OID_AUTO, warn_only, KASSERT_RWTUN, 7653945a964SAlfred Perlstein &kassert_warn_only, 0, 7664ca8c1efSConrad Meyer "KASSERT triggers a panic (0) or just a warning (1)"); 7673945a964SAlfred Perlstein 768a94053baSAlfred Perlstein #ifdef KDB 7694ca8c1efSConrad Meyer SYSCTL_INT(_debug_kassert, OID_AUTO, do_kdb, KASSERT_RWTUN, 770a94053baSAlfred Perlstein &kassert_do_kdb, 0, "KASSERT will enter the debugger"); 771a94053baSAlfred Perlstein #endif 772a94053baSAlfred Perlstein 7733945a964SAlfred Perlstein #ifdef KTR 7744ca8c1efSConrad Meyer SYSCTL_UINT(_debug_kassert, OID_AUTO, do_ktr, KASSERT_RWTUN, 7753945a964SAlfred Perlstein &kassert_do_ktr, 0, 7763945a964SAlfred Perlstein "KASSERT does a KTR, set this to the KTRMASK you want"); 7773945a964SAlfred Perlstein #endif 7783945a964SAlfred Perlstein 7794ca8c1efSConrad Meyer SYSCTL_INT(_debug_kassert, OID_AUTO, do_log, KASSERT_RWTUN, 78007aa6ea6SConrad Meyer &kassert_do_log, 0, 78107aa6ea6SConrad Meyer "If warn_only is enabled, log (1) or do not log (0) assertion violations"); 7823945a964SAlfred Perlstein 7833ad1ce46SAndriy Gapon SYSCTL_INT(_debug_kassert, OID_AUTO, warnings, CTLFLAG_RD | CTLFLAG_STATS, 7843945a964SAlfred Perlstein &kassert_warnings, 0, "number of KASSERTs that have been triggered"); 7853945a964SAlfred Perlstein 7864ca8c1efSConrad Meyer SYSCTL_INT(_debug_kassert, OID_AUTO, log_panic_at, KASSERT_RWTUN, 7873945a964SAlfred Perlstein &kassert_log_panic_at, 0, "max number of KASSERTS before we will panic"); 7883945a964SAlfred Perlstein 7894ca8c1efSConrad Meyer SYSCTL_INT(_debug_kassert, OID_AUTO, log_pps_limit, KASSERT_RWTUN, 7903945a964SAlfred Perlstein &kassert_log_pps_limit, 0, "limit number of log messages per second"); 7913945a964SAlfred Perlstein 7924ca8c1efSConrad Meyer SYSCTL_INT(_debug_kassert, OID_AUTO, log_mute_at, KASSERT_RWTUN, 7933945a964SAlfred Perlstein &kassert_log_mute_at, 0, "max number of KASSERTS to log"); 7943945a964SAlfred Perlstein 7954ca8c1efSConrad Meyer SYSCTL_INT(_debug_kassert, OID_AUTO, suppress_in_panic, KASSERT_RWTUN, 79644b71282SJonathan T. Looney &kassert_suppress_in_panic, 0, 79744b71282SJonathan T. Looney "KASSERTs will be suppressed while handling a panic"); 7984ca8c1efSConrad Meyer #undef KASSERT_RWTUN 79944b71282SJonathan T. Looney 8003945a964SAlfred Perlstein static int kassert_sysctl_kassert(SYSCTL_HANDLER_ARGS); 8013945a964SAlfred Perlstein 8023945a964SAlfred Perlstein SYSCTL_PROC(_debug_kassert, OID_AUTO, kassert, 80367f508dbSAlexander Motin CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE | CTLFLAG_MPSAFE, NULL, 0, 8047029da5cSPawel Biernacki kassert_sysctl_kassert, "I", 8057029da5cSPawel Biernacki "set to trigger a test kassert"); 8063945a964SAlfred Perlstein 8073945a964SAlfred Perlstein static int 8083945a964SAlfred Perlstein kassert_sysctl_kassert(SYSCTL_HANDLER_ARGS) 8093945a964SAlfred Perlstein { 8103945a964SAlfred Perlstein int error, i; 8113945a964SAlfred Perlstein 8123945a964SAlfred Perlstein error = sysctl_wire_old_buffer(req, sizeof(int)); 8133945a964SAlfred Perlstein if (error == 0) { 8143945a964SAlfred Perlstein i = 0; 8153945a964SAlfred Perlstein error = sysctl_handle_int(oidp, &i, 0, req); 8163945a964SAlfred Perlstein } 8173945a964SAlfred Perlstein if (error != 0 || req->newptr == NULL) 8183945a964SAlfred Perlstein return (error); 8193945a964SAlfred Perlstein KASSERT(0, ("kassert_sysctl_kassert triggered kassert %d", i)); 8203945a964SAlfred Perlstein return (0); 8213945a964SAlfred Perlstein } 8223945a964SAlfred Perlstein 8234ca8c1efSConrad Meyer #ifdef KASSERT_PANIC_OPTIONAL 8243945a964SAlfred Perlstein /* 8253945a964SAlfred Perlstein * Called by KASSERT, this decides if we will panic 8263945a964SAlfred Perlstein * or if we will log via printf and/or ktr. 8273945a964SAlfred Perlstein */ 8283945a964SAlfred Perlstein void 8293945a964SAlfred Perlstein kassert_panic(const char *fmt, ...) 8303945a964SAlfred Perlstein { 8313945a964SAlfred Perlstein static char buf[256]; 8323945a964SAlfred Perlstein va_list ap; 8333945a964SAlfred Perlstein 8343945a964SAlfred Perlstein va_start(ap, fmt); 8353945a964SAlfred Perlstein (void)vsnprintf(buf, sizeof(buf), fmt, ap); 8363945a964SAlfred Perlstein va_end(ap); 8373945a964SAlfred Perlstein 8383945a964SAlfred Perlstein /* 83965df1248SConrad Meyer * If we are suppressing secondary panics, log the warning but do not 84065df1248SConrad Meyer * re-enter panic/kdb. 84165df1248SConrad Meyer */ 84235eb9b10SMitchell Horne if (KERNEL_PANICKED() && kassert_suppress_in_panic) { 84365df1248SConrad Meyer if (kassert_do_log) { 84465df1248SConrad Meyer printf("KASSERT failed: %s\n", buf); 84565df1248SConrad Meyer #ifdef KDB 84665df1248SConrad Meyer if (trace_all_panics && trace_on_panic) 84765df1248SConrad Meyer kdb_backtrace(); 84865df1248SConrad Meyer #endif 84965df1248SConrad Meyer } 85065df1248SConrad Meyer return; 85165df1248SConrad Meyer } 85265df1248SConrad Meyer 85365df1248SConrad Meyer /* 8543945a964SAlfred Perlstein * panic if we're not just warning, or if we've exceeded 8553945a964SAlfred Perlstein * kassert_log_panic_at warnings. 8563945a964SAlfred Perlstein */ 8573945a964SAlfred Perlstein if (!kassert_warn_only || 8583945a964SAlfred Perlstein (kassert_log_panic_at > 0 && 8593945a964SAlfred Perlstein kassert_warnings >= kassert_log_panic_at)) { 8603945a964SAlfred Perlstein va_start(ap, fmt); 8613945a964SAlfred Perlstein vpanic(fmt, ap); 8623945a964SAlfred Perlstein /* NORETURN */ 8633945a964SAlfred Perlstein } 8643945a964SAlfred Perlstein #ifdef KTR 8653945a964SAlfred Perlstein if (kassert_do_ktr) 8663945a964SAlfred Perlstein CTR0(ktr_mask, buf); 8673945a964SAlfred Perlstein #endif /* KTR */ 8683945a964SAlfred Perlstein /* 8693945a964SAlfred Perlstein * log if we've not yet met the mute limit. 8703945a964SAlfred Perlstein */ 8713945a964SAlfred Perlstein if (kassert_do_log && 8723945a964SAlfred Perlstein (kassert_log_mute_at == 0 || 8733945a964SAlfred Perlstein kassert_warnings < kassert_log_mute_at)) { 8743945a964SAlfred Perlstein static struct timeval lasterr; 8753945a964SAlfred Perlstein static int curerr; 8763945a964SAlfred Perlstein 8773945a964SAlfred Perlstein if (ppsratecheck(&lasterr, &curerr, kassert_log_pps_limit)) { 8783945a964SAlfred Perlstein printf("KASSERT failed: %s\n", buf); 8793945a964SAlfred Perlstein kdb_backtrace(); 8803945a964SAlfred Perlstein } 8813945a964SAlfred Perlstein } 882a94053baSAlfred Perlstein #ifdef KDB 883a94053baSAlfred Perlstein if (kassert_do_kdb) { 884a94053baSAlfred Perlstein kdb_enter(KDB_WHY_KASSERT, buf); 885a94053baSAlfred Perlstein } 886a94053baSAlfred Perlstein #endif 8873945a964SAlfred Perlstein atomic_add_int(&kassert_warnings, 1); 8883945a964SAlfred Perlstein } 8894ca8c1efSConrad Meyer #endif /* KASSERT_PANIC_OPTIONAL */ 8903945a964SAlfred Perlstein #endif 8913945a964SAlfred Perlstein 892ad4240feSJulian Elischer /* 893ad4240feSJulian Elischer * Panic is called on unresolvable fatal errors. It prints "panic: mesg", 894ad4240feSJulian Elischer * and then reboots. If we are called twice, then we avoid trying to sync 895ad4240feSJulian Elischer * the disks as this often leads to recursive panics. 896ad4240feSJulian Elischer */ 897ad4240feSJulian Elischer void 8989a6dc4b6SPoul-Henning Kamp panic(const char *fmt, ...) 899ad4240feSJulian Elischer { 9003945a964SAlfred Perlstein va_list ap; 9013945a964SAlfred Perlstein 9023945a964SAlfred Perlstein va_start(ap, fmt); 9033945a964SAlfred Perlstein vpanic(fmt, ap); 9043945a964SAlfred Perlstein } 9053945a964SAlfred Perlstein 906da10a603SMark Johnston void 9073945a964SAlfred Perlstein vpanic(const char *fmt, va_list ap) 9083945a964SAlfred Perlstein { 90964dd590eSAndriy Gapon #ifdef SMP 91035370593SAndriy Gapon cpuset_t other_cpus; 91164dd590eSAndriy Gapon #endif 912fe799533SAndrew Gallatin struct thread *td = curthread; 913e485b64bSJohn Baldwin int bootopt, newpanic; 91499237364SAndrey A. Chernov static char buf[256]; 915ad4240feSJulian Elischer 91635370593SAndriy Gapon spinlock_enter(); 91735370593SAndriy Gapon 9180384fff8SJason Evans #ifdef SMP 9191a5333c3SJohn Baldwin /* 9206898bee9SAndriy Gapon * stop_cpus_hard(other_cpus) should prevent multiple CPUs from 9216898bee9SAndriy Gapon * concurrently entering panic. Only the winner will proceed 9226898bee9SAndriy Gapon * further. 9231a5333c3SJohn Baldwin */ 92435370593SAndriy Gapon if (panicstr == NULL && !kdb_active) { 92535370593SAndriy Gapon other_cpus = all_cpus; 92635370593SAndriy Gapon CPU_CLR(PCPU_GET(cpuid), &other_cpus); 92735370593SAndriy Gapon stop_cpus_hard(other_cpus); 92835370593SAndriy Gapon } 92942d33c1fSMark Johnston #endif 93035370593SAndriy Gapon 93135370593SAndriy Gapon /* 9329ad64f27SMark Johnston * Ensure that the scheduler is stopped while panicking, even if panic 9339ad64f27SMark Johnston * has been entered from kdb. 93435370593SAndriy Gapon */ 9355d7380f8SAttilio Rao td->td_stopsched = 1; 9360384fff8SJason Evans 937e3adb685SAttilio Rao bootopt = RB_AUTOBOOT; 938e485b64bSJohn Baldwin newpanic = 0; 93935eb9b10SMitchell Horne if (KERNEL_PANICKED()) 940ad4240feSJulian Elischer bootopt |= RB_NOSYNC; 941e485b64bSJohn Baldwin else { 942e3adb685SAttilio Rao bootopt |= RB_DUMP; 943ad4240feSJulian Elischer panicstr = fmt; 944d199ad3bSMateusz Guzik panicked = true; 945e485b64bSJohn Baldwin newpanic = 1; 946e485b64bSJohn Baldwin } 947ad4240feSJulian Elischer 9484f1b4577SIan Dowse if (newpanic) { 9492127f260SArchie Cobbs (void)vsnprintf(buf, sizeof(buf), fmt, ap); 95099237364SAndrey A. Chernov panicstr = buf; 951bf8696b4SAndriy Gapon cngrab(); 9529a6dc4b6SPoul-Henning Kamp printf("panic: %s\n", buf); 9534f1b4577SIan Dowse } else { 9544f1b4577SIan Dowse printf("panic: "); 9554f1b4577SIan Dowse vprintf(fmt, ap); 9569a6dc4b6SPoul-Henning Kamp printf("\n"); 9574f1b4577SIan Dowse } 95847d81897SSteve Passe #ifdef SMP 95955c45354SJohn Baldwin printf("cpuid = %d\n", PCPU_GET(cpuid)); 9602bcc63c5SJohn Baldwin #endif 9616cf0c1dbSGleb Smirnoff printf("time = %jd\n", (intmax_t )time_second); 9622d50560aSMarcel Moolenaar #ifdef KDB 963ad1fc315SConrad Meyer if ((newpanic || trace_all_panics) && trace_on_panic) 9642d50560aSMarcel Moolenaar kdb_backtrace(); 965ad4240feSJulian Elischer if (debugger_on_panic) 9663de213ccSRobert Watson kdb_enter(KDB_WHY_PANIC, "panic"); 967c8a96cdcSMitchell Horne else if (!newpanic && debugger_on_recursive_panic) 968c8a96cdcSMitchell Horne kdb_enter(KDB_WHY_PANIC, "re-panic"); 9691432aa0cSJohn Baldwin #endif 970982d11f8SJeff Roberson /*thread_lock(td); */ 971fe799533SAndrew Gallatin td->td_flags |= TDF_INPANIC; 972982d11f8SJeff Roberson /* thread_unlock(td); */ 973259ed917SPeter Wemm if (!sync_on_panic) 974259ed917SPeter Wemm bootopt |= RB_NOSYNC; 97548f1a492SWarner Losh if (poweroff_on_panic) 97648f1a492SWarner Losh bootopt |= RB_POWEROFF; 97748f1a492SWarner Losh if (powercycle_on_panic) 97848f1a492SWarner Losh bootopt |= RB_POWERCYCLE; 97976e18b25SMarcel Moolenaar kern_reboot(bootopt); 980ad4240feSJulian Elischer } 981ad4240feSJulian Elischer 982e0d898b4SJulian Elischer /* 983db82a982SMike Smith * Support for poweroff delay. 984b22692bdSNick Hibma * 985b22692bdSNick Hibma * Please note that setting this delay too short might power off your machine 986b22692bdSNick Hibma * before the write cache on your hard disk has been flushed, leading to 987b22692bdSNick Hibma * soft-updates inconsistencies. 988db82a982SMike Smith */ 9899eec6969SMike Smith #ifndef POWEROFF_DELAY 9909eec6969SMike Smith # define POWEROFF_DELAY 5000 9919eec6969SMike Smith #endif 9929eec6969SMike Smith static int poweroff_delay = POWEROFF_DELAY; 9939eec6969SMike Smith 994db82a982SMike Smith SYSCTL_INT(_kern_shutdown, OID_AUTO, poweroff_delay, CTLFLAG_RW, 9953eb9ab52SEitan Adler &poweroff_delay, 0, "Delay before poweroff to write disk caches (msec)"); 996db82a982SMike Smith 997fcb893a8SMike Smith static void 998fcb893a8SMike Smith poweroff_wait(void *junk, int howto) 999db82a982SMike Smith { 1000e95499bdSAlfred Perlstein 10017d41b6f0SWarner Losh if ((howto & (RB_POWEROFF | RB_POWERCYCLE)) == 0 || poweroff_delay <= 0) 1002db82a982SMike Smith return; 1003db82a982SMike Smith DELAY(poweroff_delay * 1000); 1004db82a982SMike Smith } 10055e950839SLuoqi Chen 10065e950839SLuoqi Chen /* 10075e950839SLuoqi Chen * Some system processes (e.g. syncer) need to be stopped at appropriate 10085e950839SLuoqi Chen * points in their main loops prior to a system shutdown, so that they 10095e950839SLuoqi Chen * won't interfere with the shutdown process (e.g. by holding a disk buf 10105e950839SLuoqi Chen * to cause sync to fail). For each of these system processes, register 10115e950839SLuoqi Chen * shutdown_kproc() as a handler for one of shutdown events. 10125e950839SLuoqi Chen */ 10135e950839SLuoqi Chen static int kproc_shutdown_wait = 60; 10145e950839SLuoqi Chen SYSCTL_INT(_kern_shutdown, OID_AUTO, kproc_shutdown_wait, CTLFLAG_RW, 10153eb9ab52SEitan Adler &kproc_shutdown_wait, 0, "Max wait time (sec) to stop for each process"); 10165e950839SLuoqi Chen 10175e950839SLuoqi Chen void 1018ffc831daSJohn Baldwin kproc_shutdown(void *arg, int howto) 10195e950839SLuoqi Chen { 10205e950839SLuoqi Chen struct proc *p; 10215e950839SLuoqi Chen int error; 10225e950839SLuoqi Chen 102335eb9b10SMitchell Horne if (KERNEL_PANICKED()) 10245e950839SLuoqi Chen return; 10255e950839SLuoqi Chen 10265e950839SLuoqi Chen p = (struct proc *)arg; 1027b1c81391SNate Lawson printf("Waiting (max %d seconds) for system process `%s' to stop... ", 10284f9d48e4SJohn Baldwin kproc_shutdown_wait, p->p_comm); 10293745c395SJulian Elischer error = kproc_suspend(p, kproc_shutdown_wait * hz); 10305e950839SLuoqi Chen 10315e950839SLuoqi Chen if (error == EWOULDBLOCK) 1032b1c81391SNate Lawson printf("timed out\n"); 10335e950839SLuoqi Chen else 1034b1c81391SNate Lawson printf("done\n"); 10355e950839SLuoqi Chen } 103681661c94SPoul-Henning Kamp 10377ab24ea3SJulian Elischer void 10387ab24ea3SJulian Elischer kthread_shutdown(void *arg, int howto) 10397ab24ea3SJulian Elischer { 10407ab24ea3SJulian Elischer struct thread *td; 10417ab24ea3SJulian Elischer int error; 10427ab24ea3SJulian Elischer 104335eb9b10SMitchell Horne if (KERNEL_PANICKED()) 10447ab24ea3SJulian Elischer return; 10457ab24ea3SJulian Elischer 10467ab24ea3SJulian Elischer td = (struct thread *)arg; 10477ab24ea3SJulian Elischer printf("Waiting (max %d seconds) for system thread `%s' to stop... ", 10484f9d48e4SJohn Baldwin kproc_shutdown_wait, td->td_name); 10497ab24ea3SJulian Elischer error = kthread_suspend(td, kproc_shutdown_wait * hz); 10507ab24ea3SJulian Elischer 10517ab24ea3SJulian Elischer if (error == EWOULDBLOCK) 10527ab24ea3SJulian Elischer printf("timed out\n"); 10537ab24ea3SJulian Elischer else 10547ab24ea3SJulian Elischer printf("done\n"); 10557ab24ea3SJulian Elischer } 10567ab24ea3SJulian Elischer 10576b6e2954SConrad Meyer static int 10586b6e2954SConrad Meyer dumpdevname_sysctl_handler(SYSCTL_HANDLER_ARGS) 10596b6e2954SConrad Meyer { 10606b6e2954SConrad Meyer char buf[256]; 10616b6e2954SConrad Meyer struct dumperinfo *di; 10626b6e2954SConrad Meyer struct sbuf sb; 10636b6e2954SConrad Meyer int error; 10646b6e2954SConrad Meyer 10656b6e2954SConrad Meyer error = sysctl_wire_old_buffer(req, 0); 10666b6e2954SConrad Meyer if (error != 0) 10676b6e2954SConrad Meyer return (error); 10686b6e2954SConrad Meyer 10696b6e2954SConrad Meyer sbuf_new_for_sysctl(&sb, buf, sizeof(buf), req); 10706b6e2954SConrad Meyer 10716b6e2954SConrad Meyer mtx_lock(&dumpconf_list_lk); 10726b6e2954SConrad Meyer TAILQ_FOREACH(di, &dumper_configs, di_next) { 10736b6e2954SConrad Meyer if (di != TAILQ_FIRST(&dumper_configs)) 10746b6e2954SConrad Meyer sbuf_putc(&sb, ','); 10756b6e2954SConrad Meyer sbuf_cat(&sb, di->di_devname); 10766b6e2954SConrad Meyer } 10776b6e2954SConrad Meyer mtx_unlock(&dumpconf_list_lk); 10786b6e2954SConrad Meyer 10796b6e2954SConrad Meyer error = sbuf_finish(&sb); 10806b6e2954SConrad Meyer sbuf_delete(&sb); 10816b6e2954SConrad Meyer return (error); 10826b6e2954SConrad Meyer } 10837029da5cSPawel Biernacki SYSCTL_PROC(_kern_shutdown, OID_AUTO, dumpdevname, 108467f508dbSAlexander Motin CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, &dumper_configs, 0, 10857029da5cSPawel Biernacki dumpdevname_sysctl_handler, "A", 10866b6e2954SConrad Meyer "Device(s) for kernel dumps"); 1087bad7e7f3SAlfred Perlstein 1088db71383bSMitchell Horne static int _dump_append(struct dumperinfo *di, void *virtual, size_t length); 108964a16434SMark Johnston 1090480f31c2SKonrad Witaszczyk #ifdef EKCD 1091480f31c2SKonrad Witaszczyk static struct kerneldumpcrypto * 1092480f31c2SKonrad Witaszczyk kerneldumpcrypto_create(size_t blocksize, uint8_t encryption, 1093480f31c2SKonrad Witaszczyk const uint8_t *key, uint32_t encryptedkeysize, const uint8_t *encryptedkey) 1094480f31c2SKonrad Witaszczyk { 1095480f31c2SKonrad Witaszczyk struct kerneldumpcrypto *kdc; 1096480f31c2SKonrad Witaszczyk struct kerneldumpkey *kdk; 1097480f31c2SKonrad Witaszczyk uint32_t dumpkeysize; 1098480f31c2SKonrad Witaszczyk 1099480f31c2SKonrad Witaszczyk dumpkeysize = roundup2(sizeof(*kdk) + encryptedkeysize, blocksize); 1100480f31c2SKonrad Witaszczyk kdc = malloc(sizeof(*kdc) + dumpkeysize, M_EKCD, M_WAITOK | M_ZERO); 1101480f31c2SKonrad Witaszczyk 1102480f31c2SKonrad Witaszczyk arc4rand(kdc->kdc_iv, sizeof(kdc->kdc_iv), 0); 1103480f31c2SKonrad Witaszczyk 1104480f31c2SKonrad Witaszczyk kdc->kdc_encryption = encryption; 1105480f31c2SKonrad Witaszczyk switch (kdc->kdc_encryption) { 1106480f31c2SKonrad Witaszczyk case KERNELDUMP_ENC_AES_256_CBC: 1107480f31c2SKonrad Witaszczyk if (rijndael_makeKey(&kdc->kdc_ki, DIR_ENCRYPT, 256, key) <= 0) 1108480f31c2SKonrad Witaszczyk goto failed; 1109480f31c2SKonrad Witaszczyk break; 111082985292SConrad Meyer case KERNELDUMP_ENC_CHACHA20: 111182985292SConrad Meyer chacha_keysetup(&kdc->kdc_chacha, key, 256); 111282985292SConrad Meyer break; 1113480f31c2SKonrad Witaszczyk default: 1114480f31c2SKonrad Witaszczyk goto failed; 1115480f31c2SKonrad Witaszczyk } 1116480f31c2SKonrad Witaszczyk 1117480f31c2SKonrad Witaszczyk kdc->kdc_dumpkeysize = dumpkeysize; 1118480f31c2SKonrad Witaszczyk kdk = kdc->kdc_dumpkey; 1119480f31c2SKonrad Witaszczyk kdk->kdk_encryption = kdc->kdc_encryption; 1120480f31c2SKonrad Witaszczyk memcpy(kdk->kdk_iv, kdc->kdc_iv, sizeof(kdk->kdk_iv)); 1121480f31c2SKonrad Witaszczyk kdk->kdk_encryptedkeysize = htod32(encryptedkeysize); 1122480f31c2SKonrad Witaszczyk memcpy(kdk->kdk_encryptedkey, encryptedkey, encryptedkeysize); 1123480f31c2SKonrad Witaszczyk 1124480f31c2SKonrad Witaszczyk return (kdc); 1125480f31c2SKonrad Witaszczyk failed: 11264a711b8dSJohn Baldwin zfree(kdc, M_EKCD); 1127480f31c2SKonrad Witaszczyk return (NULL); 1128480f31c2SKonrad Witaszczyk } 1129480f31c2SKonrad Witaszczyk 113050ef60daSMark Johnston static int 1131480f31c2SKonrad Witaszczyk kerneldumpcrypto_init(struct kerneldumpcrypto *kdc) 1132480f31c2SKonrad Witaszczyk { 1133480f31c2SKonrad Witaszczyk uint8_t hash[SHA256_DIGEST_LENGTH]; 1134480f31c2SKonrad Witaszczyk SHA256_CTX ctx; 1135480f31c2SKonrad Witaszczyk struct kerneldumpkey *kdk; 1136480f31c2SKonrad Witaszczyk int error; 1137480f31c2SKonrad Witaszczyk 1138480f31c2SKonrad Witaszczyk error = 0; 1139480f31c2SKonrad Witaszczyk 1140480f31c2SKonrad Witaszczyk if (kdc == NULL) 1141480f31c2SKonrad Witaszczyk return (0); 1142480f31c2SKonrad Witaszczyk 1143480f31c2SKonrad Witaszczyk /* 1144480f31c2SKonrad Witaszczyk * When a user enters ddb it can write a crash dump multiple times. 1145480f31c2SKonrad Witaszczyk * Each time it should be encrypted using a different IV. 1146480f31c2SKonrad Witaszczyk */ 1147480f31c2SKonrad Witaszczyk SHA256_Init(&ctx); 1148480f31c2SKonrad Witaszczyk SHA256_Update(&ctx, kdc->kdc_iv, sizeof(kdc->kdc_iv)); 1149480f31c2SKonrad Witaszczyk SHA256_Final(hash, &ctx); 1150480f31c2SKonrad Witaszczyk bcopy(hash, kdc->kdc_iv, sizeof(kdc->kdc_iv)); 1151480f31c2SKonrad Witaszczyk 1152480f31c2SKonrad Witaszczyk switch (kdc->kdc_encryption) { 1153480f31c2SKonrad Witaszczyk case KERNELDUMP_ENC_AES_256_CBC: 1154480f31c2SKonrad Witaszczyk if (rijndael_cipherInit(&kdc->kdc_ci, MODE_CBC, 1155480f31c2SKonrad Witaszczyk kdc->kdc_iv) <= 0) { 1156480f31c2SKonrad Witaszczyk error = EINVAL; 1157480f31c2SKonrad Witaszczyk goto out; 1158480f31c2SKonrad Witaszczyk } 1159480f31c2SKonrad Witaszczyk break; 116082985292SConrad Meyer case KERNELDUMP_ENC_CHACHA20: 116182985292SConrad Meyer chacha_ivsetup(&kdc->kdc_chacha, kdc->kdc_iv, NULL); 116282985292SConrad Meyer break; 1163480f31c2SKonrad Witaszczyk default: 1164480f31c2SKonrad Witaszczyk error = EINVAL; 1165480f31c2SKonrad Witaszczyk goto out; 1166480f31c2SKonrad Witaszczyk } 1167480f31c2SKonrad Witaszczyk 1168480f31c2SKonrad Witaszczyk kdk = kdc->kdc_dumpkey; 1169480f31c2SKonrad Witaszczyk memcpy(kdk->kdk_iv, kdc->kdc_iv, sizeof(kdk->kdk_iv)); 1170480f31c2SKonrad Witaszczyk out: 1171480f31c2SKonrad Witaszczyk explicit_bzero(hash, sizeof(hash)); 1172480f31c2SKonrad Witaszczyk return (error); 1173480f31c2SKonrad Witaszczyk } 1174480f31c2SKonrad Witaszczyk 117501938d36SMark Johnston static uint32_t 1176480f31c2SKonrad Witaszczyk kerneldumpcrypto_dumpkeysize(const struct kerneldumpcrypto *kdc) 1177480f31c2SKonrad Witaszczyk { 1178480f31c2SKonrad Witaszczyk 1179480f31c2SKonrad Witaszczyk if (kdc == NULL) 1180480f31c2SKonrad Witaszczyk return (0); 1181480f31c2SKonrad Witaszczyk return (kdc->kdc_dumpkeysize); 1182480f31c2SKonrad Witaszczyk } 118301938d36SMark Johnston #endif /* EKCD */ 1184480f31c2SKonrad Witaszczyk 118578f57a9cSMark Johnston static struct kerneldumpcomp * 118678f57a9cSMark Johnston kerneldumpcomp_create(struct dumperinfo *di, uint8_t compression) 118764a16434SMark Johnston { 118878f57a9cSMark Johnston struct kerneldumpcomp *kdcomp; 11896026dcd7SMark Johnston int format; 119064a16434SMark Johnston 11916026dcd7SMark Johnston switch (compression) { 11926026dcd7SMark Johnston case KERNELDUMP_COMP_GZIP: 11936026dcd7SMark Johnston format = COMPRESS_GZIP; 11946026dcd7SMark Johnston break; 11956026dcd7SMark Johnston case KERNELDUMP_COMP_ZSTD: 11966026dcd7SMark Johnston format = COMPRESS_ZSTD; 11976026dcd7SMark Johnston break; 11986026dcd7SMark Johnston default: 119964a16434SMark Johnston return (NULL); 12006026dcd7SMark Johnston } 12016026dcd7SMark Johnston 120278f57a9cSMark Johnston kdcomp = malloc(sizeof(*kdcomp), M_DUMPER, M_WAITOK | M_ZERO); 12036026dcd7SMark Johnston kdcomp->kdc_format = compression; 120478f57a9cSMark Johnston kdcomp->kdc_stream = compressor_init(kerneldumpcomp_write_cb, 12056026dcd7SMark Johnston format, di->maxiosize, kerneldump_gzlevel, di); 120678f57a9cSMark Johnston if (kdcomp->kdc_stream == NULL) { 120778f57a9cSMark Johnston free(kdcomp, M_DUMPER); 120864a16434SMark Johnston return (NULL); 120964a16434SMark Johnston } 121078f57a9cSMark Johnston kdcomp->kdc_buf = malloc(di->maxiosize, M_DUMPER, M_WAITOK | M_NODUMP); 121178f57a9cSMark Johnston return (kdcomp); 121264a16434SMark Johnston } 121364a16434SMark Johnston 121464a16434SMark Johnston static void 121578f57a9cSMark Johnston kerneldumpcomp_destroy(struct dumperinfo *di) 121664a16434SMark Johnston { 121778f57a9cSMark Johnston struct kerneldumpcomp *kdcomp; 121864a16434SMark Johnston 121978f57a9cSMark Johnston kdcomp = di->kdcomp; 122078f57a9cSMark Johnston if (kdcomp == NULL) 122164a16434SMark Johnston return; 122278f57a9cSMark Johnston compressor_fini(kdcomp->kdc_stream); 12234a711b8dSJohn Baldwin zfree(kdcomp->kdc_buf, M_DUMPER); 122478f57a9cSMark Johnston free(kdcomp, M_DUMPER); 122564a16434SMark Johnston } 122664a16434SMark Johnston 12276b6e2954SConrad Meyer /* 122859c27ea1SMitchell Horne * Free a dumper. Must not be present on global list. 12296b6e2954SConrad Meyer */ 123059c27ea1SMitchell Horne void 123159c27ea1SMitchell Horne dumper_destroy(struct dumperinfo *di) 12326b6e2954SConrad Meyer { 12336b6e2954SConrad Meyer 12346b6e2954SConrad Meyer if (di == NULL) 12356b6e2954SConrad Meyer return; 12366b6e2954SConrad Meyer 12374a711b8dSJohn Baldwin zfree(di->blockbuf, M_DUMPER); 12386b6e2954SConrad Meyer kerneldumpcomp_destroy(di); 12396b6e2954SConrad Meyer #ifdef EKCD 12404a711b8dSJohn Baldwin zfree(di->kdcrypto, M_EKCD); 12416b6e2954SConrad Meyer #endif 12424a711b8dSJohn Baldwin zfree(di, M_DUMPER); 12436b6e2954SConrad Meyer } 12446b6e2954SConrad Meyer 124559c27ea1SMitchell Horne /* 124659c27ea1SMitchell Horne * Allocate and set up a new dumper from the provided template. 124759c27ea1SMitchell Horne */ 124881661c94SPoul-Henning Kamp int 124959c27ea1SMitchell Horne dumper_create(const struct dumperinfo *di_template, const char *devname, 125059c27ea1SMitchell Horne const struct diocskerneldump_arg *kda, struct dumperinfo **dip) 125181661c94SPoul-Henning Kamp { 125259c27ea1SMitchell Horne struct dumperinfo *newdi; 125359c27ea1SMitchell Horne int error = 0; 12545ebb15b9SPawel Jakub Dawidek 125559c27ea1SMitchell Horne if (dip == NULL) 125659c27ea1SMitchell Horne return (EINVAL); 12576b6e2954SConrad Meyer 125859c27ea1SMitchell Horne /* Allocate a new dumper */ 125959c27ea1SMitchell Horne newdi = malloc(sizeof(*newdi) + strlen(devname) + 1, M_DUMPER, 126059c27ea1SMitchell Horne M_WAITOK | M_ZERO); 12616b6e2954SConrad Meyer memcpy(newdi, di_template, sizeof(*newdi)); 12626b6e2954SConrad Meyer newdi->blockbuf = NULL; 12636b6e2954SConrad Meyer newdi->kdcrypto = NULL; 12646b6e2954SConrad Meyer newdi->kdcomp = NULL; 12656b6e2954SConrad Meyer strcpy(newdi->di_devname, devname); 1266480f31c2SKonrad Witaszczyk 12676b6e2954SConrad Meyer if (kda->kda_encryption != KERNELDUMP_ENC_NONE) { 1268480f31c2SKonrad Witaszczyk #ifdef EKCD 126959c27ea1SMitchell Horne newdi->kdcrypto = kerneldumpcrypto_create(newdi->blocksize, 12706b6e2954SConrad Meyer kda->kda_encryption, kda->kda_key, 12716b6e2954SConrad Meyer kda->kda_encryptedkeysize, kda->kda_encryptedkey); 12726b6e2954SConrad Meyer if (newdi->kdcrypto == NULL) { 1273480f31c2SKonrad Witaszczyk error = EINVAL; 1274480f31c2SKonrad Witaszczyk goto cleanup; 1275480f31c2SKonrad Witaszczyk } 1276480f31c2SKonrad Witaszczyk #else 1277480f31c2SKonrad Witaszczyk error = EOPNOTSUPP; 1278480f31c2SKonrad Witaszczyk goto cleanup; 1279480f31c2SKonrad Witaszczyk #endif 1280480f31c2SKonrad Witaszczyk } 12816b6e2954SConrad Meyer if (kda->kda_compression != KERNELDUMP_COMP_NONE) { 12827a119578SConrad Meyer #ifdef EKCD 128364a16434SMark Johnston /* 128482985292SConrad Meyer * We can't support simultaneous unpadded block cipher 128582985292SConrad Meyer * encryption and compression because there is no guarantee the 128682985292SConrad Meyer * length of the compressed result is exactly a multiple of the 128782985292SConrad Meyer * cipher block size. 128864a16434SMark Johnston */ 128982985292SConrad Meyer if (kda->kda_encryption == KERNELDUMP_ENC_AES_256_CBC) { 129064a16434SMark Johnston error = EOPNOTSUPP; 129164a16434SMark Johnston goto cleanup; 129264a16434SMark Johnston } 12937a119578SConrad Meyer #endif 12946b6e2954SConrad Meyer newdi->kdcomp = kerneldumpcomp_create(newdi, 12956b6e2954SConrad Meyer kda->kda_compression); 12966b6e2954SConrad Meyer if (newdi->kdcomp == NULL) { 129764a16434SMark Johnston error = EINVAL; 129864a16434SMark Johnston goto cleanup; 129964a16434SMark Johnston } 130064a16434SMark Johnston } 13016b6e2954SConrad Meyer newdi->blockbuf = malloc(newdi->blocksize, M_DUMPER, M_WAITOK | M_ZERO); 13026b6e2954SConrad Meyer 130359c27ea1SMitchell Horne *dip = newdi; 130459c27ea1SMitchell Horne return (0); 130559c27ea1SMitchell Horne cleanup: 130659c27ea1SMitchell Horne dumper_destroy(newdi); 130759c27ea1SMitchell Horne return (error); 130859c27ea1SMitchell Horne } 130959c27ea1SMitchell Horne 131059c27ea1SMitchell Horne /* 131159c27ea1SMitchell Horne * Create a new dumper and register it in the global list. 131259c27ea1SMitchell Horne */ 131359c27ea1SMitchell Horne int 131459c27ea1SMitchell Horne dumper_insert(const struct dumperinfo *di_template, const char *devname, 131559c27ea1SMitchell Horne const struct diocskerneldump_arg *kda) 131659c27ea1SMitchell Horne { 131759c27ea1SMitchell Horne struct dumperinfo *newdi, *listdi; 131859c27ea1SMitchell Horne bool inserted; 131959c27ea1SMitchell Horne uint8_t index; 132059c27ea1SMitchell Horne int error; 132159c27ea1SMitchell Horne 132259c27ea1SMitchell Horne index = kda->kda_index; 132359c27ea1SMitchell Horne MPASS(index != KDA_REMOVE && index != KDA_REMOVE_DEV && 132459c27ea1SMitchell Horne index != KDA_REMOVE_ALL); 132559c27ea1SMitchell Horne 132659c27ea1SMitchell Horne error = priv_check(curthread, PRIV_SETDUMPER); 132759c27ea1SMitchell Horne if (error != 0) 132859c27ea1SMitchell Horne return (error); 132959c27ea1SMitchell Horne 133059c27ea1SMitchell Horne error = dumper_create(di_template, devname, kda, &newdi); 133159c27ea1SMitchell Horne if (error != 0) 133259c27ea1SMitchell Horne return (error); 133359c27ea1SMitchell Horne 13346b6e2954SConrad Meyer /* Add the new configuration to the queue */ 13356b6e2954SConrad Meyer mtx_lock(&dumpconf_list_lk); 13366b6e2954SConrad Meyer inserted = false; 13376b6e2954SConrad Meyer TAILQ_FOREACH(listdi, &dumper_configs, di_next) { 13386b6e2954SConrad Meyer if (index == 0) { 13396b6e2954SConrad Meyer TAILQ_INSERT_BEFORE(listdi, newdi, di_next); 13406b6e2954SConrad Meyer inserted = true; 13416b6e2954SConrad Meyer break; 13426b6e2954SConrad Meyer } 13436b6e2954SConrad Meyer index--; 13446b6e2954SConrad Meyer } 13456b6e2954SConrad Meyer if (!inserted) 13466b6e2954SConrad Meyer TAILQ_INSERT_TAIL(&dumper_configs, newdi, di_next); 13476b6e2954SConrad Meyer mtx_unlock(&dumpconf_list_lk); 13486b6e2954SConrad Meyer 134981661c94SPoul-Henning Kamp return (0); 1350bd92e6b6SMark Johnston } 1351bd92e6b6SMark Johnston 1352addccb8cSConrad Meyer #ifdef DDB 1353addccb8cSConrad Meyer void 1354addccb8cSConrad Meyer dumper_ddb_insert(struct dumperinfo *newdi) 1355addccb8cSConrad Meyer { 1356addccb8cSConrad Meyer TAILQ_INSERT_HEAD(&dumper_configs, newdi, di_next); 1357addccb8cSConrad Meyer } 1358addccb8cSConrad Meyer 1359addccb8cSConrad Meyer void 1360addccb8cSConrad Meyer dumper_ddb_remove(struct dumperinfo *di) 1361addccb8cSConrad Meyer { 1362addccb8cSConrad Meyer TAILQ_REMOVE(&dumper_configs, di, di_next); 1363addccb8cSConrad Meyer } 1364addccb8cSConrad Meyer #endif 1365addccb8cSConrad Meyer 13666b6e2954SConrad Meyer static bool 13676b6e2954SConrad Meyer dumper_config_match(const struct dumperinfo *di, const char *devname, 13686b6e2954SConrad Meyer const struct diocskerneldump_arg *kda) 13696b6e2954SConrad Meyer { 13706b6e2954SConrad Meyer if (kda->kda_index == KDA_REMOVE_ALL) 13716b6e2954SConrad Meyer return (true); 13726b6e2954SConrad Meyer 13736b6e2954SConrad Meyer if (strcmp(di->di_devname, devname) != 0) 13746b6e2954SConrad Meyer return (false); 13756b6e2954SConrad Meyer 13766b6e2954SConrad Meyer /* 13776b6e2954SConrad Meyer * Allow wildcard removal of configs matching a device on g_dev_orphan. 13786b6e2954SConrad Meyer */ 13796b6e2954SConrad Meyer if (kda->kda_index == KDA_REMOVE_DEV) 13806b6e2954SConrad Meyer return (true); 13816b6e2954SConrad Meyer 13826b6e2954SConrad Meyer if (di->kdcomp != NULL) { 13836b6e2954SConrad Meyer if (di->kdcomp->kdc_format != kda->kda_compression) 13846b6e2954SConrad Meyer return (false); 13856b6e2954SConrad Meyer } else if (kda->kda_compression != KERNELDUMP_COMP_NONE) 13866b6e2954SConrad Meyer return (false); 13876b6e2954SConrad Meyer #ifdef EKCD 13886b6e2954SConrad Meyer if (di->kdcrypto != NULL) { 13896b6e2954SConrad Meyer if (di->kdcrypto->kdc_encryption != kda->kda_encryption) 13906b6e2954SConrad Meyer return (false); 13916b6e2954SConrad Meyer /* 13926b6e2954SConrad Meyer * Do we care to verify keys match to delete? It seems weird 13936b6e2954SConrad Meyer * to expect multiple fallback dump configurations on the same 13946b6e2954SConrad Meyer * device that only differ in crypto key. 13956b6e2954SConrad Meyer */ 13966b6e2954SConrad Meyer } else 13976b6e2954SConrad Meyer #endif 13986b6e2954SConrad Meyer if (kda->kda_encryption != KERNELDUMP_ENC_NONE) 13996b6e2954SConrad Meyer return (false); 14006b6e2954SConrad Meyer 14016b6e2954SConrad Meyer return (true); 14026b6e2954SConrad Meyer } 14036b6e2954SConrad Meyer 140459c27ea1SMitchell Horne /* 140559c27ea1SMitchell Horne * Remove and free the requested dumper(s) from the global list. 140659c27ea1SMitchell Horne */ 1407bd92e6b6SMark Johnston int 14086b6e2954SConrad Meyer dumper_remove(const char *devname, const struct diocskerneldump_arg *kda) 1409bd92e6b6SMark Johnston { 14106b6e2954SConrad Meyer struct dumperinfo *di, *sdi; 14116b6e2954SConrad Meyer bool found; 1412bd92e6b6SMark Johnston int error; 1413bd92e6b6SMark Johnston 14146b6e2954SConrad Meyer error = priv_check(curthread, PRIV_SETDUMPER); 1415bd92e6b6SMark Johnston if (error != 0) 1416bd92e6b6SMark Johnston return (error); 1417bd92e6b6SMark Johnston 14186b6e2954SConrad Meyer /* 14196b6e2954SConrad Meyer * Try to find a matching configuration, and kill it. 14206b6e2954SConrad Meyer * 14216b6e2954SConrad Meyer * NULL 'kda' indicates remove any configuration matching 'devname', 14226b6e2954SConrad Meyer * which may remove multiple configurations in atypical configurations. 14236b6e2954SConrad Meyer */ 14246b6e2954SConrad Meyer found = false; 14256b6e2954SConrad Meyer mtx_lock(&dumpconf_list_lk); 14266b6e2954SConrad Meyer TAILQ_FOREACH_SAFE(di, &dumper_configs, di_next, sdi) { 14276b6e2954SConrad Meyer if (dumper_config_match(di, devname, kda)) { 14286b6e2954SConrad Meyer found = true; 14296b6e2954SConrad Meyer TAILQ_REMOVE(&dumper_configs, di, di_next); 143059c27ea1SMitchell Horne dumper_destroy(di); 1431480f31c2SKonrad Witaszczyk } 1432480f31c2SKonrad Witaszczyk } 14336b6e2954SConrad Meyer mtx_unlock(&dumpconf_list_lk); 14346b6e2954SConrad Meyer 14356b6e2954SConrad Meyer /* Only produce ENOENT if a more targeted match didn't match. */ 14366b6e2954SConrad Meyer if (!found && kda->kda_index == KDA_REMOVE) 14376b6e2954SConrad Meyer return (ENOENT); 1438bd92e6b6SMark Johnston return (0); 143981661c94SPoul-Henning Kamp } 144081661c94SPoul-Henning Kamp 1441480f31c2SKonrad Witaszczyk static int 1442480f31c2SKonrad Witaszczyk dump_check_bounds(struct dumperinfo *di, off_t offset, size_t length) 1443007b1b7bSRuslan Ermilov { 1444007b1b7bSRuslan Ermilov 1445bd92e6b6SMark Johnston if (di->mediasize > 0 && length != 0 && (offset < di->mediaoffset || 1446007b1b7bSRuslan Ermilov offset - di->mediaoffset + length > di->mediasize)) { 1447bde3b1e1SMark Johnston if (di->kdcomp != NULL && offset >= di->mediaoffset) { 1448bde3b1e1SMark Johnston printf( 1449bde3b1e1SMark Johnston "Compressed dump failed to fit in device boundaries.\n"); 1450bde3b1e1SMark Johnston return (E2BIG); 1451bde3b1e1SMark Johnston } 1452bde3b1e1SMark Johnston 145358379067SAttilio Rao printf("Attempt to write outside dump device boundaries.\n" 145458379067SAttilio Rao "offset(%jd), mediaoffset(%jd), length(%ju), mediasize(%jd).\n", 145558379067SAttilio Rao (intmax_t)offset, (intmax_t)di->mediaoffset, 145658379067SAttilio Rao (uintmax_t)length, (intmax_t)di->mediasize); 145758379067SAttilio Rao return (ENOSPC); 1458007b1b7bSRuslan Ermilov } 145946fcd1afSMark Johnston if (length % di->blocksize != 0) { 146046fcd1afSMark Johnston printf("Attempt to write partial block of length %ju.\n", 146146fcd1afSMark Johnston (uintmax_t)length); 146246fcd1afSMark Johnston return (EINVAL); 146346fcd1afSMark Johnston } 146446fcd1afSMark Johnston if (offset % di->blocksize != 0) { 146546fcd1afSMark Johnston printf("Attempt to write at unaligned offset %jd.\n", 146646fcd1afSMark Johnston (intmax_t)offset); 146746fcd1afSMark Johnston return (EINVAL); 1468480f31c2SKonrad Witaszczyk } 1469480f31c2SKonrad Witaszczyk 147046fcd1afSMark Johnston return (0); 147101938d36SMark Johnston } 147201938d36SMark Johnston 1473480f31c2SKonrad Witaszczyk #ifdef EKCD 1474480f31c2SKonrad Witaszczyk static int 1475480f31c2SKonrad Witaszczyk dump_encrypt(struct kerneldumpcrypto *kdc, uint8_t *buf, size_t size) 1476480f31c2SKonrad Witaszczyk { 1477480f31c2SKonrad Witaszczyk 1478480f31c2SKonrad Witaszczyk switch (kdc->kdc_encryption) { 1479480f31c2SKonrad Witaszczyk case KERNELDUMP_ENC_AES_256_CBC: 1480480f31c2SKonrad Witaszczyk if (rijndael_blockEncrypt(&kdc->kdc_ci, &kdc->kdc_ki, buf, 1481480f31c2SKonrad Witaszczyk 8 * size, buf) <= 0) { 1482480f31c2SKonrad Witaszczyk return (EIO); 1483480f31c2SKonrad Witaszczyk } 1484480f31c2SKonrad Witaszczyk if (rijndael_cipherInit(&kdc->kdc_ci, MODE_CBC, 1485480f31c2SKonrad Witaszczyk buf + size - 16 /* IV size for AES-256-CBC */) <= 0) { 1486480f31c2SKonrad Witaszczyk return (EIO); 1487480f31c2SKonrad Witaszczyk } 1488480f31c2SKonrad Witaszczyk break; 148982985292SConrad Meyer case KERNELDUMP_ENC_CHACHA20: 149082985292SConrad Meyer chacha_encrypt_bytes(&kdc->kdc_chacha, buf, buf, size); 149182985292SConrad Meyer break; 1492480f31c2SKonrad Witaszczyk default: 1493480f31c2SKonrad Witaszczyk return (EINVAL); 1494480f31c2SKonrad Witaszczyk } 1495480f31c2SKonrad Witaszczyk 1496480f31c2SKonrad Witaszczyk return (0); 1497480f31c2SKonrad Witaszczyk } 1498480f31c2SKonrad Witaszczyk 1499480f31c2SKonrad Witaszczyk /* Encrypt data and call dumper. */ 1500480f31c2SKonrad Witaszczyk static int 1501db71383bSMitchell Horne dump_encrypted_write(struct dumperinfo *di, void *virtual, off_t offset, 1502db71383bSMitchell Horne size_t length) 1503480f31c2SKonrad Witaszczyk { 1504480f31c2SKonrad Witaszczyk static uint8_t buf[KERNELDUMP_BUFFER_SIZE]; 1505480f31c2SKonrad Witaszczyk struct kerneldumpcrypto *kdc; 1506480f31c2SKonrad Witaszczyk int error; 1507480f31c2SKonrad Witaszczyk size_t nbytes; 1508480f31c2SKonrad Witaszczyk 150978f57a9cSMark Johnston kdc = di->kdcrypto; 1510480f31c2SKonrad Witaszczyk 1511480f31c2SKonrad Witaszczyk while (length > 0) { 1512480f31c2SKonrad Witaszczyk nbytes = MIN(length, sizeof(buf)); 1513480f31c2SKonrad Witaszczyk bcopy(virtual, buf, nbytes); 1514480f31c2SKonrad Witaszczyk 1515480f31c2SKonrad Witaszczyk if (dump_encrypt(kdc, buf, nbytes) != 0) 1516480f31c2SKonrad Witaszczyk return (EIO); 1517480f31c2SKonrad Witaszczyk 1518db71383bSMitchell Horne error = dump_write(di, buf, offset, nbytes); 1519480f31c2SKonrad Witaszczyk if (error != 0) 1520480f31c2SKonrad Witaszczyk return (error); 1521480f31c2SKonrad Witaszczyk 1522480f31c2SKonrad Witaszczyk offset += nbytes; 1523480f31c2SKonrad Witaszczyk virtual = (void *)((uint8_t *)virtual + nbytes); 1524480f31c2SKonrad Witaszczyk length -= nbytes; 1525480f31c2SKonrad Witaszczyk } 1526480f31c2SKonrad Witaszczyk 1527480f31c2SKonrad Witaszczyk return (0); 1528480f31c2SKonrad Witaszczyk } 152901938d36SMark Johnston #endif /* EKCD */ 1530007b1b7bSRuslan Ermilov 153164a16434SMark Johnston static int 153278f57a9cSMark Johnston kerneldumpcomp_write_cb(void *base, size_t length, off_t offset, void *arg) 153364a16434SMark Johnston { 153464a16434SMark Johnston struct dumperinfo *di; 153564a16434SMark Johnston size_t resid, rlength; 153664a16434SMark Johnston int error; 153764a16434SMark Johnston 153864a16434SMark Johnston di = arg; 153964a16434SMark Johnston 154064a16434SMark Johnston if (length % di->blocksize != 0) { 154164a16434SMark Johnston /* 154264a16434SMark Johnston * This must be the final write after flushing the compression 154364a16434SMark Johnston * stream. Write as many full blocks as possible and stash the 154464a16434SMark Johnston * residual data in the dumper's block buffer. It will be 154564a16434SMark Johnston * padded and written in dump_finish(). 154664a16434SMark Johnston */ 154764a16434SMark Johnston rlength = rounddown(length, di->blocksize); 154864a16434SMark Johnston if (rlength != 0) { 1549db71383bSMitchell Horne error = _dump_append(di, base, rlength); 155064a16434SMark Johnston if (error != 0) 155164a16434SMark Johnston return (error); 155264a16434SMark Johnston } 155364a16434SMark Johnston resid = length - rlength; 155464a16434SMark Johnston memmove(di->blockbuf, (uint8_t *)base + rlength, resid); 15556255e8c8SMark Johnston bzero((uint8_t *)di->blockbuf + resid, di->blocksize - resid); 155678f57a9cSMark Johnston di->kdcomp->kdc_resid = resid; 155764a16434SMark Johnston return (EAGAIN); 155864a16434SMark Johnston } 1559db71383bSMitchell Horne return (_dump_append(di, base, length)); 156064a16434SMark Johnston } 156164a16434SMark Johnston 156264a16434SMark Johnston /* 1563bd92e6b6SMark Johnston * Write kernel dump headers at the beginning and end of the dump extent. 1564bd92e6b6SMark Johnston * Write the kernel dump encryption key after the leading header if we were 1565bd92e6b6SMark Johnston * configured to do so. 156664a16434SMark Johnston */ 1567480f31c2SKonrad Witaszczyk static int 1568bd92e6b6SMark Johnston dump_write_headers(struct dumperinfo *di, struct kerneldumpheader *kdh) 1569480f31c2SKonrad Witaszczyk { 1570bd92e6b6SMark Johnston #ifdef EKCD 1571bd92e6b6SMark Johnston struct kerneldumpcrypto *kdc; 1572bd92e6b6SMark Johnston #endif 157313a58148SEric van Gyzen void *buf; 1574e9666bf6SMark Johnston size_t hdrsz; 1575bd92e6b6SMark Johnston uint64_t extent; 1576bd92e6b6SMark Johnston uint32_t keysize; 1577bd92e6b6SMark Johnston int error; 1578480f31c2SKonrad Witaszczyk 1579e9666bf6SMark Johnston hdrsz = sizeof(*kdh); 1580e9666bf6SMark Johnston if (hdrsz > di->blocksize) 1581e9666bf6SMark Johnston return (ENOMEM); 1582e9666bf6SMark Johnston 1583bd92e6b6SMark Johnston #ifdef EKCD 1584bd92e6b6SMark Johnston kdc = di->kdcrypto; 1585bd92e6b6SMark Johnston keysize = kerneldumpcrypto_dumpkeysize(kdc); 1586bd92e6b6SMark Johnston #else 1587bd92e6b6SMark Johnston keysize = 0; 1588bd92e6b6SMark Johnston #endif 1589bd92e6b6SMark Johnston 1590bd92e6b6SMark Johnston /* 1591bd92e6b6SMark Johnston * If the dump device has special handling for headers, let it take care 1592bd92e6b6SMark Johnston * of writing them out. 1593bd92e6b6SMark Johnston */ 1594bd92e6b6SMark Johnston if (di->dumper_hdr != NULL) 159513a58148SEric van Gyzen return (di->dumper_hdr(di, kdh)); 1596bd92e6b6SMark Johnston 1597e9666bf6SMark Johnston if (hdrsz == di->blocksize) 1598e9666bf6SMark Johnston buf = kdh; 1599e9666bf6SMark Johnston else { 1600e9666bf6SMark Johnston buf = di->blockbuf; 1601e9666bf6SMark Johnston memset(buf, 0, di->blocksize); 1602e9666bf6SMark Johnston memcpy(buf, kdh, hdrsz); 1603e9666bf6SMark Johnston } 1604e9666bf6SMark Johnston 1605bd92e6b6SMark Johnston extent = dtoh64(kdh->dumpextent); 1606bd92e6b6SMark Johnston #ifdef EKCD 1607bd92e6b6SMark Johnston if (kdc != NULL) { 1608db71383bSMitchell Horne error = dump_write(di, kdc->kdc_dumpkey, 1609bd92e6b6SMark Johnston di->mediaoffset + di->mediasize - di->blocksize - extent - 1610bd92e6b6SMark Johnston keysize, keysize); 1611bd92e6b6SMark Johnston if (error != 0) 1612bd92e6b6SMark Johnston return (error); 1613bd92e6b6SMark Johnston } 1614bd92e6b6SMark Johnston #endif 1615bd92e6b6SMark Johnston 1616db71383bSMitchell Horne error = dump_write(di, buf, 1617bd92e6b6SMark Johnston di->mediaoffset + di->mediasize - 2 * di->blocksize - extent - 1618bd92e6b6SMark Johnston keysize, di->blocksize); 1619bd92e6b6SMark Johnston if (error == 0) 1620db71383bSMitchell Horne error = dump_write(di, buf, di->mediaoffset + di->mediasize - 1621bd92e6b6SMark Johnston di->blocksize, di->blocksize); 1622bd92e6b6SMark Johnston return (error); 16235dc5dab6SConrad Meyer } 16245dc5dab6SConrad Meyer 162550ef60daSMark Johnston /* 162650ef60daSMark Johnston * Don't touch the first SIZEOF_METADATA bytes on the dump device. This is to 162750ef60daSMark Johnston * protect us from metadata and metadata from us. 162850ef60daSMark Johnston */ 162950ef60daSMark Johnston #define SIZEOF_METADATA (64 * 1024) 163050ef60daSMark Johnston 163150ef60daSMark Johnston /* 163264a16434SMark Johnston * Do some preliminary setup for a kernel dump: initialize state for encryption, 163364a16434SMark Johnston * if requested, and make sure that we have enough space on the dump device. 163464a16434SMark Johnston * 163564a16434SMark Johnston * We set things up so that the dump ends before the last sector of the dump 163664a16434SMark Johnston * device, at which the trailing header is written. 163764a16434SMark Johnston * 163864a16434SMark Johnston * +-----------+------+-----+----------------------------+------+ 163964a16434SMark Johnston * | | lhdr | key | ... kernel dump ... | thdr | 164064a16434SMark Johnston * +-----------+------+-----+----------------------------+------+ 164164a16434SMark Johnston * 1 blk opt <------- dump extent --------> 1 blk 164264a16434SMark Johnston * 164364a16434SMark Johnston * Dumps written using dump_append() start at the beginning of the extent. 164464a16434SMark Johnston * Uncompressed dumps will use the entire extent, but compressed dumps typically 164564a16434SMark Johnston * will not. The true length of the dump is recorded in the leading and trailing 164664a16434SMark Johnston * headers once the dump has been completed. 1647bd92e6b6SMark Johnston * 1648bd92e6b6SMark Johnston * The dump device may provide a callback, in which case it will initialize 1649bd92e6b6SMark Johnston * dumpoff and take care of laying out the headers. 165050ef60daSMark Johnston */ 165150ef60daSMark Johnston int 165246fcd1afSMark Johnston dump_start(struct dumperinfo *di, struct kerneldumpheader *kdh) 165350ef60daSMark Johnston { 165413a58148SEric van Gyzen #ifdef EKCD 165513a58148SEric van Gyzen struct kerneldumpcrypto *kdc; 165613a58148SEric van Gyzen #endif 165713a58148SEric van Gyzen void *key; 1658bd92e6b6SMark Johnston uint64_t dumpextent, span; 165901938d36SMark Johnston uint32_t keysize; 1660bd92e6b6SMark Johnston int error; 166150ef60daSMark Johnston 166201938d36SMark Johnston #ifdef EKCD 166313a58148SEric van Gyzen /* Send the key before the dump so a partial dump is still usable. */ 166413a58148SEric van Gyzen kdc = di->kdcrypto; 166513a58148SEric van Gyzen error = kerneldumpcrypto_init(kdc); 166650ef60daSMark Johnston if (error != 0) 166750ef60daSMark Johnston return (error); 166813a58148SEric van Gyzen keysize = kerneldumpcrypto_dumpkeysize(kdc); 166913a58148SEric van Gyzen key = keysize > 0 ? kdc->kdc_dumpkey : NULL; 167001938d36SMark Johnston #else 1671bd92e6b6SMark Johnston error = 0; 167201938d36SMark Johnston keysize = 0; 167313a58148SEric van Gyzen key = NULL; 167401938d36SMark Johnston #endif 167550ef60daSMark Johnston 1676bd92e6b6SMark Johnston if (di->dumper_start != NULL) { 167713a58148SEric van Gyzen error = di->dumper_start(di, key, keysize); 1678bd92e6b6SMark Johnston } else { 167964a16434SMark Johnston dumpextent = dtoh64(kdh->dumpextent); 1680bd92e6b6SMark Johnston span = SIZEOF_METADATA + dumpextent + 2 * di->blocksize + 1681bd92e6b6SMark Johnston keysize; 1682bd92e6b6SMark Johnston if (di->mediasize < span) { 1683bd92e6b6SMark Johnston if (di->kdcomp == NULL) 1684bd92e6b6SMark Johnston return (E2BIG); 1685bd92e6b6SMark Johnston 168664a16434SMark Johnston /* 168764a16434SMark Johnston * We don't yet know how much space the compressed dump 168864a16434SMark Johnston * will occupy, so try to use the whole swap partition 168964a16434SMark Johnston * (minus the first 64KB) in the hope that the 169064a16434SMark Johnston * compressed dump will fit. If that doesn't turn out to 16916026dcd7SMark Johnston * be enough, the bounds checking in dump_write() 169264a16434SMark Johnston * will catch us and cause the dump to fail. 169364a16434SMark Johnston */ 1694bd92e6b6SMark Johnston dumpextent = di->mediasize - span + dumpextent; 169564a16434SMark Johnston kdh->dumpextent = htod64(dumpextent); 169664a16434SMark Johnston } 169764a16434SMark Johnston 1698bd92e6b6SMark Johnston /* 1699bd92e6b6SMark Johnston * The offset at which to begin writing the dump. 1700bd92e6b6SMark Johnston */ 170164a16434SMark Johnston di->dumpoff = di->mediaoffset + di->mediasize - di->blocksize - 170264a16434SMark Johnston dumpextent; 1703bd92e6b6SMark Johnston } 1704bd92e6b6SMark Johnston di->origdumpoff = di->dumpoff; 1705bd92e6b6SMark Johnston return (error); 170650ef60daSMark Johnston } 170750ef60daSMark Johnston 170864a16434SMark Johnston static int 1709db71383bSMitchell Horne _dump_append(struct dumperinfo *di, void *virtual, size_t length) 171046fcd1afSMark Johnston { 171146fcd1afSMark Johnston int error; 171246fcd1afSMark Johnston 171346fcd1afSMark Johnston #ifdef EKCD 171478f57a9cSMark Johnston if (di->kdcrypto != NULL) 1715db71383bSMitchell Horne error = dump_encrypted_write(di, virtual, di->dumpoff, length); 171646fcd1afSMark Johnston else 171746fcd1afSMark Johnston #endif 1718db71383bSMitchell Horne error = dump_write(di, virtual, di->dumpoff, length); 171946fcd1afSMark Johnston if (error == 0) 172046fcd1afSMark Johnston di->dumpoff += length; 172146fcd1afSMark Johnston return (error); 172246fcd1afSMark Johnston } 172346fcd1afSMark Johnston 172464a16434SMark Johnston /* 172564a16434SMark Johnston * Write to the dump device starting at dumpoff. When compression is enabled, 172664a16434SMark Johnston * writes to the device will be performed using a callback that gets invoked 172764a16434SMark Johnston * when the compression stream's output buffer is full. 172864a16434SMark Johnston */ 172964a16434SMark Johnston int 1730db71383bSMitchell Horne dump_append(struct dumperinfo *di, void *virtual, size_t length) 173164a16434SMark Johnston { 173264a16434SMark Johnston void *buf; 173364a16434SMark Johnston 173478f57a9cSMark Johnston if (di->kdcomp != NULL) { 173578f57a9cSMark Johnston /* Bounce through a buffer to avoid CRC errors. */ 173664a16434SMark Johnston if (length > di->maxiosize) 173764a16434SMark Johnston return (EINVAL); 173878f57a9cSMark Johnston buf = di->kdcomp->kdc_buf; 173964a16434SMark Johnston memmove(buf, virtual, length); 174078f57a9cSMark Johnston return (compressor_write(di->kdcomp->kdc_stream, buf, length)); 174164a16434SMark Johnston } 1742db71383bSMitchell Horne return (_dump_append(di, virtual, length)); 174364a16434SMark Johnston } 174464a16434SMark Johnston 174564a16434SMark Johnston /* 174664a16434SMark Johnston * Write to the dump device at the specified offset. 174764a16434SMark Johnston */ 174846fcd1afSMark Johnston int 1749db71383bSMitchell Horne dump_write(struct dumperinfo *di, void *virtual, off_t offset, size_t length) 175046fcd1afSMark Johnston { 175146fcd1afSMark Johnston int error; 175246fcd1afSMark Johnston 175346fcd1afSMark Johnston error = dump_check_bounds(di, offset, length); 175446fcd1afSMark Johnston if (error != 0) 175546fcd1afSMark Johnston return (error); 1756489ba222SMitchell Horne return (di->dumper(di->priv, virtual, offset, length)); 175746fcd1afSMark Johnston } 175846fcd1afSMark Johnston 175950ef60daSMark Johnston /* 176064a16434SMark Johnston * Perform kernel dump finalization: flush the compression stream, if necessary, 176164a16434SMark Johnston * write the leading and trailing kernel dump headers now that we know the true 176264a16434SMark Johnston * length of the dump, and optionally write the encryption key following the 176364a16434SMark Johnston * leading header. 176450ef60daSMark Johnston */ 176550ef60daSMark Johnston int 176646fcd1afSMark Johnston dump_finish(struct dumperinfo *di, struct kerneldumpheader *kdh) 176750ef60daSMark Johnston { 176850ef60daSMark Johnston int error; 176950ef60daSMark Johnston 177078f57a9cSMark Johnston if (di->kdcomp != NULL) { 177178f57a9cSMark Johnston error = compressor_flush(di->kdcomp->kdc_stream); 177264a16434SMark Johnston if (error == EAGAIN) { 177364a16434SMark Johnston /* We have residual data in di->blockbuf. */ 1774db71383bSMitchell Horne error = _dump_append(di, di->blockbuf, di->blocksize); 17756255e8c8SMark Johnston if (error == 0) 17766255e8c8SMark Johnston /* Compensate for _dump_append()'s adjustment. */ 17776255e8c8SMark Johnston di->dumpoff -= di->blocksize - di->kdcomp->kdc_resid; 177878f57a9cSMark Johnston di->kdcomp->kdc_resid = 0; 177964a16434SMark Johnston } 178064a16434SMark Johnston if (error != 0) 178164a16434SMark Johnston return (error); 178264a16434SMark Johnston 178364a16434SMark Johnston /* 178464a16434SMark Johnston * We now know the size of the compressed dump, so update the 178564a16434SMark Johnston * header accordingly and recompute parity. 178664a16434SMark Johnston */ 1787bd92e6b6SMark Johnston kdh->dumplength = htod64(di->dumpoff - di->origdumpoff); 178864a16434SMark Johnston kdh->parity = 0; 178964a16434SMark Johnston kdh->parity = kerneldump_parity(kdh); 179064a16434SMark Johnston 179178f57a9cSMark Johnston compressor_reset(di->kdcomp->kdc_stream); 179264a16434SMark Johnston } 179364a16434SMark Johnston 1794bd92e6b6SMark Johnston error = dump_write_headers(di, kdh); 179550ef60daSMark Johnston if (error != 0) 179650ef60daSMark Johnston return (error); 179750ef60daSMark Johnston 1798db71383bSMitchell Horne (void)dump_write(di, NULL, 0, 0); 179950ef60daSMark Johnston return (0); 180050ef60daSMark Johnston } 180150ef60daSMark Johnston 1802e6592ee5SPeter Wemm void 180301938d36SMark Johnston dump_init_header(const struct dumperinfo *di, struct kerneldumpheader *kdh, 1804fe20aaecSRyan Libby const char *magic, uint32_t archver, uint64_t dumplen) 1805e6592ee5SPeter Wemm { 1806ab384d75SMark Johnston size_t dstsize; 1807e6592ee5SPeter Wemm 1808e6592ee5SPeter Wemm bzero(kdh, sizeof(*kdh)); 18097a9c38e6SAlan Somers strlcpy(kdh->magic, magic, sizeof(kdh->magic)); 18107a9c38e6SAlan Somers strlcpy(kdh->architecture, MACHINE_ARCH, sizeof(kdh->architecture)); 1811e6592ee5SPeter Wemm kdh->version = htod32(KERNELDUMPVERSION); 1812e6592ee5SPeter Wemm kdh->architectureversion = htod32(archver); 1813e6592ee5SPeter Wemm kdh->dumplength = htod64(dumplen); 181464a16434SMark Johnston kdh->dumpextent = kdh->dumplength; 1815e6592ee5SPeter Wemm kdh->dumptime = htod64(time_second); 181601938d36SMark Johnston #ifdef EKCD 181778f57a9cSMark Johnston kdh->dumpkeysize = htod32(kerneldumpcrypto_dumpkeysize(di->kdcrypto)); 181801938d36SMark Johnston #else 181901938d36SMark Johnston kdh->dumpkeysize = 0; 182001938d36SMark Johnston #endif 182101938d36SMark Johnston kdh->blocksize = htod32(di->blocksize); 18227a9c38e6SAlan Somers strlcpy(kdh->hostname, prison0.pr_hostname, sizeof(kdh->hostname)); 1823ab384d75SMark Johnston dstsize = sizeof(kdh->versionstring); 1824ab384d75SMark Johnston if (strlcpy(kdh->versionstring, version, dstsize) >= dstsize) 1825ab384d75SMark Johnston kdh->versionstring[dstsize - 2] = '\n'; 1826e6592ee5SPeter Wemm if (panicstr != NULL) 18277a9c38e6SAlan Somers strlcpy(kdh->panicstring, panicstr, sizeof(kdh->panicstring)); 182878f57a9cSMark Johnston if (di->kdcomp != NULL) 18296026dcd7SMark Johnston kdh->compression = di->kdcomp->kdc_format; 1830e6592ee5SPeter Wemm kdh->parity = kerneldump_parity(kdh); 1831e6592ee5SPeter Wemm } 18323af72c11SBjoern A. Zeeb 18333af72c11SBjoern A. Zeeb #ifdef DDB 1834c84c5e00SMitchell Horne DB_SHOW_COMMAND_FLAGS(panic, db_show_panic, DB_CMD_MEMSAFE) 18353af72c11SBjoern A. Zeeb { 18363af72c11SBjoern A. Zeeb 18373af72c11SBjoern A. Zeeb if (panicstr == NULL) 18383af72c11SBjoern A. Zeeb db_printf("panicstr not set\n"); 18393af72c11SBjoern A. Zeeb else 18403af72c11SBjoern A. Zeeb db_printf("panic: %s\n", panicstr); 18413af72c11SBjoern A. Zeeb } 18423af72c11SBjoern A. Zeeb #endif 1843