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