10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*4578Ssp92102 * Common Development and Distribution License (the "License"). 6*4578Ssp92102 * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*4578Ssp92102 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate /* 290Sstevel@tonic-gate * Dump driver. Provides ioctls to get/set crash dump configuration. 300Sstevel@tonic-gate */ 310Sstevel@tonic-gate 320Sstevel@tonic-gate #include <sys/types.h> 330Sstevel@tonic-gate #include <sys/param.h> 340Sstevel@tonic-gate #include <sys/systm.h> 350Sstevel@tonic-gate #include <sys/vnode.h> 360Sstevel@tonic-gate #include <sys/uio.h> 370Sstevel@tonic-gate #include <sys/cred.h> 380Sstevel@tonic-gate #include <sys/kmem.h> 390Sstevel@tonic-gate #include <sys/errno.h> 400Sstevel@tonic-gate #include <sys/modctl.h> 410Sstevel@tonic-gate #include <sys/dumphdr.h> 420Sstevel@tonic-gate #include <sys/dumpadm.h> 430Sstevel@tonic-gate #include <sys/pathname.h> 440Sstevel@tonic-gate #include <sys/file.h> 450Sstevel@tonic-gate #include <vm/anon.h> 460Sstevel@tonic-gate #include <sys/stat.h> 470Sstevel@tonic-gate #include <sys/conf.h> 480Sstevel@tonic-gate #include <sys/ddi.h> 490Sstevel@tonic-gate #include <sys/sunddi.h> 500Sstevel@tonic-gate 510Sstevel@tonic-gate static dev_info_t *dump_devi; 520Sstevel@tonic-gate 530Sstevel@tonic-gate static int 540Sstevel@tonic-gate dump_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 550Sstevel@tonic-gate { 560Sstevel@tonic-gate if (cmd != DDI_ATTACH) 570Sstevel@tonic-gate return (DDI_FAILURE); 580Sstevel@tonic-gate if (ddi_create_minor_node(devi, "dump", S_IFCHR, 0, DDI_PSEUDO, NULL) == 590Sstevel@tonic-gate DDI_FAILURE) { 600Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 610Sstevel@tonic-gate return (DDI_FAILURE); 620Sstevel@tonic-gate } 630Sstevel@tonic-gate dump_devi = devi; 640Sstevel@tonic-gate return (DDI_SUCCESS); 650Sstevel@tonic-gate } 660Sstevel@tonic-gate 670Sstevel@tonic-gate static int 680Sstevel@tonic-gate dump_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 690Sstevel@tonic-gate { 700Sstevel@tonic-gate if (cmd != DDI_DETACH) 710Sstevel@tonic-gate return (DDI_FAILURE); 720Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 730Sstevel@tonic-gate return (DDI_SUCCESS); 740Sstevel@tonic-gate } 750Sstevel@tonic-gate 760Sstevel@tonic-gate /*ARGSUSED*/ 770Sstevel@tonic-gate static int 780Sstevel@tonic-gate dump_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 790Sstevel@tonic-gate { 800Sstevel@tonic-gate switch (infocmd) { 810Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 820Sstevel@tonic-gate *result = dump_devi; 830Sstevel@tonic-gate return (DDI_SUCCESS); 840Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 850Sstevel@tonic-gate *result = 0; 860Sstevel@tonic-gate return (DDI_SUCCESS); 870Sstevel@tonic-gate } 880Sstevel@tonic-gate return (DDI_FAILURE); 890Sstevel@tonic-gate } 900Sstevel@tonic-gate 910Sstevel@tonic-gate /*ARGSUSED*/ 920Sstevel@tonic-gate int 930Sstevel@tonic-gate dump_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred, int *rvalp) 940Sstevel@tonic-gate { 950Sstevel@tonic-gate uint64_t size; 960Sstevel@tonic-gate uint64_t dumpsize_in_pages; 970Sstevel@tonic-gate int error = 0; 980Sstevel@tonic-gate char *pathbuf = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 990Sstevel@tonic-gate vnode_t *vp; 1000Sstevel@tonic-gate 1010Sstevel@tonic-gate switch (cmd) { 1020Sstevel@tonic-gate case DIOCGETDUMPSIZE: 1030Sstevel@tonic-gate if (dump_conflags & DUMP_ALL) 1040Sstevel@tonic-gate size = ptob((uint64_t)physmem) / DUMP_COMPRESS_RATIO; 1050Sstevel@tonic-gate else { 1060Sstevel@tonic-gate /* 1070Sstevel@tonic-gate * We can't give a good answer for the DUMP_CURPROC 1080Sstevel@tonic-gate * because we won't know which process to use until it 1090Sstevel@tonic-gate * causes a panic. We'll therefore punt and give the 1100Sstevel@tonic-gate * caller the size for the kernel. 1110Sstevel@tonic-gate * 1120Sstevel@tonic-gate * This kernel size equation takes care of the 1130Sstevel@tonic-gate * boot time kernel footprint and also accounts 1140Sstevel@tonic-gate * for availrmem changes due to user explicit locking. 1150Sstevel@tonic-gate * Refer to common/vm/vm_page.c for an explanation 1160Sstevel@tonic-gate * of these counters. 1170Sstevel@tonic-gate */ 1180Sstevel@tonic-gate dumpsize_in_pages = (physinstalled - obp_pages - 1190Sstevel@tonic-gate availrmem - 1200Sstevel@tonic-gate anon_segkp_pages_locked - 1210Sstevel@tonic-gate k_anoninfo.ani_mem_resv - 1220Sstevel@tonic-gate segvn_pages_locked - 1230Sstevel@tonic-gate pages_locked - 1240Sstevel@tonic-gate pages_claimed - 1250Sstevel@tonic-gate pages_useclaim); 1260Sstevel@tonic-gate 127*4578Ssp92102 /* 128*4578Ssp92102 * Protect against vm vagaries. 129*4578Ssp92102 */ 130*4578Ssp92102 if (dumpsize_in_pages > (uint64_t)physmem) 131*4578Ssp92102 dumpsize_in_pages = (uint64_t)physmem; 132*4578Ssp92102 1330Sstevel@tonic-gate size = ptob(dumpsize_in_pages) / DUMP_COMPRESS_RATIO; 1340Sstevel@tonic-gate } 1350Sstevel@tonic-gate if (copyout(&size, (void *)arg, sizeof (size)) < 0) 1360Sstevel@tonic-gate error = EFAULT; 1370Sstevel@tonic-gate break; 1380Sstevel@tonic-gate 1390Sstevel@tonic-gate case DIOCGETCONF: 1400Sstevel@tonic-gate mutex_enter(&dump_lock); 1410Sstevel@tonic-gate *rvalp = dump_conflags; 1420Sstevel@tonic-gate if (dumpvp && !(dumpvp->v_flag & VISSWAP)) 1430Sstevel@tonic-gate *rvalp |= DUMP_EXCL; 1440Sstevel@tonic-gate mutex_exit(&dump_lock); 1450Sstevel@tonic-gate break; 1460Sstevel@tonic-gate 1470Sstevel@tonic-gate case DIOCSETCONF: 1480Sstevel@tonic-gate mutex_enter(&dump_lock); 1490Sstevel@tonic-gate if (arg == DUMP_KERNEL || arg == DUMP_ALL || 1500Sstevel@tonic-gate arg == DUMP_CURPROC) 1510Sstevel@tonic-gate dump_conflags = arg; 1520Sstevel@tonic-gate else 1530Sstevel@tonic-gate error = EINVAL; 1540Sstevel@tonic-gate mutex_exit(&dump_lock); 1550Sstevel@tonic-gate break; 1560Sstevel@tonic-gate 1570Sstevel@tonic-gate case DIOCGETDEV: 1580Sstevel@tonic-gate mutex_enter(&dump_lock); 1590Sstevel@tonic-gate if (dumppath == NULL) { 1600Sstevel@tonic-gate mutex_exit(&dump_lock); 1610Sstevel@tonic-gate error = ENODEV; 1620Sstevel@tonic-gate break; 1630Sstevel@tonic-gate } 1640Sstevel@tonic-gate (void) strcpy(pathbuf, dumppath); 1650Sstevel@tonic-gate mutex_exit(&dump_lock); 1660Sstevel@tonic-gate error = copyoutstr(pathbuf, (void *)arg, MAXPATHLEN, NULL); 1670Sstevel@tonic-gate break; 1680Sstevel@tonic-gate 1690Sstevel@tonic-gate case DIOCSETDEV: 1700Sstevel@tonic-gate case DIOCTRYDEV: 1710Sstevel@tonic-gate if ((error = copyinstr((char *)arg, pathbuf, MAXPATHLEN, 1720Sstevel@tonic-gate NULL)) != 0 || (error = lookupname(pathbuf, UIO_SYSSPACE, 1730Sstevel@tonic-gate FOLLOW, NULLVPP, &vp)) != 0) 1740Sstevel@tonic-gate break; 1750Sstevel@tonic-gate mutex_enter(&dump_lock); 1760Sstevel@tonic-gate error = dumpinit(vp, pathbuf, cmd == DIOCTRYDEV); 1770Sstevel@tonic-gate mutex_exit(&dump_lock); 1780Sstevel@tonic-gate VN_RELE(vp); 1790Sstevel@tonic-gate break; 1800Sstevel@tonic-gate 1810Sstevel@tonic-gate case DIOCDUMP: 1820Sstevel@tonic-gate mutex_enter(&dump_lock); 1830Sstevel@tonic-gate if (dumpvp == NULL) 1840Sstevel@tonic-gate error = ENODEV; 1850Sstevel@tonic-gate else if (dumpvp->v_flag & VISSWAP) 1860Sstevel@tonic-gate error = EBUSY; 1870Sstevel@tonic-gate else 1880Sstevel@tonic-gate dumpsys(); 1890Sstevel@tonic-gate mutex_exit(&dump_lock); 1900Sstevel@tonic-gate break; 1910Sstevel@tonic-gate 1920Sstevel@tonic-gate default: 1930Sstevel@tonic-gate error = ENXIO; 1940Sstevel@tonic-gate } 1950Sstevel@tonic-gate 1960Sstevel@tonic-gate kmem_free(pathbuf, MAXPATHLEN); 1970Sstevel@tonic-gate return (error); 1980Sstevel@tonic-gate } 1990Sstevel@tonic-gate 2000Sstevel@tonic-gate struct cb_ops dump_cb_ops = { 2010Sstevel@tonic-gate nulldev, /* open */ 2020Sstevel@tonic-gate nulldev, /* close */ 2030Sstevel@tonic-gate nodev, /* strategy */ 2040Sstevel@tonic-gate nodev, /* print */ 2050Sstevel@tonic-gate nodev, /* dump */ 2060Sstevel@tonic-gate nodev, /* read */ 2070Sstevel@tonic-gate nodev, /* write */ 2080Sstevel@tonic-gate dump_ioctl, /* ioctl */ 2090Sstevel@tonic-gate nodev, /* devmap */ 2100Sstevel@tonic-gate nodev, /* mmap */ 2110Sstevel@tonic-gate nodev, /* segmap */ 2120Sstevel@tonic-gate nochpoll, /* poll */ 2130Sstevel@tonic-gate ddi_prop_op, /* prop_op */ 2140Sstevel@tonic-gate 0, /* streamtab */ 2150Sstevel@tonic-gate D_NEW|D_MP /* Driver compatibility flag */ 2160Sstevel@tonic-gate }; 2170Sstevel@tonic-gate 2180Sstevel@tonic-gate struct dev_ops dump_ops = { 2190Sstevel@tonic-gate DEVO_REV, /* devo_rev, */ 2200Sstevel@tonic-gate 0, /* refcnt */ 2210Sstevel@tonic-gate dump_info, /* info */ 2220Sstevel@tonic-gate nulldev, /* identify */ 2230Sstevel@tonic-gate nulldev, /* probe */ 2240Sstevel@tonic-gate dump_attach, /* attach */ 2250Sstevel@tonic-gate dump_detach, /* detach */ 2260Sstevel@tonic-gate nodev, /* reset */ 2270Sstevel@tonic-gate &dump_cb_ops, /* driver operations */ 2280Sstevel@tonic-gate (struct bus_ops *)0 /* bus operations */ 2290Sstevel@tonic-gate }; 2300Sstevel@tonic-gate 2310Sstevel@tonic-gate static struct modldrv modldrv = { 2320Sstevel@tonic-gate &mod_driverops, "crash dump driver %I%", &dump_ops, 2330Sstevel@tonic-gate }; 2340Sstevel@tonic-gate 2350Sstevel@tonic-gate static struct modlinkage modlinkage = { 2360Sstevel@tonic-gate MODREV_1, (void *)&modldrv, NULL 2370Sstevel@tonic-gate }; 2380Sstevel@tonic-gate 2390Sstevel@tonic-gate int 2400Sstevel@tonic-gate _init(void) 2410Sstevel@tonic-gate { 2420Sstevel@tonic-gate return (mod_install(&modlinkage)); 2430Sstevel@tonic-gate } 2440Sstevel@tonic-gate 2450Sstevel@tonic-gate int 2460Sstevel@tonic-gate _fini(void) 2470Sstevel@tonic-gate { 2480Sstevel@tonic-gate return (mod_remove(&modlinkage)); 2490Sstevel@tonic-gate } 2500Sstevel@tonic-gate 2510Sstevel@tonic-gate int 2520Sstevel@tonic-gate _info(struct modinfo *modinfop) 2530Sstevel@tonic-gate { 2540Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 2550Sstevel@tonic-gate } 256