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