• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
70 enum 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 
82 enum ctype {
83 	NONE,
84 	PANIC,
85 	BUG,
86 	EXCEPTION,
87 	LOOP,
88 	OVERFLOW
89 };
90 
91 static 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 
102 static char *cp_type[] = {
103 	"PANIC",
104 	"BUG",
105 	"EXCEPTION",
106 	"LOOP",
107 	"OVERFLOW"
108 };
109 
110 static struct jprobe lkdtm;
111 
112 static int lkdtm_parse_commandline(void);
113 static void lkdtm_handler(void);
114 
115 static char *cpoint_name = INVALID;
116 static char *cpoint_type = NONE;
117 static int cpoint_count = DEFAULT_COUNT;
118 static int recur_count = REC_NUM_DEFAULT;
119 
120 static enum cname cpoint = INVALID;
121 static enum ctype cptype = NONE;
122 static int count = DEFAULT_COUNT;
123 
124 module_param(recur_count, int, 0644);
125 MODULE_PARM_DESC(recur_count, " Recursion level for the stack overflow test, "
126 		 "default is 10");
127 module_param(cpoint_name, charp, 0644);
128 MODULE_PARM_DESC(cpoint_name, " Crash Point, where kernel is to be crashed");
129 module_param(cpoint_type, charp, 0644);
130 MODULE_PARM_DESC(cpoint_type, " Crash Point Type, action to be taken on "
131 		 "hitting the crash point");
132 module_param(cpoint_count, int, 0644);
133 MODULE_PARM_DESC(cpoint_count, " Crash Point Count, number of times the "
134 		 "crash point is to be hit to trigger action");
135 
jp_do_irq(unsigned int irq)136 unsigned int jp_do_irq(unsigned int irq)
137 {
138 	lkdtm_handler();
139 	jprobe_return();
140 	return 0;
141 }
142 
jp_handle_irq_event(unsigned int irq,struct irqaction * action)143 irqreturn_t jp_handle_irq_event(unsigned int irq, struct irqaction * action)
144 {
145 	lkdtm_handler();
146 	jprobe_return();
147 	return 0;
148 }
149 
jp_tasklet_action(struct softirq_action * a)150 void jp_tasklet_action(struct softirq_action *a)
151 {
152 	lkdtm_handler();
153 	jprobe_return();
154 }
155 
jp_ll_rw_block(int rw,int nr,struct buffer_head * bhs[])156 void jp_ll_rw_block(int rw, int nr, struct buffer_head *bhs[])
157 {
158 	lkdtm_handler();
159 	jprobe_return();
160 }
161 
162 struct scan_control;
163 
jp_shrink_page_list(struct list_head * page_list,struct scan_control * sc)164 unsigned 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 
jp_hrtimer_start(struct hrtimer * timer,ktime_t tim,const enum hrtimer_mode mode)172 int 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 
jp_scsi_dispatch_cmd(struct scsi_cmnd * cmd)180 int jp_scsi_dispatch_cmd(struct scsi_cmnd *cmd)
181 {
182 	lkdtm_handler();
183 	jprobe_return();
184 	return 0;
185 }
186 
187 #ifdef CONFIG_IDE
jp_generic_ide_ioctl(ide_drive_t * drive,struct file * file,struct block_device * bdev,unsigned int cmd,unsigned long arg)188 int 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 
lkdtm_parse_commandline(void)198 static 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 
recursive_loop(int a)228 static 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 
lkdtm_handler(void)240 void 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
lkdtm_symbol_name(char * name,void (* entry)(void))282 void 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
lkdtm_lookup_name(char * name,void (* entry)(void))289 void 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 
lkdtm_module_init(void)302 int 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 
lkdtm_module_exit(void)478 void lkdtm_module_exit(void)
479 {
480 	unregister_jprobe(&lkdtm);
481 	printk(KERN_INFO "lkdtm : Crash point unregistered\n");
482 }
483 
484 module_init(lkdtm_module_init);
485 module_exit(lkdtm_module_exit);
486 
487 MODULE_LICENSE("GPL");
488