Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.7-rc3 697 lines 16 kB view raw
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 * 22 * This module induces system failures at predefined crashpoints to 23 * evaluate the reliability of crash dumps obtained using different dumping 24 * solutions. 25 * 26 * It is adapted from the Linux Kernel Dump Test Tool by 27 * Fernando Luis Vazquez Cao <http://lkdtt.sourceforge.net> 28 * 29 * Debugfs support added by Simon Kagstrom <simon.kagstrom@netinsight.net> 30 * 31 * See Documentation/fault-injection/provoke-crashes.txt for instructions 32 */ 33 34#include <linux/kernel.h> 35#include <linux/fs.h> 36#include <linux/module.h> 37#include <linux/buffer_head.h> 38#include <linux/kprobes.h> 39#include <linux/list.h> 40#include <linux/init.h> 41#include <linux/interrupt.h> 42#include <linux/hrtimer.h> 43#include <linux/slab.h> 44#include <scsi/scsi_cmnd.h> 45#include <linux/debugfs.h> 46 47#ifdef CONFIG_IDE 48#include <linux/ide.h> 49#endif 50 51#define DEFAULT_COUNT 10 52#define REC_NUM_DEFAULT 10 53 54enum cname { 55 CN_INVALID, 56 CN_INT_HARDWARE_ENTRY, 57 CN_INT_HW_IRQ_EN, 58 CN_INT_TASKLET_ENTRY, 59 CN_FS_DEVRW, 60 CN_MEM_SWAPOUT, 61 CN_TIMERADD, 62 CN_SCSI_DISPATCH_CMD, 63 CN_IDE_CORE_CP, 64 CN_DIRECT, 65}; 66 67enum ctype { 68 CT_NONE, 69 CT_PANIC, 70 CT_BUG, 71 CT_EXCEPTION, 72 CT_LOOP, 73 CT_OVERFLOW, 74 CT_CORRUPT_STACK, 75 CT_UNALIGNED_LOAD_STORE_WRITE, 76 CT_OVERWRITE_ALLOCATION, 77 CT_WRITE_AFTER_FREE, 78 CT_SOFTLOCKUP, 79 CT_HARDLOCKUP, 80 CT_HUNG_TASK, 81}; 82 83static char* cp_name[] = { 84 "INT_HARDWARE_ENTRY", 85 "INT_HW_IRQ_EN", 86 "INT_TASKLET_ENTRY", 87 "FS_DEVRW", 88 "MEM_SWAPOUT", 89 "TIMERADD", 90 "SCSI_DISPATCH_CMD", 91 "IDE_CORE_CP", 92 "DIRECT", 93}; 94 95static char* cp_type[] = { 96 "PANIC", 97 "BUG", 98 "EXCEPTION", 99 "LOOP", 100 "OVERFLOW", 101 "CORRUPT_STACK", 102 "UNALIGNED_LOAD_STORE_WRITE", 103 "OVERWRITE_ALLOCATION", 104 "WRITE_AFTER_FREE", 105 "SOFTLOCKUP", 106 "HARDLOCKUP", 107 "HUNG_TASK", 108}; 109 110static struct jprobe lkdtm; 111 112static int lkdtm_parse_commandline(void); 113static void lkdtm_handler(void); 114 115static char* cpoint_name; 116static char* cpoint_type; 117static int cpoint_count = DEFAULT_COUNT; 118static int recur_count = REC_NUM_DEFAULT; 119 120static enum cname cpoint = CN_INVALID; 121static enum ctype cptype = CT_NONE; 122static int count = DEFAULT_COUNT; 123static DEFINE_SPINLOCK(count_lock); 124 125module_param(recur_count, int, 0644); 126MODULE_PARM_DESC(recur_count, " Recursion level for the stack overflow test, "\ 127 "default is 10"); 128module_param(cpoint_name, charp, 0444); 129MODULE_PARM_DESC(cpoint_name, " Crash Point, where kernel is to be crashed"); 130module_param(cpoint_type, charp, 0444); 131MODULE_PARM_DESC(cpoint_type, " Crash Point Type, action to be taken on "\ 132 "hitting the crash point"); 133module_param(cpoint_count, int, 0644); 134MODULE_PARM_DESC(cpoint_count, " Crash Point Count, number of times the "\ 135 "crash point is to be hit to trigger action"); 136 137static unsigned int jp_do_irq(unsigned int irq) 138{ 139 lkdtm_handler(); 140 jprobe_return(); 141 return 0; 142} 143 144static irqreturn_t jp_handle_irq_event(unsigned int irq, 145 struct irqaction *action) 146{ 147 lkdtm_handler(); 148 jprobe_return(); 149 return 0; 150} 151 152static void jp_tasklet_action(struct softirq_action *a) 153{ 154 lkdtm_handler(); 155 jprobe_return(); 156} 157 158static void jp_ll_rw_block(int rw, int nr, struct buffer_head *bhs[]) 159{ 160 lkdtm_handler(); 161 jprobe_return(); 162} 163 164struct scan_control; 165 166static unsigned long jp_shrink_inactive_list(unsigned long max_scan, 167 struct zone *zone, 168 struct scan_control *sc) 169{ 170 lkdtm_handler(); 171 jprobe_return(); 172 return 0; 173} 174 175static int jp_hrtimer_start(struct hrtimer *timer, ktime_t tim, 176 const enum hrtimer_mode mode) 177{ 178 lkdtm_handler(); 179 jprobe_return(); 180 return 0; 181} 182 183static int jp_scsi_dispatch_cmd(struct scsi_cmnd *cmd) 184{ 185 lkdtm_handler(); 186 jprobe_return(); 187 return 0; 188} 189 190#ifdef CONFIG_IDE 191int jp_generic_ide_ioctl(ide_drive_t *drive, struct file *file, 192 struct block_device *bdev, unsigned int cmd, 193 unsigned long arg) 194{ 195 lkdtm_handler(); 196 jprobe_return(); 197 return 0; 198} 199#endif 200 201/* Return the crashpoint number or NONE if the name is invalid */ 202static enum ctype parse_cp_type(const char *what, size_t count) 203{ 204 int i; 205 206 for (i = 0; i < ARRAY_SIZE(cp_type); i++) { 207 if (!strcmp(what, cp_type[i])) 208 return i + 1; 209 } 210 211 return CT_NONE; 212} 213 214static const char *cp_type_to_str(enum ctype type) 215{ 216 if (type == CT_NONE || type < 0 || type > ARRAY_SIZE(cp_type)) 217 return "None"; 218 219 return cp_type[type - 1]; 220} 221 222static const char *cp_name_to_str(enum cname name) 223{ 224 if (name == CN_INVALID || name < 0 || name > ARRAY_SIZE(cp_name)) 225 return "INVALID"; 226 227 return cp_name[name - 1]; 228} 229 230 231static int lkdtm_parse_commandline(void) 232{ 233 int i; 234 unsigned long flags; 235 236 if (cpoint_count < 1 || recur_count < 1) 237 return -EINVAL; 238 239 spin_lock_irqsave(&count_lock, flags); 240 count = cpoint_count; 241 spin_unlock_irqrestore(&count_lock, flags); 242 243 /* No special parameters */ 244 if (!cpoint_type && !cpoint_name) 245 return 0; 246 247 /* Neither or both of these need to be set */ 248 if (!cpoint_type || !cpoint_name) 249 return -EINVAL; 250 251 cptype = parse_cp_type(cpoint_type, strlen(cpoint_type)); 252 if (cptype == CT_NONE) 253 return -EINVAL; 254 255 for (i = 0; i < ARRAY_SIZE(cp_name); i++) { 256 if (!strcmp(cpoint_name, cp_name[i])) { 257 cpoint = i + 1; 258 return 0; 259 } 260 } 261 262 /* Could not find a valid crash point */ 263 return -EINVAL; 264} 265 266static int recursive_loop(int a) 267{ 268 char buf[1024]; 269 270 memset(buf,0xFF,1024); 271 recur_count--; 272 if (!recur_count) 273 return 0; 274 else 275 return recursive_loop(a); 276} 277 278static void lkdtm_do_action(enum ctype which) 279{ 280 switch (which) { 281 case CT_PANIC: 282 panic("dumptest"); 283 break; 284 case CT_BUG: 285 BUG(); 286 break; 287 case CT_EXCEPTION: 288 *((int *) 0) = 0; 289 break; 290 case CT_LOOP: 291 for (;;) 292 ; 293 break; 294 case CT_OVERFLOW: 295 (void) recursive_loop(0); 296 break; 297 case CT_CORRUPT_STACK: { 298 volatile u32 data[8]; 299 volatile u32 *p = data; 300 301 p[12] = 0x12345678; 302 break; 303 } 304 case CT_UNALIGNED_LOAD_STORE_WRITE: { 305 static u8 data[5] __attribute__((aligned(4))) = {1, 2, 306 3, 4, 5}; 307 u32 *p; 308 u32 val = 0x12345678; 309 310 p = (u32 *)(data + 1); 311 if (*p == 0) 312 val = 0x87654321; 313 *p = val; 314 break; 315 } 316 case CT_OVERWRITE_ALLOCATION: { 317 size_t len = 1020; 318 u32 *data = kmalloc(len, GFP_KERNEL); 319 320 data[1024 / sizeof(u32)] = 0x12345678; 321 kfree(data); 322 break; 323 } 324 case CT_WRITE_AFTER_FREE: { 325 size_t len = 1024; 326 u32 *data = kmalloc(len, GFP_KERNEL); 327 328 kfree(data); 329 schedule(); 330 memset(data, 0x78, len); 331 break; 332 } 333 case CT_SOFTLOCKUP: 334 preempt_disable(); 335 for (;;) 336 cpu_relax(); 337 break; 338 case CT_HARDLOCKUP: 339 local_irq_disable(); 340 for (;;) 341 cpu_relax(); 342 break; 343 case CT_HUNG_TASK: 344 set_current_state(TASK_UNINTERRUPTIBLE); 345 schedule(); 346 break; 347 case CT_NONE: 348 default: 349 break; 350 } 351 352} 353 354static void lkdtm_handler(void) 355{ 356 unsigned long flags; 357 bool do_it = false; 358 359 spin_lock_irqsave(&count_lock, flags); 360 count--; 361 printk(KERN_INFO "lkdtm: Crash point %s of type %s hit, trigger in %d rounds\n", 362 cp_name_to_str(cpoint), cp_type_to_str(cptype), count); 363 364 if (count == 0) { 365 do_it = true; 366 count = cpoint_count; 367 } 368 spin_unlock_irqrestore(&count_lock, flags); 369 370 if (do_it) 371 lkdtm_do_action(cptype); 372} 373 374static int lkdtm_register_cpoint(enum cname which) 375{ 376 int ret; 377 378 cpoint = CN_INVALID; 379 if (lkdtm.entry != NULL) 380 unregister_jprobe(&lkdtm); 381 382 switch (which) { 383 case CN_DIRECT: 384 lkdtm_do_action(cptype); 385 return 0; 386 case CN_INT_HARDWARE_ENTRY: 387 lkdtm.kp.symbol_name = "do_IRQ"; 388 lkdtm.entry = (kprobe_opcode_t*) jp_do_irq; 389 break; 390 case CN_INT_HW_IRQ_EN: 391 lkdtm.kp.symbol_name = "handle_IRQ_event"; 392 lkdtm.entry = (kprobe_opcode_t*) jp_handle_irq_event; 393 break; 394 case CN_INT_TASKLET_ENTRY: 395 lkdtm.kp.symbol_name = "tasklet_action"; 396 lkdtm.entry = (kprobe_opcode_t*) jp_tasklet_action; 397 break; 398 case CN_FS_DEVRW: 399 lkdtm.kp.symbol_name = "ll_rw_block"; 400 lkdtm.entry = (kprobe_opcode_t*) jp_ll_rw_block; 401 break; 402 case CN_MEM_SWAPOUT: 403 lkdtm.kp.symbol_name = "shrink_inactive_list"; 404 lkdtm.entry = (kprobe_opcode_t*) jp_shrink_inactive_list; 405 break; 406 case CN_TIMERADD: 407 lkdtm.kp.symbol_name = "hrtimer_start"; 408 lkdtm.entry = (kprobe_opcode_t*) jp_hrtimer_start; 409 break; 410 case CN_SCSI_DISPATCH_CMD: 411 lkdtm.kp.symbol_name = "scsi_dispatch_cmd"; 412 lkdtm.entry = (kprobe_opcode_t*) jp_scsi_dispatch_cmd; 413 break; 414 case CN_IDE_CORE_CP: 415#ifdef CONFIG_IDE 416 lkdtm.kp.symbol_name = "generic_ide_ioctl"; 417 lkdtm.entry = (kprobe_opcode_t*) jp_generic_ide_ioctl; 418#else 419 printk(KERN_INFO "lkdtm: Crash point not available\n"); 420 return -EINVAL; 421#endif 422 break; 423 default: 424 printk(KERN_INFO "lkdtm: Invalid Crash Point\n"); 425 return -EINVAL; 426 } 427 428 cpoint = which; 429 if ((ret = register_jprobe(&lkdtm)) < 0) { 430 printk(KERN_INFO "lkdtm: Couldn't register jprobe\n"); 431 cpoint = CN_INVALID; 432 } 433 434 return ret; 435} 436 437static ssize_t do_register_entry(enum cname which, struct file *f, 438 const char __user *user_buf, size_t count, loff_t *off) 439{ 440 char *buf; 441 int err; 442 443 if (count >= PAGE_SIZE) 444 return -EINVAL; 445 446 buf = (char *)__get_free_page(GFP_KERNEL); 447 if (!buf) 448 return -ENOMEM; 449 if (copy_from_user(buf, user_buf, count)) { 450 free_page((unsigned long) buf); 451 return -EFAULT; 452 } 453 /* NULL-terminate and remove enter */ 454 buf[count] = '\0'; 455 strim(buf); 456 457 cptype = parse_cp_type(buf, count); 458 free_page((unsigned long) buf); 459 460 if (cptype == CT_NONE) 461 return -EINVAL; 462 463 err = lkdtm_register_cpoint(which); 464 if (err < 0) 465 return err; 466 467 *off += count; 468 469 return count; 470} 471 472/* Generic read callback that just prints out the available crash types */ 473static ssize_t lkdtm_debugfs_read(struct file *f, char __user *user_buf, 474 size_t count, loff_t *off) 475{ 476 char *buf; 477 int i, n, out; 478 479 buf = (char *)__get_free_page(GFP_KERNEL); 480 if (buf == NULL) 481 return -ENOMEM; 482 483 n = snprintf(buf, PAGE_SIZE, "Available crash types:\n"); 484 for (i = 0; i < ARRAY_SIZE(cp_type); i++) 485 n += snprintf(buf + n, PAGE_SIZE - n, "%s\n", cp_type[i]); 486 buf[n] = '\0'; 487 488 out = simple_read_from_buffer(user_buf, count, off, 489 buf, n); 490 free_page((unsigned long) buf); 491 492 return out; 493} 494 495static int lkdtm_debugfs_open(struct inode *inode, struct file *file) 496{ 497 return 0; 498} 499 500 501static ssize_t int_hardware_entry(struct file *f, const char __user *buf, 502 size_t count, loff_t *off) 503{ 504 return do_register_entry(CN_INT_HARDWARE_ENTRY, f, buf, count, off); 505} 506 507static ssize_t int_hw_irq_en(struct file *f, const char __user *buf, 508 size_t count, loff_t *off) 509{ 510 return do_register_entry(CN_INT_HW_IRQ_EN, f, buf, count, off); 511} 512 513static ssize_t int_tasklet_entry(struct file *f, const char __user *buf, 514 size_t count, loff_t *off) 515{ 516 return do_register_entry(CN_INT_TASKLET_ENTRY, f, buf, count, off); 517} 518 519static ssize_t fs_devrw_entry(struct file *f, const char __user *buf, 520 size_t count, loff_t *off) 521{ 522 return do_register_entry(CN_FS_DEVRW, f, buf, count, off); 523} 524 525static ssize_t mem_swapout_entry(struct file *f, const char __user *buf, 526 size_t count, loff_t *off) 527{ 528 return do_register_entry(CN_MEM_SWAPOUT, f, buf, count, off); 529} 530 531static ssize_t timeradd_entry(struct file *f, const char __user *buf, 532 size_t count, loff_t *off) 533{ 534 return do_register_entry(CN_TIMERADD, f, buf, count, off); 535} 536 537static ssize_t scsi_dispatch_cmd_entry(struct file *f, 538 const char __user *buf, size_t count, loff_t *off) 539{ 540 return do_register_entry(CN_SCSI_DISPATCH_CMD, f, buf, count, off); 541} 542 543static ssize_t ide_core_cp_entry(struct file *f, const char __user *buf, 544 size_t count, loff_t *off) 545{ 546 return do_register_entry(CN_IDE_CORE_CP, f, buf, count, off); 547} 548 549/* Special entry to just crash directly. Available without KPROBEs */ 550static ssize_t direct_entry(struct file *f, const char __user *user_buf, 551 size_t count, loff_t *off) 552{ 553 enum ctype type; 554 char *buf; 555 556 if (count >= PAGE_SIZE) 557 return -EINVAL; 558 if (count < 1) 559 return -EINVAL; 560 561 buf = (char *)__get_free_page(GFP_KERNEL); 562 if (!buf) 563 return -ENOMEM; 564 if (copy_from_user(buf, user_buf, count)) { 565 free_page((unsigned long) buf); 566 return -EFAULT; 567 } 568 /* NULL-terminate and remove enter */ 569 buf[count] = '\0'; 570 strim(buf); 571 572 type = parse_cp_type(buf, count); 573 free_page((unsigned long) buf); 574 if (type == CT_NONE) 575 return -EINVAL; 576 577 printk(KERN_INFO "lkdtm: Performing direct entry %s\n", 578 cp_type_to_str(type)); 579 lkdtm_do_action(type); 580 *off += count; 581 582 return count; 583} 584 585struct crash_entry { 586 const char *name; 587 const struct file_operations fops; 588}; 589 590static const struct crash_entry crash_entries[] = { 591 {"DIRECT", {.read = lkdtm_debugfs_read, 592 .llseek = generic_file_llseek, 593 .open = lkdtm_debugfs_open, 594 .write = direct_entry} }, 595 {"INT_HARDWARE_ENTRY", {.read = lkdtm_debugfs_read, 596 .llseek = generic_file_llseek, 597 .open = lkdtm_debugfs_open, 598 .write = int_hardware_entry} }, 599 {"INT_HW_IRQ_EN", {.read = lkdtm_debugfs_read, 600 .llseek = generic_file_llseek, 601 .open = lkdtm_debugfs_open, 602 .write = int_hw_irq_en} }, 603 {"INT_TASKLET_ENTRY", {.read = lkdtm_debugfs_read, 604 .llseek = generic_file_llseek, 605 .open = lkdtm_debugfs_open, 606 .write = int_tasklet_entry} }, 607 {"FS_DEVRW", {.read = lkdtm_debugfs_read, 608 .llseek = generic_file_llseek, 609 .open = lkdtm_debugfs_open, 610 .write = fs_devrw_entry} }, 611 {"MEM_SWAPOUT", {.read = lkdtm_debugfs_read, 612 .llseek = generic_file_llseek, 613 .open = lkdtm_debugfs_open, 614 .write = mem_swapout_entry} }, 615 {"TIMERADD", {.read = lkdtm_debugfs_read, 616 .llseek = generic_file_llseek, 617 .open = lkdtm_debugfs_open, 618 .write = timeradd_entry} }, 619 {"SCSI_DISPATCH_CMD", {.read = lkdtm_debugfs_read, 620 .llseek = generic_file_llseek, 621 .open = lkdtm_debugfs_open, 622 .write = scsi_dispatch_cmd_entry} }, 623 {"IDE_CORE_CP", {.read = lkdtm_debugfs_read, 624 .llseek = generic_file_llseek, 625 .open = lkdtm_debugfs_open, 626 .write = ide_core_cp_entry} }, 627}; 628 629static struct dentry *lkdtm_debugfs_root; 630 631static int __init lkdtm_module_init(void) 632{ 633 int ret = -EINVAL; 634 int n_debugfs_entries = 1; /* Assume only the direct entry */ 635 int i; 636 637 /* Register debugfs interface */ 638 lkdtm_debugfs_root = debugfs_create_dir("provoke-crash", NULL); 639 if (!lkdtm_debugfs_root) { 640 printk(KERN_ERR "lkdtm: creating root dir failed\n"); 641 return -ENODEV; 642 } 643 644#ifdef CONFIG_KPROBES 645 n_debugfs_entries = ARRAY_SIZE(crash_entries); 646#endif 647 648 for (i = 0; i < n_debugfs_entries; i++) { 649 const struct crash_entry *cur = &crash_entries[i]; 650 struct dentry *de; 651 652 de = debugfs_create_file(cur->name, 0644, lkdtm_debugfs_root, 653 NULL, &cur->fops); 654 if (de == NULL) { 655 printk(KERN_ERR "lkdtm: could not create %s\n", 656 cur->name); 657 goto out_err; 658 } 659 } 660 661 if (lkdtm_parse_commandline() == -EINVAL) { 662 printk(KERN_INFO "lkdtm: Invalid command\n"); 663 goto out_err; 664 } 665 666 if (cpoint != CN_INVALID && cptype != CT_NONE) { 667 ret = lkdtm_register_cpoint(cpoint); 668 if (ret < 0) { 669 printk(KERN_INFO "lkdtm: Invalid crash point %d\n", 670 cpoint); 671 goto out_err; 672 } 673 printk(KERN_INFO "lkdtm: Crash point %s of type %s registered\n", 674 cpoint_name, cpoint_type); 675 } else { 676 printk(KERN_INFO "lkdtm: No crash points registered, enable through debugfs\n"); 677 } 678 679 return 0; 680 681out_err: 682 debugfs_remove_recursive(lkdtm_debugfs_root); 683 return ret; 684} 685 686static void __exit lkdtm_module_exit(void) 687{ 688 debugfs_remove_recursive(lkdtm_debugfs_root); 689 690 unregister_jprobe(&lkdtm); 691 printk(KERN_INFO "lkdtm: Crash point unregistered\n"); 692} 693 694module_init(lkdtm_module_init); 695module_exit(lkdtm_module_exit); 696 697MODULE_LICENSE("GPL");