lkdtm.c 16 KB

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