1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2002 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * Dump driver. Provides ioctls to get/set crash dump configuration. 31*0Sstevel@tonic-gate */ 32*0Sstevel@tonic-gate 33*0Sstevel@tonic-gate #include <sys/types.h> 34*0Sstevel@tonic-gate #include <sys/param.h> 35*0Sstevel@tonic-gate #include <sys/systm.h> 36*0Sstevel@tonic-gate #include <sys/vnode.h> 37*0Sstevel@tonic-gate #include <sys/uio.h> 38*0Sstevel@tonic-gate #include <sys/cred.h> 39*0Sstevel@tonic-gate #include <sys/kmem.h> 40*0Sstevel@tonic-gate #include <sys/errno.h> 41*0Sstevel@tonic-gate #include <sys/modctl.h> 42*0Sstevel@tonic-gate #include <sys/dumphdr.h> 43*0Sstevel@tonic-gate #include <sys/dumpadm.h> 44*0Sstevel@tonic-gate #include <sys/pathname.h> 45*0Sstevel@tonic-gate #include <sys/file.h> 46*0Sstevel@tonic-gate #include <vm/anon.h> 47*0Sstevel@tonic-gate #include <sys/stat.h> 48*0Sstevel@tonic-gate #include <sys/conf.h> 49*0Sstevel@tonic-gate #include <sys/ddi.h> 50*0Sstevel@tonic-gate #include <sys/sunddi.h> 51*0Sstevel@tonic-gate 52*0Sstevel@tonic-gate static dev_info_t *dump_devi; 53*0Sstevel@tonic-gate 54*0Sstevel@tonic-gate static int 55*0Sstevel@tonic-gate dump_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 56*0Sstevel@tonic-gate { 57*0Sstevel@tonic-gate if (cmd != DDI_ATTACH) 58*0Sstevel@tonic-gate return (DDI_FAILURE); 59*0Sstevel@tonic-gate if (ddi_create_minor_node(devi, "dump", S_IFCHR, 0, DDI_PSEUDO, NULL) == 60*0Sstevel@tonic-gate DDI_FAILURE) { 61*0Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 62*0Sstevel@tonic-gate return (DDI_FAILURE); 63*0Sstevel@tonic-gate } 64*0Sstevel@tonic-gate dump_devi = devi; 65*0Sstevel@tonic-gate return (DDI_SUCCESS); 66*0Sstevel@tonic-gate } 67*0Sstevel@tonic-gate 68*0Sstevel@tonic-gate static int 69*0Sstevel@tonic-gate dump_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 70*0Sstevel@tonic-gate { 71*0Sstevel@tonic-gate if (cmd != DDI_DETACH) 72*0Sstevel@tonic-gate return (DDI_FAILURE); 73*0Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 74*0Sstevel@tonic-gate return (DDI_SUCCESS); 75*0Sstevel@tonic-gate } 76*0Sstevel@tonic-gate 77*0Sstevel@tonic-gate /*ARGSUSED*/ 78*0Sstevel@tonic-gate static int 79*0Sstevel@tonic-gate dump_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 80*0Sstevel@tonic-gate { 81*0Sstevel@tonic-gate switch (infocmd) { 82*0Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 83*0Sstevel@tonic-gate *result = dump_devi; 84*0Sstevel@tonic-gate return (DDI_SUCCESS); 85*0Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 86*0Sstevel@tonic-gate *result = 0; 87*0Sstevel@tonic-gate return (DDI_SUCCESS); 88*0Sstevel@tonic-gate } 89*0Sstevel@tonic-gate return (DDI_FAILURE); 90*0Sstevel@tonic-gate } 91*0Sstevel@tonic-gate 92*0Sstevel@tonic-gate /*ARGSUSED*/ 93*0Sstevel@tonic-gate int 94*0Sstevel@tonic-gate dump_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred, int *rvalp) 95*0Sstevel@tonic-gate { 96*0Sstevel@tonic-gate uint64_t size; 97*0Sstevel@tonic-gate uint64_t dumpsize_in_pages; 98*0Sstevel@tonic-gate int error = 0; 99*0Sstevel@tonic-gate char *pathbuf = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 100*0Sstevel@tonic-gate vnode_t *vp; 101*0Sstevel@tonic-gate 102*0Sstevel@tonic-gate switch (cmd) { 103*0Sstevel@tonic-gate case DIOCGETDUMPSIZE: 104*0Sstevel@tonic-gate if (dump_conflags & DUMP_ALL) 105*0Sstevel@tonic-gate size = ptob((uint64_t)physmem) / DUMP_COMPRESS_RATIO; 106*0Sstevel@tonic-gate else { 107*0Sstevel@tonic-gate /* 108*0Sstevel@tonic-gate * We can't give a good answer for the DUMP_CURPROC 109*0Sstevel@tonic-gate * because we won't know which process to use until it 110*0Sstevel@tonic-gate * causes a panic. We'll therefore punt and give the 111*0Sstevel@tonic-gate * caller the size for the kernel. 112*0Sstevel@tonic-gate * 113*0Sstevel@tonic-gate * This kernel size equation takes care of the 114*0Sstevel@tonic-gate * boot time kernel footprint and also accounts 115*0Sstevel@tonic-gate * for availrmem changes due to user explicit locking. 116*0Sstevel@tonic-gate * Refer to common/vm/vm_page.c for an explanation 117*0Sstevel@tonic-gate * of these counters. 118*0Sstevel@tonic-gate */ 119*0Sstevel@tonic-gate dumpsize_in_pages = (physinstalled - obp_pages - 120*0Sstevel@tonic-gate availrmem - 121*0Sstevel@tonic-gate anon_segkp_pages_locked - 122*0Sstevel@tonic-gate k_anoninfo.ani_mem_resv - 123*0Sstevel@tonic-gate segvn_pages_locked - 124*0Sstevel@tonic-gate pages_locked - 125*0Sstevel@tonic-gate pages_claimed - 126*0Sstevel@tonic-gate pages_useclaim); 127*0Sstevel@tonic-gate 128*0Sstevel@tonic-gate size = ptob(dumpsize_in_pages) / DUMP_COMPRESS_RATIO; 129*0Sstevel@tonic-gate } 130*0Sstevel@tonic-gate if (copyout(&size, (void *)arg, sizeof (size)) < 0) 131*0Sstevel@tonic-gate error = EFAULT; 132*0Sstevel@tonic-gate break; 133*0Sstevel@tonic-gate 134*0Sstevel@tonic-gate case DIOCGETCONF: 135*0Sstevel@tonic-gate mutex_enter(&dump_lock); 136*0Sstevel@tonic-gate *rvalp = dump_conflags; 137*0Sstevel@tonic-gate if (dumpvp && !(dumpvp->v_flag & VISSWAP)) 138*0Sstevel@tonic-gate *rvalp |= DUMP_EXCL; 139*0Sstevel@tonic-gate mutex_exit(&dump_lock); 140*0Sstevel@tonic-gate break; 141*0Sstevel@tonic-gate 142*0Sstevel@tonic-gate case DIOCSETCONF: 143*0Sstevel@tonic-gate mutex_enter(&dump_lock); 144*0Sstevel@tonic-gate if (arg == DUMP_KERNEL || arg == DUMP_ALL || 145*0Sstevel@tonic-gate arg == DUMP_CURPROC) 146*0Sstevel@tonic-gate dump_conflags = arg; 147*0Sstevel@tonic-gate else 148*0Sstevel@tonic-gate error = EINVAL; 149*0Sstevel@tonic-gate mutex_exit(&dump_lock); 150*0Sstevel@tonic-gate break; 151*0Sstevel@tonic-gate 152*0Sstevel@tonic-gate case DIOCGETDEV: 153*0Sstevel@tonic-gate mutex_enter(&dump_lock); 154*0Sstevel@tonic-gate if (dumppath == NULL) { 155*0Sstevel@tonic-gate mutex_exit(&dump_lock); 156*0Sstevel@tonic-gate error = ENODEV; 157*0Sstevel@tonic-gate break; 158*0Sstevel@tonic-gate } 159*0Sstevel@tonic-gate (void) strcpy(pathbuf, dumppath); 160*0Sstevel@tonic-gate mutex_exit(&dump_lock); 161*0Sstevel@tonic-gate error = copyoutstr(pathbuf, (void *)arg, MAXPATHLEN, NULL); 162*0Sstevel@tonic-gate break; 163*0Sstevel@tonic-gate 164*0Sstevel@tonic-gate case DIOCSETDEV: 165*0Sstevel@tonic-gate case DIOCTRYDEV: 166*0Sstevel@tonic-gate if ((error = copyinstr((char *)arg, pathbuf, MAXPATHLEN, 167*0Sstevel@tonic-gate NULL)) != 0 || (error = lookupname(pathbuf, UIO_SYSSPACE, 168*0Sstevel@tonic-gate FOLLOW, NULLVPP, &vp)) != 0) 169*0Sstevel@tonic-gate break; 170*0Sstevel@tonic-gate mutex_enter(&dump_lock); 171*0Sstevel@tonic-gate error = dumpinit(vp, pathbuf, cmd == DIOCTRYDEV); 172*0Sstevel@tonic-gate mutex_exit(&dump_lock); 173*0Sstevel@tonic-gate VN_RELE(vp); 174*0Sstevel@tonic-gate break; 175*0Sstevel@tonic-gate 176*0Sstevel@tonic-gate case DIOCDUMP: 177*0Sstevel@tonic-gate mutex_enter(&dump_lock); 178*0Sstevel@tonic-gate if (dumpvp == NULL) 179*0Sstevel@tonic-gate error = ENODEV; 180*0Sstevel@tonic-gate else if (dumpvp->v_flag & VISSWAP) 181*0Sstevel@tonic-gate error = EBUSY; 182*0Sstevel@tonic-gate else 183*0Sstevel@tonic-gate dumpsys(); 184*0Sstevel@tonic-gate mutex_exit(&dump_lock); 185*0Sstevel@tonic-gate break; 186*0Sstevel@tonic-gate 187*0Sstevel@tonic-gate default: 188*0Sstevel@tonic-gate error = ENXIO; 189*0Sstevel@tonic-gate } 190*0Sstevel@tonic-gate 191*0Sstevel@tonic-gate kmem_free(pathbuf, MAXPATHLEN); 192*0Sstevel@tonic-gate return (error); 193*0Sstevel@tonic-gate } 194*0Sstevel@tonic-gate 195*0Sstevel@tonic-gate struct cb_ops dump_cb_ops = { 196*0Sstevel@tonic-gate nulldev, /* open */ 197*0Sstevel@tonic-gate nulldev, /* close */ 198*0Sstevel@tonic-gate nodev, /* strategy */ 199*0Sstevel@tonic-gate nodev, /* print */ 200*0Sstevel@tonic-gate nodev, /* dump */ 201*0Sstevel@tonic-gate nodev, /* read */ 202*0Sstevel@tonic-gate nodev, /* write */ 203*0Sstevel@tonic-gate dump_ioctl, /* ioctl */ 204*0Sstevel@tonic-gate nodev, /* devmap */ 205*0Sstevel@tonic-gate nodev, /* mmap */ 206*0Sstevel@tonic-gate nodev, /* segmap */ 207*0Sstevel@tonic-gate nochpoll, /* poll */ 208*0Sstevel@tonic-gate ddi_prop_op, /* prop_op */ 209*0Sstevel@tonic-gate 0, /* streamtab */ 210*0Sstevel@tonic-gate D_NEW|D_MP /* Driver compatibility flag */ 211*0Sstevel@tonic-gate }; 212*0Sstevel@tonic-gate 213*0Sstevel@tonic-gate struct dev_ops dump_ops = { 214*0Sstevel@tonic-gate DEVO_REV, /* devo_rev, */ 215*0Sstevel@tonic-gate 0, /* refcnt */ 216*0Sstevel@tonic-gate dump_info, /* info */ 217*0Sstevel@tonic-gate nulldev, /* identify */ 218*0Sstevel@tonic-gate nulldev, /* probe */ 219*0Sstevel@tonic-gate dump_attach, /* attach */ 220*0Sstevel@tonic-gate dump_detach, /* detach */ 221*0Sstevel@tonic-gate nodev, /* reset */ 222*0Sstevel@tonic-gate &dump_cb_ops, /* driver operations */ 223*0Sstevel@tonic-gate (struct bus_ops *)0 /* bus operations */ 224*0Sstevel@tonic-gate }; 225*0Sstevel@tonic-gate 226*0Sstevel@tonic-gate static struct modldrv modldrv = { 227*0Sstevel@tonic-gate &mod_driverops, "crash dump driver %I%", &dump_ops, 228*0Sstevel@tonic-gate }; 229*0Sstevel@tonic-gate 230*0Sstevel@tonic-gate static struct modlinkage modlinkage = { 231*0Sstevel@tonic-gate MODREV_1, (void *)&modldrv, NULL 232*0Sstevel@tonic-gate }; 233*0Sstevel@tonic-gate 234*0Sstevel@tonic-gate int 235*0Sstevel@tonic-gate _init(void) 236*0Sstevel@tonic-gate { 237*0Sstevel@tonic-gate return (mod_install(&modlinkage)); 238*0Sstevel@tonic-gate } 239*0Sstevel@tonic-gate 240*0Sstevel@tonic-gate int 241*0Sstevel@tonic-gate _fini(void) 242*0Sstevel@tonic-gate { 243*0Sstevel@tonic-gate return (mod_remove(&modlinkage)); 244*0Sstevel@tonic-gate } 245*0Sstevel@tonic-gate 246*0Sstevel@tonic-gate int 247*0Sstevel@tonic-gate _info(struct modinfo *modinfop) 248*0Sstevel@tonic-gate { 249*0Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 250*0Sstevel@tonic-gate } 251