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 54578Ssp92102 * Common Development and Distribution License (the "License"). 64578Ssp92102 * 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 /* 226423Sgw25295 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate 270Sstevel@tonic-gate /* 280Sstevel@tonic-gate * Dump driver. Provides ioctls to get/set crash dump configuration. 290Sstevel@tonic-gate */ 300Sstevel@tonic-gate 310Sstevel@tonic-gate #include <sys/types.h> 320Sstevel@tonic-gate #include <sys/param.h> 330Sstevel@tonic-gate #include <sys/systm.h> 340Sstevel@tonic-gate #include <sys/vnode.h> 350Sstevel@tonic-gate #include <sys/uio.h> 360Sstevel@tonic-gate #include <sys/cred.h> 370Sstevel@tonic-gate #include <sys/kmem.h> 380Sstevel@tonic-gate #include <sys/errno.h> 390Sstevel@tonic-gate #include <sys/modctl.h> 400Sstevel@tonic-gate #include <sys/dumphdr.h> 410Sstevel@tonic-gate #include <sys/dumpadm.h> 420Sstevel@tonic-gate #include <sys/pathname.h> 430Sstevel@tonic-gate #include <sys/file.h> 440Sstevel@tonic-gate #include <vm/anon.h> 450Sstevel@tonic-gate #include <sys/stat.h> 460Sstevel@tonic-gate #include <sys/conf.h> 470Sstevel@tonic-gate #include <sys/ddi.h> 480Sstevel@tonic-gate #include <sys/sunddi.h> 490Sstevel@tonic-gate 500Sstevel@tonic-gate static dev_info_t *dump_devi; 510Sstevel@tonic-gate 520Sstevel@tonic-gate static int 530Sstevel@tonic-gate dump_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 540Sstevel@tonic-gate { 550Sstevel@tonic-gate if (cmd != DDI_ATTACH) 560Sstevel@tonic-gate return (DDI_FAILURE); 570Sstevel@tonic-gate if (ddi_create_minor_node(devi, "dump", S_IFCHR, 0, DDI_PSEUDO, NULL) == 580Sstevel@tonic-gate DDI_FAILURE) { 590Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 600Sstevel@tonic-gate return (DDI_FAILURE); 610Sstevel@tonic-gate } 620Sstevel@tonic-gate dump_devi = devi; 630Sstevel@tonic-gate return (DDI_SUCCESS); 640Sstevel@tonic-gate } 650Sstevel@tonic-gate 660Sstevel@tonic-gate static int 670Sstevel@tonic-gate dump_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 680Sstevel@tonic-gate { 690Sstevel@tonic-gate if (cmd != DDI_DETACH) 700Sstevel@tonic-gate return (DDI_FAILURE); 710Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 720Sstevel@tonic-gate return (DDI_SUCCESS); 730Sstevel@tonic-gate } 740Sstevel@tonic-gate 750Sstevel@tonic-gate /*ARGSUSED*/ 760Sstevel@tonic-gate static int 770Sstevel@tonic-gate dump_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 780Sstevel@tonic-gate { 790Sstevel@tonic-gate switch (infocmd) { 800Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 810Sstevel@tonic-gate *result = dump_devi; 820Sstevel@tonic-gate return (DDI_SUCCESS); 830Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 840Sstevel@tonic-gate *result = 0; 850Sstevel@tonic-gate return (DDI_SUCCESS); 860Sstevel@tonic-gate } 870Sstevel@tonic-gate return (DDI_FAILURE); 880Sstevel@tonic-gate } 890Sstevel@tonic-gate 900Sstevel@tonic-gate /*ARGSUSED*/ 910Sstevel@tonic-gate int 920Sstevel@tonic-gate dump_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred, int *rvalp) 930Sstevel@tonic-gate { 940Sstevel@tonic-gate uint64_t size; 950Sstevel@tonic-gate uint64_t dumpsize_in_pages; 960Sstevel@tonic-gate int error = 0; 970Sstevel@tonic-gate char *pathbuf = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 980Sstevel@tonic-gate vnode_t *vp; 990Sstevel@tonic-gate 1000Sstevel@tonic-gate switch (cmd) { 1010Sstevel@tonic-gate case DIOCGETDUMPSIZE: 1020Sstevel@tonic-gate if (dump_conflags & DUMP_ALL) 1030Sstevel@tonic-gate size = ptob((uint64_t)physmem) / DUMP_COMPRESS_RATIO; 1040Sstevel@tonic-gate else { 1050Sstevel@tonic-gate /* 1060Sstevel@tonic-gate * We can't give a good answer for the DUMP_CURPROC 1070Sstevel@tonic-gate * because we won't know which process to use until it 1080Sstevel@tonic-gate * causes a panic. We'll therefore punt and give the 1090Sstevel@tonic-gate * caller the size for the kernel. 1100Sstevel@tonic-gate * 1110Sstevel@tonic-gate * This kernel size equation takes care of the 1120Sstevel@tonic-gate * boot time kernel footprint and also accounts 1130Sstevel@tonic-gate * for availrmem changes due to user explicit locking. 1140Sstevel@tonic-gate * Refer to common/vm/vm_page.c for an explanation 1150Sstevel@tonic-gate * of these counters. 1160Sstevel@tonic-gate */ 1170Sstevel@tonic-gate dumpsize_in_pages = (physinstalled - obp_pages - 1186695Saguzovsk availrmem - 1196695Saguzovsk anon_segkp_pages_locked - 1206695Saguzovsk k_anoninfo.ani_mem_resv - 1216695Saguzovsk pages_locked - 1226695Saguzovsk pages_claimed - 1236695Saguzovsk pages_useclaim); 1240Sstevel@tonic-gate 1254578Ssp92102 /* 1264578Ssp92102 * Protect against vm vagaries. 1274578Ssp92102 */ 1284578Ssp92102 if (dumpsize_in_pages > (uint64_t)physmem) 1294578Ssp92102 dumpsize_in_pages = (uint64_t)physmem; 1304578Ssp92102 1310Sstevel@tonic-gate size = ptob(dumpsize_in_pages) / DUMP_COMPRESS_RATIO; 1320Sstevel@tonic-gate } 1330Sstevel@tonic-gate if (copyout(&size, (void *)arg, sizeof (size)) < 0) 1340Sstevel@tonic-gate error = EFAULT; 1350Sstevel@tonic-gate break; 1360Sstevel@tonic-gate 1370Sstevel@tonic-gate case DIOCGETCONF: 1380Sstevel@tonic-gate mutex_enter(&dump_lock); 1390Sstevel@tonic-gate *rvalp = dump_conflags; 1400Sstevel@tonic-gate if (dumpvp && !(dumpvp->v_flag & VISSWAP)) 1410Sstevel@tonic-gate *rvalp |= DUMP_EXCL; 1420Sstevel@tonic-gate mutex_exit(&dump_lock); 1430Sstevel@tonic-gate break; 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate case DIOCSETCONF: 1460Sstevel@tonic-gate mutex_enter(&dump_lock); 1470Sstevel@tonic-gate if (arg == DUMP_KERNEL || arg == DUMP_ALL || 1480Sstevel@tonic-gate arg == DUMP_CURPROC) 1490Sstevel@tonic-gate dump_conflags = arg; 1500Sstevel@tonic-gate else 1510Sstevel@tonic-gate error = EINVAL; 1520Sstevel@tonic-gate mutex_exit(&dump_lock); 1530Sstevel@tonic-gate break; 1540Sstevel@tonic-gate 1550Sstevel@tonic-gate case DIOCGETDEV: 1560Sstevel@tonic-gate mutex_enter(&dump_lock); 1570Sstevel@tonic-gate if (dumppath == NULL) { 1580Sstevel@tonic-gate mutex_exit(&dump_lock); 1590Sstevel@tonic-gate error = ENODEV; 1600Sstevel@tonic-gate break; 1610Sstevel@tonic-gate } 1620Sstevel@tonic-gate (void) strcpy(pathbuf, dumppath); 1630Sstevel@tonic-gate mutex_exit(&dump_lock); 1640Sstevel@tonic-gate error = copyoutstr(pathbuf, (void *)arg, MAXPATHLEN, NULL); 1650Sstevel@tonic-gate break; 1660Sstevel@tonic-gate 1670Sstevel@tonic-gate case DIOCSETDEV: 1680Sstevel@tonic-gate case DIOCTRYDEV: 1690Sstevel@tonic-gate if ((error = copyinstr((char *)arg, pathbuf, MAXPATHLEN, 1700Sstevel@tonic-gate NULL)) != 0 || (error = lookupname(pathbuf, UIO_SYSSPACE, 1710Sstevel@tonic-gate FOLLOW, NULLVPP, &vp)) != 0) 1720Sstevel@tonic-gate break; 1730Sstevel@tonic-gate mutex_enter(&dump_lock); 1746423Sgw25295 if (vp->v_type == VBLK) 1756423Sgw25295 error = dumpinit(vp, pathbuf, cmd == DIOCTRYDEV); 1766423Sgw25295 else 1776423Sgw25295 error = ENOTBLK; 1780Sstevel@tonic-gate mutex_exit(&dump_lock); 1790Sstevel@tonic-gate VN_RELE(vp); 1800Sstevel@tonic-gate break; 1810Sstevel@tonic-gate 1820Sstevel@tonic-gate case DIOCDUMP: 1830Sstevel@tonic-gate mutex_enter(&dump_lock); 1840Sstevel@tonic-gate if (dumpvp == NULL) 1850Sstevel@tonic-gate error = ENODEV; 1860Sstevel@tonic-gate else if (dumpvp->v_flag & VISSWAP) 1870Sstevel@tonic-gate error = EBUSY; 1880Sstevel@tonic-gate else 1890Sstevel@tonic-gate dumpsys(); 1900Sstevel@tonic-gate mutex_exit(&dump_lock); 1910Sstevel@tonic-gate break; 1920Sstevel@tonic-gate 1930Sstevel@tonic-gate default: 1940Sstevel@tonic-gate error = ENXIO; 1950Sstevel@tonic-gate } 1960Sstevel@tonic-gate 1970Sstevel@tonic-gate kmem_free(pathbuf, MAXPATHLEN); 1980Sstevel@tonic-gate return (error); 1990Sstevel@tonic-gate } 2000Sstevel@tonic-gate 2010Sstevel@tonic-gate struct cb_ops dump_cb_ops = { 2020Sstevel@tonic-gate nulldev, /* open */ 2030Sstevel@tonic-gate nulldev, /* close */ 2040Sstevel@tonic-gate nodev, /* strategy */ 2050Sstevel@tonic-gate nodev, /* print */ 2060Sstevel@tonic-gate nodev, /* dump */ 2070Sstevel@tonic-gate nodev, /* read */ 2080Sstevel@tonic-gate nodev, /* write */ 2090Sstevel@tonic-gate dump_ioctl, /* ioctl */ 2100Sstevel@tonic-gate nodev, /* devmap */ 2110Sstevel@tonic-gate nodev, /* mmap */ 2120Sstevel@tonic-gate nodev, /* segmap */ 2130Sstevel@tonic-gate nochpoll, /* poll */ 2140Sstevel@tonic-gate ddi_prop_op, /* prop_op */ 2150Sstevel@tonic-gate 0, /* streamtab */ 2160Sstevel@tonic-gate D_NEW|D_MP /* Driver compatibility flag */ 2170Sstevel@tonic-gate }; 2180Sstevel@tonic-gate 2190Sstevel@tonic-gate struct dev_ops dump_ops = { 2200Sstevel@tonic-gate DEVO_REV, /* devo_rev, */ 2210Sstevel@tonic-gate 0, /* refcnt */ 2220Sstevel@tonic-gate dump_info, /* info */ 2230Sstevel@tonic-gate nulldev, /* identify */ 2240Sstevel@tonic-gate nulldev, /* probe */ 2250Sstevel@tonic-gate dump_attach, /* attach */ 2260Sstevel@tonic-gate dump_detach, /* detach */ 2270Sstevel@tonic-gate nodev, /* reset */ 2280Sstevel@tonic-gate &dump_cb_ops, /* driver operations */ 229*7656SSherry.Moore@Sun.COM (struct bus_ops *)0, /* bus operations */ 230*7656SSherry.Moore@Sun.COM NULL, /* power */ 231*7656SSherry.Moore@Sun.COM ddi_quiesce_not_needed, /* quiesce */ 2320Sstevel@tonic-gate }; 2330Sstevel@tonic-gate 2340Sstevel@tonic-gate static struct modldrv modldrv = { 235*7656SSherry.Moore@Sun.COM &mod_driverops, "crash dump driver", &dump_ops, 2360Sstevel@tonic-gate }; 2370Sstevel@tonic-gate 2380Sstevel@tonic-gate static struct modlinkage modlinkage = { 2390Sstevel@tonic-gate MODREV_1, (void *)&modldrv, NULL 2400Sstevel@tonic-gate }; 2410Sstevel@tonic-gate 2420Sstevel@tonic-gate int 2430Sstevel@tonic-gate _init(void) 2440Sstevel@tonic-gate { 2450Sstevel@tonic-gate return (mod_install(&modlinkage)); 2460Sstevel@tonic-gate } 2470Sstevel@tonic-gate 2480Sstevel@tonic-gate int 2490Sstevel@tonic-gate _fini(void) 2500Sstevel@tonic-gate { 2510Sstevel@tonic-gate return (mod_remove(&modlinkage)); 2520Sstevel@tonic-gate } 2530Sstevel@tonic-gate 2540Sstevel@tonic-gate int 2550Sstevel@tonic-gate _info(struct modinfo *modinfop) 2560Sstevel@tonic-gate { 2570Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 2580Sstevel@tonic-gate } 259