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 /* 22*12967Sgavin.maltby@oracle.com * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. 230Sstevel@tonic-gate */ 240Sstevel@tonic-gate 250Sstevel@tonic-gate 260Sstevel@tonic-gate /* 270Sstevel@tonic-gate * Dump driver. Provides ioctls to get/set crash dump configuration. 280Sstevel@tonic-gate */ 290Sstevel@tonic-gate 300Sstevel@tonic-gate #include <sys/types.h> 310Sstevel@tonic-gate #include <sys/param.h> 320Sstevel@tonic-gate #include <sys/systm.h> 330Sstevel@tonic-gate #include <sys/vnode.h> 340Sstevel@tonic-gate #include <sys/uio.h> 350Sstevel@tonic-gate #include <sys/cred.h> 360Sstevel@tonic-gate #include <sys/kmem.h> 370Sstevel@tonic-gate #include <sys/errno.h> 380Sstevel@tonic-gate #include <sys/modctl.h> 390Sstevel@tonic-gate #include <sys/dumphdr.h> 400Sstevel@tonic-gate #include <sys/dumpadm.h> 410Sstevel@tonic-gate #include <sys/pathname.h> 420Sstevel@tonic-gate #include <sys/file.h> 430Sstevel@tonic-gate #include <vm/anon.h> 440Sstevel@tonic-gate #include <sys/stat.h> 450Sstevel@tonic-gate #include <sys/conf.h> 460Sstevel@tonic-gate #include <sys/ddi.h> 470Sstevel@tonic-gate #include <sys/sunddi.h> 480Sstevel@tonic-gate 490Sstevel@tonic-gate static dev_info_t *dump_devi; 500Sstevel@tonic-gate 510Sstevel@tonic-gate static int 520Sstevel@tonic-gate dump_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 530Sstevel@tonic-gate { 540Sstevel@tonic-gate if (cmd != DDI_ATTACH) 550Sstevel@tonic-gate return (DDI_FAILURE); 560Sstevel@tonic-gate if (ddi_create_minor_node(devi, "dump", S_IFCHR, 0, DDI_PSEUDO, NULL) == 570Sstevel@tonic-gate DDI_FAILURE) { 580Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 590Sstevel@tonic-gate return (DDI_FAILURE); 600Sstevel@tonic-gate } 610Sstevel@tonic-gate dump_devi = devi; 620Sstevel@tonic-gate return (DDI_SUCCESS); 630Sstevel@tonic-gate } 640Sstevel@tonic-gate 650Sstevel@tonic-gate static int 660Sstevel@tonic-gate dump_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 670Sstevel@tonic-gate { 680Sstevel@tonic-gate if (cmd != DDI_DETACH) 690Sstevel@tonic-gate return (DDI_FAILURE); 700Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 710Sstevel@tonic-gate return (DDI_SUCCESS); 720Sstevel@tonic-gate } 730Sstevel@tonic-gate 740Sstevel@tonic-gate /*ARGSUSED*/ 750Sstevel@tonic-gate static int 760Sstevel@tonic-gate dump_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 770Sstevel@tonic-gate { 780Sstevel@tonic-gate switch (infocmd) { 790Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 800Sstevel@tonic-gate *result = dump_devi; 810Sstevel@tonic-gate return (DDI_SUCCESS); 820Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 830Sstevel@tonic-gate *result = 0; 840Sstevel@tonic-gate return (DDI_SUCCESS); 850Sstevel@tonic-gate } 860Sstevel@tonic-gate return (DDI_FAILURE); 870Sstevel@tonic-gate } 880Sstevel@tonic-gate 890Sstevel@tonic-gate /*ARGSUSED*/ 900Sstevel@tonic-gate int 910Sstevel@tonic-gate dump_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred, int *rvalp) 920Sstevel@tonic-gate { 930Sstevel@tonic-gate uint64_t size; 940Sstevel@tonic-gate uint64_t dumpsize_in_pages; 950Sstevel@tonic-gate int error = 0; 960Sstevel@tonic-gate char *pathbuf = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 97*12967Sgavin.maltby@oracle.com char uuidbuf[36 + 1]; 98*12967Sgavin.maltby@oracle.com size_t len; 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 - 1196695Saguzovsk availrmem - 1206695Saguzovsk anon_segkp_pages_locked - 1216695Saguzovsk k_anoninfo.ani_mem_resv - 1226695Saguzovsk pages_locked - 1236695Saguzovsk pages_claimed - 1246695Saguzovsk pages_useclaim); 1250Sstevel@tonic-gate 1264578Ssp92102 /* 1274578Ssp92102 * Protect against vm vagaries. 1284578Ssp92102 */ 1294578Ssp92102 if (dumpsize_in_pages > (uint64_t)physmem) 1304578Ssp92102 dumpsize_in_pages = (uint64_t)physmem; 1314578Ssp92102 1320Sstevel@tonic-gate size = ptob(dumpsize_in_pages) / DUMP_COMPRESS_RATIO; 1330Sstevel@tonic-gate } 1340Sstevel@tonic-gate if (copyout(&size, (void *)arg, sizeof (size)) < 0) 1350Sstevel@tonic-gate error = EFAULT; 1360Sstevel@tonic-gate break; 1370Sstevel@tonic-gate 1380Sstevel@tonic-gate case DIOCGETCONF: 1390Sstevel@tonic-gate mutex_enter(&dump_lock); 1400Sstevel@tonic-gate *rvalp = dump_conflags; 1410Sstevel@tonic-gate if (dumpvp && !(dumpvp->v_flag & VISSWAP)) 1420Sstevel@tonic-gate *rvalp |= DUMP_EXCL; 1430Sstevel@tonic-gate mutex_exit(&dump_lock); 1440Sstevel@tonic-gate break; 1450Sstevel@tonic-gate 1460Sstevel@tonic-gate case DIOCSETCONF: 1470Sstevel@tonic-gate mutex_enter(&dump_lock); 1480Sstevel@tonic-gate if (arg == DUMP_KERNEL || arg == DUMP_ALL || 1490Sstevel@tonic-gate arg == DUMP_CURPROC) 1500Sstevel@tonic-gate dump_conflags = arg; 1510Sstevel@tonic-gate else 1520Sstevel@tonic-gate error = EINVAL; 1530Sstevel@tonic-gate mutex_exit(&dump_lock); 1540Sstevel@tonic-gate break; 1550Sstevel@tonic-gate 1560Sstevel@tonic-gate case DIOCGETDEV: 1570Sstevel@tonic-gate mutex_enter(&dump_lock); 1580Sstevel@tonic-gate if (dumppath == NULL) { 1590Sstevel@tonic-gate mutex_exit(&dump_lock); 1600Sstevel@tonic-gate error = ENODEV; 1610Sstevel@tonic-gate break; 1620Sstevel@tonic-gate } 1630Sstevel@tonic-gate (void) strcpy(pathbuf, dumppath); 1640Sstevel@tonic-gate mutex_exit(&dump_lock); 1650Sstevel@tonic-gate error = copyoutstr(pathbuf, (void *)arg, MAXPATHLEN, NULL); 1660Sstevel@tonic-gate break; 1670Sstevel@tonic-gate 1680Sstevel@tonic-gate case DIOCSETDEV: 1690Sstevel@tonic-gate case DIOCTRYDEV: 1700Sstevel@tonic-gate if ((error = copyinstr((char *)arg, pathbuf, MAXPATHLEN, 1710Sstevel@tonic-gate NULL)) != 0 || (error = lookupname(pathbuf, UIO_SYSSPACE, 1720Sstevel@tonic-gate FOLLOW, NULLVPP, &vp)) != 0) 1730Sstevel@tonic-gate break; 1740Sstevel@tonic-gate mutex_enter(&dump_lock); 1756423Sgw25295 if (vp->v_type == VBLK) 1766423Sgw25295 error = dumpinit(vp, pathbuf, cmd == DIOCTRYDEV); 1776423Sgw25295 else 1786423Sgw25295 error = ENOTBLK; 1790Sstevel@tonic-gate mutex_exit(&dump_lock); 1800Sstevel@tonic-gate VN_RELE(vp); 1810Sstevel@tonic-gate break; 1820Sstevel@tonic-gate 1830Sstevel@tonic-gate case DIOCDUMP: 1840Sstevel@tonic-gate mutex_enter(&dump_lock); 1850Sstevel@tonic-gate if (dumpvp == NULL) 1860Sstevel@tonic-gate error = ENODEV; 1870Sstevel@tonic-gate else if (dumpvp->v_flag & VISSWAP) 1880Sstevel@tonic-gate error = EBUSY; 1890Sstevel@tonic-gate else 1900Sstevel@tonic-gate dumpsys(); 1910Sstevel@tonic-gate mutex_exit(&dump_lock); 1920Sstevel@tonic-gate break; 1930Sstevel@tonic-gate 194*12967Sgavin.maltby@oracle.com case DIOCSETUUID: 195*12967Sgavin.maltby@oracle.com if ((error = copyinstr((char *)arg, uuidbuf, sizeof (uuidbuf), 196*12967Sgavin.maltby@oracle.com &len)) != 0) 197*12967Sgavin.maltby@oracle.com break; 198*12967Sgavin.maltby@oracle.com 199*12967Sgavin.maltby@oracle.com if (len != 37) { 200*12967Sgavin.maltby@oracle.com error = EINVAL; 201*12967Sgavin.maltby@oracle.com break; 202*12967Sgavin.maltby@oracle.com } 203*12967Sgavin.maltby@oracle.com 204*12967Sgavin.maltby@oracle.com error = dump_set_uuid(uuidbuf); 205*12967Sgavin.maltby@oracle.com break; 206*12967Sgavin.maltby@oracle.com 207*12967Sgavin.maltby@oracle.com case DIOCGETUUID: 208*12967Sgavin.maltby@oracle.com error = copyoutstr(dump_get_uuid(), (void *)arg, 37, NULL); 209*12967Sgavin.maltby@oracle.com break; 210*12967Sgavin.maltby@oracle.com 2110Sstevel@tonic-gate default: 2120Sstevel@tonic-gate error = ENXIO; 2130Sstevel@tonic-gate } 2140Sstevel@tonic-gate 2150Sstevel@tonic-gate kmem_free(pathbuf, MAXPATHLEN); 2160Sstevel@tonic-gate return (error); 2170Sstevel@tonic-gate } 2180Sstevel@tonic-gate 2190Sstevel@tonic-gate struct cb_ops dump_cb_ops = { 2200Sstevel@tonic-gate nulldev, /* open */ 2210Sstevel@tonic-gate nulldev, /* close */ 2220Sstevel@tonic-gate nodev, /* strategy */ 2230Sstevel@tonic-gate nodev, /* print */ 2240Sstevel@tonic-gate nodev, /* dump */ 2250Sstevel@tonic-gate nodev, /* read */ 2260Sstevel@tonic-gate nodev, /* write */ 2270Sstevel@tonic-gate dump_ioctl, /* ioctl */ 2280Sstevel@tonic-gate nodev, /* devmap */ 2290Sstevel@tonic-gate nodev, /* mmap */ 2300Sstevel@tonic-gate nodev, /* segmap */ 2310Sstevel@tonic-gate nochpoll, /* poll */ 2320Sstevel@tonic-gate ddi_prop_op, /* prop_op */ 2330Sstevel@tonic-gate 0, /* streamtab */ 2340Sstevel@tonic-gate D_NEW|D_MP /* Driver compatibility flag */ 2350Sstevel@tonic-gate }; 2360Sstevel@tonic-gate 2370Sstevel@tonic-gate struct dev_ops dump_ops = { 2380Sstevel@tonic-gate DEVO_REV, /* devo_rev, */ 2390Sstevel@tonic-gate 0, /* refcnt */ 2400Sstevel@tonic-gate dump_info, /* info */ 2410Sstevel@tonic-gate nulldev, /* identify */ 2420Sstevel@tonic-gate nulldev, /* probe */ 2430Sstevel@tonic-gate dump_attach, /* attach */ 2440Sstevel@tonic-gate dump_detach, /* detach */ 2450Sstevel@tonic-gate nodev, /* reset */ 2460Sstevel@tonic-gate &dump_cb_ops, /* driver operations */ 2477656SSherry.Moore@Sun.COM (struct bus_ops *)0, /* bus operations */ 2487656SSherry.Moore@Sun.COM NULL, /* power */ 2497656SSherry.Moore@Sun.COM ddi_quiesce_not_needed, /* quiesce */ 2500Sstevel@tonic-gate }; 2510Sstevel@tonic-gate 2520Sstevel@tonic-gate static struct modldrv modldrv = { 2537656SSherry.Moore@Sun.COM &mod_driverops, "crash dump driver", &dump_ops, 2540Sstevel@tonic-gate }; 2550Sstevel@tonic-gate 2560Sstevel@tonic-gate static struct modlinkage modlinkage = { 2570Sstevel@tonic-gate MODREV_1, (void *)&modldrv, NULL 2580Sstevel@tonic-gate }; 2590Sstevel@tonic-gate 2600Sstevel@tonic-gate int 2610Sstevel@tonic-gate _init(void) 2620Sstevel@tonic-gate { 2630Sstevel@tonic-gate return (mod_install(&modlinkage)); 2640Sstevel@tonic-gate } 2650Sstevel@tonic-gate 2660Sstevel@tonic-gate int 2670Sstevel@tonic-gate _fini(void) 2680Sstevel@tonic-gate { 2690Sstevel@tonic-gate return (mod_remove(&modlinkage)); 2700Sstevel@tonic-gate } 2710Sstevel@tonic-gate 2720Sstevel@tonic-gate int 2730Sstevel@tonic-gate _info(struct modinfo *modinfop) 2740Sstevel@tonic-gate { 2750Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 2760Sstevel@tonic-gate } 277