1/* 2 * Kprobe module for testing crash dumps 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 * 18 * Copyright (C) IBM Corporation, 2006 19 * 20 * Author: Ankita Garg <ankita@in.ibm.com> 21 * Sachin Sant <sachinp@in.ibm.com> 22 * Cai Qian <qcai@redhat.com> 23 * 24 * This module induces system failures at predefined crashpoints to 25 * evaluate the reliability of crash dumps obtained using different dumping 26 * solutions. 27 * 28 * It is adapted from the Linux Kernel Dump Test Tool by 29 * Fernando Luis Vazquez Cao <http://lkdtt.sourceforge.net> 30 * 31 * Usage : insmod lkdtm.ko [recur_count={>0}] cpoint_name=<> cpoint_type=<> 32 * [cpoint_count={>0}] 33 * 34 * recur_count : Recursion level for the stack overflow test. Default is 10. 35 * 36 * cpoint_name : Crash point where the kernel is to be crashed. It can be 37 * one of INT_HARDWARE_ENTRY, INT_HW_IRQ_EN, INT_TASKLET_ENTRY, 38 * FS_DEVRW, MEM_SWAPOUT, TIMERADD, SCSI_DISPATCH_CMD, 39 * IDE_CORE_CP 40 * 41 * cpoint_type : Indicates the action to be taken on hitting the crash point. 42 * It can be one of PANIC, BUG, EXCEPTION, LOOP, OVERFLOW 43 * 44 * cpoint_count : Indicates the number of times the crash point is to be hit 45 * to trigger an action. The default is 10. 46 */ 47 48#include <linux/kernel.h> 49#include <linux/fs.h> 50#include <linux/module.h> 51#include <linux/buffer_head.h> 52#include <linux/kprobes.h> 53#include <linux/list.h> 54#include <linux/init.h> 55#include <linux/interrupt.h> 56#include <linux/hrtimer.h> 57#include <scsi/scsi_cmnd.h> 58#include <linux/version.h> 59#include <linux/kallsyms.h> 60 61#ifdef CONFIG_IDE 62#include <linux/ide.h> 63#endif 64 65#define NUM_CPOINTS 8 66#define NUM_CPOINT_TYPES 5 67#define DEFAULT_COUNT 10 68#define REC_NUM_DEFAULT 10 69 70enum cname { 71 INVALID, 72 INT_HARDWARE_ENTRY, 73 INT_HW_IRQ_EN, 74 INT_TASKLET_ENTRY, 75 FS_DEVRW, 76 MEM_SWAPOUT, 77 TIMERADD, 78 SCSI_DISPATCH_CMD, 79 IDE_CORE_CP 80}; 81 82enum ctype { 83 NONE, 84 PANIC, 85 BUG, 86 EXCEPTION, 87 LOOP, 88 OVERFLOW 89}; 90 91static char *cp_name[] = { 92 "INT_HARDWARE_ENTRY", 93 "INT_HW_IRQ_EN", 94 "INT_TASKLET_ENTRY", 95 "FS_DEVRW", 96 "MEM_SWAPOUT", 97 "TIMERADD", 98 "SCSI_DISPATCH_CMD", 99 "IDE_CORE_CP" 100}; 101 102static char *cp_type[] = { 103 "PANIC", 104 "BUG", 105 "EXCEPTION", 106 "LOOP", 107 "OVERFLOW" 108}; 109 110static struct jprobe lkdtm; 111 112static int lkdtm_parse_commandline(void); 113static void lkdtm_handler(void); 114 115static char *cpoint_name = INVALID; 116static char *cpoint_type = NONE; 117static int cpoint_count = DEFAULT_COUNT; 118static int recur_count = REC_NUM_DEFAULT; 119 120static enum cname cpoint = INVALID; 121static enum ctype cptype = NONE; 122static int count = DEFAULT_COUNT; 123 124module_param(recur_count, int, 0644); 125MODULE_PARM_DESC(recur_count, " Recursion level for the stack overflow test, " 126 "default is 10"); 127module_param(cpoint_name, charp, 0644); 128MODULE_PARM_DESC(cpoint_name, " Crash Point, where kernel is to be crashed"); 129module_param(cpoint_type, charp, 0644); 130MODULE_PARM_DESC(cpoint_type, " Crash Point Type, action to be taken on " 131 "hitting the crash point"); 132module_param(cpoint_count, int, 0644); 133MODULE_PARM_DESC(cpoint_count, " Crash Point Count, number of times the " 134 "crash point is to be hit to trigger action"); 135 136unsigned int jp_do_irq(unsigned int irq) 137{ 138 lkdtm_handler(); 139 jprobe_return(); 140 return 0; 141} 142 143irqreturn_t jp_handle_irq_event(unsigned int irq, struct irqaction * action) 144{ 145 lkdtm_handler(); 146 jprobe_return(); 147 return 0; 148} 149 150void jp_tasklet_action(struct softirq_action *a) 151{ 152 lkdtm_handler(); 153 jprobe_return(); 154} 155 156void jp_ll_rw_block(int rw, int nr, struct buffer_head *bhs[]) 157{ 158 lkdtm_handler(); 159 jprobe_return(); 160} 161 162struct scan_control; 163 164unsigned long jp_shrink_page_list(struct list_head *page_list, 165 struct scan_control *sc) 166{ 167 lkdtm_handler(); 168 jprobe_return(); 169 return 0; 170} 171 172int jp_hrtimer_start(struct hrtimer *timer, ktime_t tim, 173 const enum hrtimer_mode mode) 174{ 175 lkdtm_handler(); 176 jprobe_return(); 177 return 0; 178} 179 180int jp_scsi_dispatch_cmd(struct scsi_cmnd *cmd) 181{ 182 lkdtm_handler(); 183 jprobe_return(); 184 return 0; 185} 186 187#ifdef CONFIG_IDE 188int jp_generic_ide_ioctl(ide_drive_t * drive, struct file *file, 189 struct block_device *bdev, unsigned int cmd, 190 unsigned long arg) 191{ 192 lkdtm_handler(); 193 jprobe_return(); 194 return 0; 195} 196#endif 197 198static int lkdtm_parse_commandline(void) 199{ 200 int i; 201 202 if (cpoint_name == INVALID || cpoint_type == NONE || 203 cpoint_count < 1 || recur_count < 1) 204 return -EINVAL; 205 206 for (i = 0; i < NUM_CPOINTS; ++i) { 207 if (!strcmp(cpoint_name, cp_name[i])) { 208 cpoint = i + 1; 209 break; 210 } 211 } 212 213 for (i = 0; i < NUM_CPOINT_TYPES; ++i) { 214 if (!strcmp(cpoint_type, cp_type[i])) { 215 cptype = i + 1; 216 break; 217 } 218 } 219 220 if (cpoint == INVALID || cptype == NONE) 221 return -EINVAL; 222 223 count = cpoint_count; 224 225 return 0; 226} 227 228static int recursive_loop(int a) 229{ 230 char buf[1024]; 231 232 memset(buf, 0xFF, 1024); 233 recur_count--; 234 if (!recur_count) 235 return 0; 236 else 237 return recursive_loop(a); 238} 239 240void lkdtm_handler(void) 241{ 242 /* Escape endless loop. */ 243 if (count < 0) 244 return; 245 246 printk(KERN_INFO "lkdtm : Crash point %s of type %s hit\n", 247 cpoint_name, cpoint_type); 248 --count; 249 250 if (count == 0) { 251 switch (cptype) { 252 case NONE: 253 break; 254 case PANIC: 255 printk(KERN_INFO "lkdtm : PANIC\n"); 256 panic("dumptest"); 257 break; 258 case BUG: 259 printk(KERN_INFO "lkdtm : BUG\n"); 260 BUG(); 261 break; 262 case EXCEPTION: 263 printk(KERN_INFO "lkdtm : EXCEPTION\n"); 264 *((int *)0) = 0; 265 break; 266 case LOOP: 267 printk(KERN_INFO "lkdtm : LOOP\n"); 268 for (;;) ; 269 break; 270 case OVERFLOW: 271 printk(KERN_INFO "lkdtm : OVERFLOW\n"); 272 (void)recursive_loop(0); 273 break; 274 default: 275 break; 276 } 277 count = cpoint_count; 278 } 279} 280 281#ifdef USE_SYMBOL_NAME 282void lkdtm_symbol_name(char *name, void (*entry) (void)) 283{ 284 lkdtm.kp.symbol_name = name; 285 lkdtm.entry = (kprobe_opcode_t *) entry; 286} 287 288#else 289void lkdtm_lookup_name(char *name, void (*entry) (void)) 290{ 291 unsigned long addr; 292 293 addr = kallsyms_lookup_name(name); 294 if (addr) { 295 *(lkdtm.kp.addr) = addr; 296 lkdtm.entry = JPROBE_ENTRY(entry); 297 } else 298 printk(KERN_INFO "lkdtm : Crash point not available\n"); 299} 300#endif 301 302int lkdtm_module_init(void) 303{ 304 int ret; 305 306 if (lkdtm_parse_commandline() == -EINVAL) { 307 printk(KERN_INFO "lkdtm : Invalid command\n"); 308 return -EINVAL; 309 } 310 311 switch (cpoint) { 312 case INT_HARDWARE_ENTRY: 313 314#ifdef USE_SYMBOL_NAME 315 316#ifdef __powerpc__ 317 lkdtm_symbol_name(".__do_IRQ", (void (*)(void))jp_do_irq); 318#else 319 lkdtm_symbol_name("__do_IRQ", (void (*)(void))jp_do_irq); 320#endif /*__powerpc__*/ 321 322#else /* USE_SYMBOL_NAME */ 323 lkdtm_lookup_name("__do_IRQ", (void (*)(void))jp_do_irq); 324 325#endif /* USE_SYMBOL_NAME */ 326 break; 327 328 case INT_HW_IRQ_EN: 329 330#ifdef USE_SYMBOL_NAME 331 332#ifdef __powerpc__ 333 lkdtm_symbol_name(".handle_IRQ_event", 334 (void (*)(void))jp_handle_irq_event); 335#else 336 lkdtm_symbol_name("handle_IRQ_event", 337 (void (*)(void))jp_handle_irq_event); 338#endif /*__powerpc__*/ 339 340#else /* USE_SYMBOL_NAME */ 341 lkdtm_lookup_name("handle_IRQ_event", 342 (void (*)(void))jp_handle_irq_event); 343 344#endif /* USE_SYMBOL_NAME */ 345 break; 346 347 case INT_TASKLET_ENTRY: 348 349#ifdef USE_SYMBOL_NAME 350 351#ifdef __powerpc__ 352 lkdtm_symbol_name(".tasklet_action", 353 (void (*)(void))jp_tasklet_action); 354#else 355 lkdtm_symbol_name("tasklet_action", 356 (void (*)(void))jp_tasklet_action); 357#endif /*__powerpc__*/ 358 359#else /* USE_SYMBOL_NAME */ 360 lkdtm_lookup_name("tasklet_action", 361 (void (*)(void))jp_tasklet_action); 362 363#endif /* USE_SYMBOL_NAME */ 364 break; 365 366 case FS_DEVRW: 367 368#ifdef USE_SYMBOL_NAME 369 370#ifdef __powerpc__ 371 lkdtm_symbol_name(".ll_rw_block", 372 (void (*)(void))jp_ll_rw_block); 373#else 374 lkdtm_symbol_name("ll_rw_block", 375 (void (*)(void))jp_ll_rw_block); 376#endif /*__powerpc__*/ 377 378#else /* USE_SYMBOL_NAME */ 379 lkdtm_lookup_name("ll_rw_block", 380 (void (*)(void))jp_ll_rw_block); 381 382#endif /* USE_SYMBOL_NAME */ 383 break; 384 385 case MEM_SWAPOUT: 386 387#ifdef USE_SYMBOL_NAME 388 389#ifdef __powerpc__ 390 lkdtm_symbol_name(".shrink_inactive_list", 391 (void (*)(void))jp_shrink_page_list); 392#else 393 lkdtm_symbol_name("shrink_inactive_list", 394 (void (*)(void))jp_shrink_page_list); 395#endif /*__powerpc__*/ 396 397#else /* USE_SYMBOL_NAME */ 398 lkdtm_lookup_name("shrink_inactive_list", 399 (void (*)(void))jp_shrink_page_list); 400 401#endif /* USE_SYMBOL_NAME */ 402 break; 403 404 case TIMERADD: 405 406#ifdef USE_SYMBOL_NAME 407 408#ifdef __powerpc__ 409 lkdtm_symbol_name(".hrtimer_start", 410 (void (*)(void))jp_hrtimer_start); 411#else 412 lkdtm_symbol_name("hrtimer_start", 413 (void (*)(void))jp_hrtimer_start); 414#endif /*__powerpc__*/ 415 416#else /* USE_SYMBOL_NAME */ 417 lkdtm_lookup_name("hrtimer_start", 418 (void (*)(void))jp_hrtimer_start); 419 420#endif /* USE_SYMBOL_NAME */ 421 break; 422 423 case SCSI_DISPATCH_CMD: 424 425#ifdef USE_SYMBOL_NAME 426 427#ifdef __powerpc__ 428 lkdtm_symbol_name(".scsi_dispatch_cmd", 429 (void (*)(void))jp_scsi_dispatch_cmd); 430#else 431 lkdtm_symbol_name("scsi_dispatch_cmd", 432 (void (*)(void))jp_scsi_dispatch_cmd); 433#endif /*__powerpc__*/ 434 435#else /* USE_SYMBOL_NAME */ 436 lkdtm_lookup_name("scsi_dispatch_cmd", 437 (void (*)(void))jp_scsi_dispatch_cmd); 438 439#endif /* USE_SYMBOL_NAME */ 440 break; 441 442 case IDE_CORE_CP: 443#ifdef CONFIG_IDE 444 445#ifdef USE_SYMBOL_NAME 446 447#ifdef __powerpc__ 448 lkdtm_symbol_name(".scsi_dispatch_cmd", 449 (void (*)(void))jp_scsi_dispatch_cmd); 450#else 451 lkdtm_symbol_name("scsi_dispatch_cmd", 452 (void (*)(void))jp_scsi_dispatch_cmd); 453#endif /*__powerpc__*/ 454 455#else /* USE_SYMBOL_NAME */ 456 lkdtm_lookup_name("scsi_dispatch_cmd", 457 (void (*)(void))jp_scsi_dispatch_cmd); 458 459#endif /* USE_SYMBOL_NAME */ 460#endif /* CONFIG_IDE */ 461 break; 462 463 default: 464 printk(KERN_INFO "lkdtm : Invalid Crash Point\n"); 465 break; 466 } 467 468 if ((ret = register_jprobe(&lkdtm)) < 0) { 469 printk(KERN_INFO "lkdtm : Couldn't register jprobe\n"); 470 return ret; 471 } 472 473 printk(KERN_INFO "lkdtm : Crash point %s of type %s registered\n", 474 cpoint_name, cpoint_type); 475 return 0; 476} 477 478void lkdtm_module_exit(void) 479{ 480 unregister_jprobe(&lkdtm); 481 printk(KERN_INFO "lkdtm : Crash point unregistered\n"); 482} 483 484module_init(lkdtm_module_init); 485module_exit(lkdtm_module_exit); 486 487MODULE_LICENSE("GPL"); 488