Blame view

drivers/misc/lkdtm.c 15.5 KB
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
  /*
   * Kprobe module for testing crash dumps
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
   *
   * Copyright (C) IBM Corporation, 2006
   *
   * Author: Ankita Garg <ankita@in.ibm.com>
   *
   * This module induces system failures at predefined crashpoints to
   * evaluate the reliability of crash dumps obtained using different dumping
   * solutions.
   *
   * It is adapted from the Linux Kernel Dump Test Tool by
   * Fernando Luis Vazquez Cao <http://lkdtt.sourceforge.net>
   *
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
29
   * Debugfs support added by Simon Kagstrom <simon.kagstrom@netinsight.net>
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
30
   *
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
31
   * See Documentation/fault-injection/provoke-crashes.txt for instructions
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
32
33
34
   */
  
  #include <linux/kernel.h>
5d861d920   Randy Dunlap   [PATCH] lkdtm: cl...
35
  #include <linux/fs.h>
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
36
  #include <linux/module.h>
5d861d920   Randy Dunlap   [PATCH] lkdtm: cl...
37
  #include <linux/buffer_head.h>
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
38
  #include <linux/kprobes.h>
5d861d920   Randy Dunlap   [PATCH] lkdtm: cl...
39
  #include <linux/list.h>
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
40
  #include <linux/init.h>
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
41
  #include <linux/interrupt.h>
5d861d920   Randy Dunlap   [PATCH] lkdtm: cl...
42
  #include <linux/hrtimer.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
43
  #include <linux/slab.h>
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
44
  #include <scsi/scsi_cmnd.h>
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
45
  #include <linux/debugfs.h>
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
46
47
48
49
  
  #ifdef CONFIG_IDE
  #include <linux/ide.h>
  #endif
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
50
51
52
53
  #define DEFAULT_COUNT 10
  #define REC_NUM_DEFAULT 10
  
  enum cname {
93e2f585c   Namhyung Kim   lkdtm: prefix enu...
54
55
56
57
58
59
60
61
62
63
  	CN_INVALID,
  	CN_INT_HARDWARE_ENTRY,
  	CN_INT_HW_IRQ_EN,
  	CN_INT_TASKLET_ENTRY,
  	CN_FS_DEVRW,
  	CN_MEM_SWAPOUT,
  	CN_TIMERADD,
  	CN_SCSI_DISPATCH_CMD,
  	CN_IDE_CORE_CP,
  	CN_DIRECT,
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
64
65
66
  };
  
  enum ctype {
93e2f585c   Namhyung Kim   lkdtm: prefix enu...
67
68
69
70
71
72
73
74
75
76
77
78
79
  	CT_NONE,
  	CT_PANIC,
  	CT_BUG,
  	CT_EXCEPTION,
  	CT_LOOP,
  	CT_OVERFLOW,
  	CT_CORRUPT_STACK,
  	CT_UNALIGNED_LOAD_STORE_WRITE,
  	CT_OVERWRITE_ALLOCATION,
  	CT_WRITE_AFTER_FREE,
  	CT_SOFTLOCKUP,
  	CT_HARDLOCKUP,
  	CT_HUNG_TASK,
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
80
81
82
83
84
85
86
87
88
89
  };
  
  static char* cp_name[] = {
  	"INT_HARDWARE_ENTRY",
  	"INT_HW_IRQ_EN",
  	"INT_TASKLET_ENTRY",
  	"FS_DEVRW",
  	"MEM_SWAPOUT",
  	"TIMERADD",
  	"SCSI_DISPATCH_CMD",
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
90
91
  	"IDE_CORE_CP",
  	"DIRECT",
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
92
93
94
95
96
97
98
  };
  
  static char* cp_type[] = {
  	"PANIC",
  	"BUG",
  	"EXCEPTION",
  	"LOOP",
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
99
100
101
102
103
  	"OVERFLOW",
  	"CORRUPT_STACK",
  	"UNALIGNED_LOAD_STORE_WRITE",
  	"OVERWRITE_ALLOCATION",
  	"WRITE_AFTER_FREE",
a48223f94   Frederic Weisbecker   lktdm: add suppor...
104
105
106
  	"SOFTLOCKUP",
  	"HARDLOCKUP",
  	"HUNG_TASK",
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
107
108
109
110
111
112
  };
  
  static struct jprobe lkdtm;
  
  static int lkdtm_parse_commandline(void);
  static void lkdtm_handler(void);
ec1c620b1   Al Viro   [PATCH] assigning...
113
114
  static char* cpoint_name;
  static char* cpoint_type;
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
115
116
  static int cpoint_count = DEFAULT_COUNT;
  static int recur_count = REC_NUM_DEFAULT;
93e2f585c   Namhyung Kim   lkdtm: prefix enu...
117
118
  static enum cname cpoint = CN_INVALID;
  static enum ctype cptype = CT_NONE;
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
119
  static int count = DEFAULT_COUNT;
aa2c96d6f   Josh Hunt   drivers/misc/lkdt...
120
  static DEFINE_SPINLOCK(count_lock);
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
121
122
  
  module_param(recur_count, int, 0644);
5d861d920   Randy Dunlap   [PATCH] lkdtm: cl...
123
124
  MODULE_PARM_DESC(recur_count, " Recursion level for the stack overflow test, "\
  				 "default is 10");
dca413063   Rusty Russell   param: remove unn...
125
  module_param(cpoint_name, charp, 0444);
5d861d920   Randy Dunlap   [PATCH] lkdtm: cl...
126
  MODULE_PARM_DESC(cpoint_name, " Crash Point, where kernel is to be crashed");
dca413063   Rusty Russell   param: remove unn...
127
  module_param(cpoint_type, charp, 0444);
5d861d920   Randy Dunlap   [PATCH] lkdtm: cl...
128
129
130
131
132
  MODULE_PARM_DESC(cpoint_type, " Crash Point Type, action to be taken on "\
  				"hitting the crash point");
  module_param(cpoint_count, int, 0644);
  MODULE_PARM_DESC(cpoint_count, " Crash Point Count, number of times the "\
  				"crash point is to be hit to trigger action");
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
133

2118116e5   Adrian Bunk   drivers/misc/lkdt...
134
  static unsigned int jp_do_irq(unsigned int irq)
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
135
136
137
138
139
  {
  	lkdtm_handler();
  	jprobe_return();
  	return 0;
  }
2118116e5   Adrian Bunk   drivers/misc/lkdt...
140
141
  static irqreturn_t jp_handle_irq_event(unsigned int irq,
  				       struct irqaction *action)
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
142
143
144
145
146
  {
  	lkdtm_handler();
  	jprobe_return();
  	return 0;
  }
2118116e5   Adrian Bunk   drivers/misc/lkdt...
147
  static void jp_tasklet_action(struct softirq_action *a)
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
148
149
150
151
  {
  	lkdtm_handler();
  	jprobe_return();
  }
2118116e5   Adrian Bunk   drivers/misc/lkdt...
152
  static void jp_ll_rw_block(int rw, int nr, struct buffer_head *bhs[])
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
153
154
155
156
157
158
  {
  	lkdtm_handler();
  	jprobe_return();
  }
  
  struct scan_control;
2118116e5   Adrian Bunk   drivers/misc/lkdt...
159
160
161
  static unsigned long jp_shrink_inactive_list(unsigned long max_scan,
  					     struct zone *zone,
  					     struct scan_control *sc)
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
162
163
164
165
166
  {
  	lkdtm_handler();
  	jprobe_return();
  	return 0;
  }
2118116e5   Adrian Bunk   drivers/misc/lkdt...
167
168
  static int jp_hrtimer_start(struct hrtimer *timer, ktime_t tim,
  			    const enum hrtimer_mode mode)
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
169
170
171
172
173
  {
  	lkdtm_handler();
  	jprobe_return();
  	return 0;
  }
2118116e5   Adrian Bunk   drivers/misc/lkdt...
174
  static int jp_scsi_dispatch_cmd(struct scsi_cmnd *cmd)
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
  {
  	lkdtm_handler();
  	jprobe_return();
  	return 0;
  }
  
  #ifdef CONFIG_IDE
  int jp_generic_ide_ioctl(ide_drive_t *drive, struct file *file,
  			struct block_device *bdev, unsigned int cmd,
  			unsigned long arg)
  {
  	lkdtm_handler();
  	jprobe_return();
  	return 0;
  }
  #endif
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
191
192
193
194
195
196
197
198
199
  /* Return the crashpoint number or NONE if the name is invalid */
  static enum ctype parse_cp_type(const char *what, size_t count)
  {
  	int i;
  
  	for (i = 0; i < ARRAY_SIZE(cp_type); i++) {
  		if (!strcmp(what, cp_type[i]))
  			return i + 1;
  	}
93e2f585c   Namhyung Kim   lkdtm: prefix enu...
200
  	return CT_NONE;
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
201
202
203
204
  }
  
  static const char *cp_type_to_str(enum ctype type)
  {
93e2f585c   Namhyung Kim   lkdtm: prefix enu...
205
  	if (type == CT_NONE || type < 0 || type > ARRAY_SIZE(cp_type))
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
206
207
208
209
210
211
212
  		return "None";
  
  	return cp_type[type - 1];
  }
  
  static const char *cp_name_to_str(enum cname name)
  {
93e2f585c   Namhyung Kim   lkdtm: prefix enu...
213
  	if (name == CN_INVALID || name < 0 || name > ARRAY_SIZE(cp_name))
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
214
215
216
217
  		return "INVALID";
  
  	return cp_name[name - 1];
  }
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
218
219
220
  static int lkdtm_parse_commandline(void)
  {
  	int i;
aa2c96d6f   Josh Hunt   drivers/misc/lkdt...
221
  	unsigned long flags;
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
222

0347af4ee   Simon Kagstrom   lkdtm: add debugf...
223
  	if (cpoint_count < 1 || recur_count < 1)
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
224
  		return -EINVAL;
aa2c96d6f   Josh Hunt   drivers/misc/lkdt...
225
  	spin_lock_irqsave(&count_lock, flags);
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
226
  	count = cpoint_count;
aa2c96d6f   Josh Hunt   drivers/misc/lkdt...
227
  	spin_unlock_irqrestore(&count_lock, flags);
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
228
229
230
231
232
233
234
235
236
237
  
  	/* No special parameters */
  	if (!cpoint_type && !cpoint_name)
  		return 0;
  
  	/* Neither or both of these need to be set */
  	if (!cpoint_type || !cpoint_name)
  		return -EINVAL;
  
  	cptype = parse_cp_type(cpoint_type, strlen(cpoint_type));
93e2f585c   Namhyung Kim   lkdtm: prefix enu...
238
  	if (cptype == CT_NONE)
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
239
240
241
  		return -EINVAL;
  
  	for (i = 0; i < ARRAY_SIZE(cp_name); i++) {
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
242
243
  		if (!strcmp(cpoint_name, cp_name[i])) {
  			cpoint = i + 1;
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
244
  			return 0;
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
245
246
  		}
  	}
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
247
248
  	/* Could not find a valid crash point */
  	return -EINVAL;
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
249
250
251
252
253
254
255
256
257
258
259
260
261
  }
  
  static int recursive_loop(int a)
  {
  	char buf[1024];
  
  	memset(buf,0xFF,1024);
  	recur_count--;
  	if (!recur_count)
  		return 0;
  	else
          	return recursive_loop(a);
  }
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
262
  static void lkdtm_do_action(enum ctype which)
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
263
  {
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
264
  	switch (which) {
93e2f585c   Namhyung Kim   lkdtm: prefix enu...
265
  	case CT_PANIC:
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
266
267
  		panic("dumptest");
  		break;
93e2f585c   Namhyung Kim   lkdtm: prefix enu...
268
  	case CT_BUG:
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
269
270
  		BUG();
  		break;
93e2f585c   Namhyung Kim   lkdtm: prefix enu...
271
  	case CT_EXCEPTION:
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
272
273
  		*((int *) 0) = 0;
  		break;
93e2f585c   Namhyung Kim   lkdtm: prefix enu...
274
  	case CT_LOOP:
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
275
276
277
  		for (;;)
  			;
  		break;
93e2f585c   Namhyung Kim   lkdtm: prefix enu...
278
  	case CT_OVERFLOW:
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
279
280
  		(void) recursive_loop(0);
  		break;
93e2f585c   Namhyung Kim   lkdtm: prefix enu...
281
  	case CT_CORRUPT_STACK: {
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
282
283
284
285
286
287
  		volatile u32 data[8];
  		volatile u32 *p = data;
  
  		p[12] = 0x12345678;
  		break;
  	}
93e2f585c   Namhyung Kim   lkdtm: prefix enu...
288
  	case CT_UNALIGNED_LOAD_STORE_WRITE: {
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
289
290
291
292
293
294
295
296
297
298
299
  		static u8 data[5] __attribute__((aligned(4))) = {1, 2,
  				3, 4, 5};
  		u32 *p;
  		u32 val = 0x12345678;
  
  		p = (u32 *)(data + 1);
  		if (*p == 0)
  			val = 0x87654321;
  		*p = val;
  		 break;
  	}
93e2f585c   Namhyung Kim   lkdtm: prefix enu...
300
  	case CT_OVERWRITE_ALLOCATION: {
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
301
302
303
304
305
306
307
  		size_t len = 1020;
  		u32 *data = kmalloc(len, GFP_KERNEL);
  
  		data[1024 / sizeof(u32)] = 0x12345678;
  		kfree(data);
  		break;
  	}
93e2f585c   Namhyung Kim   lkdtm: prefix enu...
308
  	case CT_WRITE_AFTER_FREE: {
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
309
310
311
312
313
314
315
316
  		size_t len = 1024;
  		u32 *data = kmalloc(len, GFP_KERNEL);
  
  		kfree(data);
  		schedule();
  		memset(data, 0x78, len);
  		break;
  	}
93e2f585c   Namhyung Kim   lkdtm: prefix enu...
317
  	case CT_SOFTLOCKUP:
a48223f94   Frederic Weisbecker   lktdm: add suppor...
318
319
320
321
  		preempt_disable();
  		for (;;)
  			cpu_relax();
  		break;
93e2f585c   Namhyung Kim   lkdtm: prefix enu...
322
  	case CT_HARDLOCKUP:
a48223f94   Frederic Weisbecker   lktdm: add suppor...
323
324
325
326
  		local_irq_disable();
  		for (;;)
  			cpu_relax();
  		break;
93e2f585c   Namhyung Kim   lkdtm: prefix enu...
327
  	case CT_HUNG_TASK:
a48223f94   Frederic Weisbecker   lktdm: add suppor...
328
329
330
  		set_current_state(TASK_UNINTERRUPTIBLE);
  		schedule();
  		break;
93e2f585c   Namhyung Kim   lkdtm: prefix enu...
331
  	case CT_NONE:
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
332
333
334
335
336
337
338
339
  	default:
  		break;
  	}
  
  }
  
  static void lkdtm_handler(void)
  {
aa2c96d6f   Josh Hunt   drivers/misc/lkdt...
340
341
342
  	unsigned long flags;
  
  	spin_lock_irqsave(&count_lock, flags);
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
343
344
345
346
  	count--;
  	printk(KERN_INFO "lkdtm: Crash point %s of type %s hit, trigger in %d rounds
  ",
  			cp_name_to_str(cpoint), cp_type_to_str(cptype), count);
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
347
348
  
  	if (count == 0) {
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
349
  		lkdtm_do_action(cptype);
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
350
351
  		count = cpoint_count;
  	}
aa2c96d6f   Josh Hunt   drivers/misc/lkdt...
352
  	spin_unlock_irqrestore(&count_lock, flags);
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
353
  }
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
354
  static int lkdtm_register_cpoint(enum cname which)
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
355
356
  {
  	int ret;
93e2f585c   Namhyung Kim   lkdtm: prefix enu...
357
  	cpoint = CN_INVALID;
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
358
359
  	if (lkdtm.entry != NULL)
  		unregister_jprobe(&lkdtm);
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
360

0347af4ee   Simon Kagstrom   lkdtm: add debugf...
361
  	switch (which) {
93e2f585c   Namhyung Kim   lkdtm: prefix enu...
362
  	case CN_DIRECT:
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
363
364
  		lkdtm_do_action(cptype);
  		return 0;
93e2f585c   Namhyung Kim   lkdtm: prefix enu...
365
  	case CN_INT_HARDWARE_ENTRY:
f58f2fa92   M. Mohan Kumar   kprobes: use do_I...
366
  		lkdtm.kp.symbol_name = "do_IRQ";
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
367
368
  		lkdtm.entry = (kprobe_opcode_t*) jp_do_irq;
  		break;
93e2f585c   Namhyung Kim   lkdtm: prefix enu...
369
  	case CN_INT_HW_IRQ_EN:
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
370
371
372
  		lkdtm.kp.symbol_name = "handle_IRQ_event";
  		lkdtm.entry = (kprobe_opcode_t*) jp_handle_irq_event;
  		break;
93e2f585c   Namhyung Kim   lkdtm: prefix enu...
373
  	case CN_INT_TASKLET_ENTRY:
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
374
375
376
  		lkdtm.kp.symbol_name = "tasklet_action";
  		lkdtm.entry = (kprobe_opcode_t*) jp_tasklet_action;
  		break;
93e2f585c   Namhyung Kim   lkdtm: prefix enu...
377
  	case CN_FS_DEVRW:
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
378
379
380
  		lkdtm.kp.symbol_name = "ll_rw_block";
  		lkdtm.entry = (kprobe_opcode_t*) jp_ll_rw_block;
  		break;
93e2f585c   Namhyung Kim   lkdtm: prefix enu...
381
  	case CN_MEM_SWAPOUT:
18a61e4ad   Ankita Garg   [PATCH] Fix for L...
382
383
  		lkdtm.kp.symbol_name = "shrink_inactive_list";
  		lkdtm.entry = (kprobe_opcode_t*) jp_shrink_inactive_list;
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
384
  		break;
93e2f585c   Namhyung Kim   lkdtm: prefix enu...
385
  	case CN_TIMERADD:
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
386
387
388
  		lkdtm.kp.symbol_name = "hrtimer_start";
  		lkdtm.entry = (kprobe_opcode_t*) jp_hrtimer_start;
  		break;
93e2f585c   Namhyung Kim   lkdtm: prefix enu...
389
  	case CN_SCSI_DISPATCH_CMD:
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
390
391
392
  		lkdtm.kp.symbol_name = "scsi_dispatch_cmd";
  		lkdtm.entry = (kprobe_opcode_t*) jp_scsi_dispatch_cmd;
  		break;
93e2f585c   Namhyung Kim   lkdtm: prefix enu...
393
  	case CN_IDE_CORE_CP:
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
394
395
396
397
  #ifdef CONFIG_IDE
  		lkdtm.kp.symbol_name = "generic_ide_ioctl";
  		lkdtm.entry = (kprobe_opcode_t*) jp_generic_ide_ioctl;
  #else
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
398
399
400
  		printk(KERN_INFO "lkdtm: Crash point not available
  ");
  		return -EINVAL;
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
401
402
403
  #endif
  		break;
  	default:
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
404
405
406
  		printk(KERN_INFO "lkdtm: Invalid Crash Point
  ");
  		return -EINVAL;
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
407
  	}
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
408
  	cpoint = which;
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
409
  	if ((ret = register_jprobe(&lkdtm)) < 0) {
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
410
411
  		printk(KERN_INFO "lkdtm: Couldn't register jprobe
  ");
93e2f585c   Namhyung Kim   lkdtm: prefix enu...
412
  		cpoint = CN_INVALID;
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
  	}
  
  	return ret;
  }
  
  static ssize_t do_register_entry(enum cname which, struct file *f,
  		const char __user *user_buf, size_t count, loff_t *off)
  {
  	char *buf;
  	int err;
  
  	if (count >= PAGE_SIZE)
  		return -EINVAL;
  
  	buf = (char *)__get_free_page(GFP_KERNEL);
  	if (!buf)
  		return -ENOMEM;
  	if (copy_from_user(buf, user_buf, count)) {
  		free_page((unsigned long) buf);
  		return -EFAULT;
  	}
  	/* NULL-terminate and remove enter */
  	buf[count] = '\0';
  	strim(buf);
  
  	cptype = parse_cp_type(buf, count);
  	free_page((unsigned long) buf);
93e2f585c   Namhyung Kim   lkdtm: prefix enu...
440
  	if (cptype == CT_NONE)
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
  		return -EINVAL;
  
  	err = lkdtm_register_cpoint(which);
  	if (err < 0)
  		return err;
  
  	*off += count;
  
  	return count;
  }
  
  /* Generic read callback that just prints out the available crash types */
  static ssize_t lkdtm_debugfs_read(struct file *f, char __user *user_buf,
  		size_t count, loff_t *off)
  {
  	char *buf;
  	int i, n, out;
  
  	buf = (char *)__get_free_page(GFP_KERNEL);
  
  	n = snprintf(buf, PAGE_SIZE, "Available crash types:
  ");
  	for (i = 0; i < ARRAY_SIZE(cp_type); i++)
  		n += snprintf(buf + n, PAGE_SIZE - n, "%s
  ", cp_type[i]);
  	buf[n] = '\0';
  
  	out = simple_read_from_buffer(user_buf, count, off,
  				      buf, n);
  	free_page((unsigned long) buf);
  
  	return out;
  }
  
  static int lkdtm_debugfs_open(struct inode *inode, struct file *file)
  {
  	return 0;
  }
  
  
  static ssize_t int_hardware_entry(struct file *f, const char __user *buf,
  		size_t count, loff_t *off)
  {
93e2f585c   Namhyung Kim   lkdtm: prefix enu...
484
  	return do_register_entry(CN_INT_HARDWARE_ENTRY, f, buf, count, off);
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
485
486
487
488
489
  }
  
  static ssize_t int_hw_irq_en(struct file *f, const char __user *buf,
  		size_t count, loff_t *off)
  {
93e2f585c   Namhyung Kim   lkdtm: prefix enu...
490
  	return do_register_entry(CN_INT_HW_IRQ_EN, f, buf, count, off);
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
491
492
493
494
495
  }
  
  static ssize_t int_tasklet_entry(struct file *f, const char __user *buf,
  		size_t count, loff_t *off)
  {
93e2f585c   Namhyung Kim   lkdtm: prefix enu...
496
  	return do_register_entry(CN_INT_TASKLET_ENTRY, f, buf, count, off);
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
497
498
499
500
501
  }
  
  static ssize_t fs_devrw_entry(struct file *f, const char __user *buf,
  		size_t count, loff_t *off)
  {
93e2f585c   Namhyung Kim   lkdtm: prefix enu...
502
  	return do_register_entry(CN_FS_DEVRW, f, buf, count, off);
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
503
504
505
506
507
  }
  
  static ssize_t mem_swapout_entry(struct file *f, const char __user *buf,
  		size_t count, loff_t *off)
  {
93e2f585c   Namhyung Kim   lkdtm: prefix enu...
508
  	return do_register_entry(CN_MEM_SWAPOUT, f, buf, count, off);
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
509
510
511
512
513
  }
  
  static ssize_t timeradd_entry(struct file *f, const char __user *buf,
  		size_t count, loff_t *off)
  {
93e2f585c   Namhyung Kim   lkdtm: prefix enu...
514
  	return do_register_entry(CN_TIMERADD, f, buf, count, off);
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
515
516
517
518
519
  }
  
  static ssize_t scsi_dispatch_cmd_entry(struct file *f,
  		const char __user *buf, size_t count, loff_t *off)
  {
93e2f585c   Namhyung Kim   lkdtm: prefix enu...
520
  	return do_register_entry(CN_SCSI_DISPATCH_CMD, f, buf, count, off);
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
521
522
523
524
525
  }
  
  static ssize_t ide_core_cp_entry(struct file *f, const char __user *buf,
  		size_t count, loff_t *off)
  {
93e2f585c   Namhyung Kim   lkdtm: prefix enu...
526
  	return do_register_entry(CN_IDE_CORE_CP, f, buf, count, off);
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
  }
  
  /* Special entry to just crash directly. Available without KPROBEs */
  static ssize_t direct_entry(struct file *f, const char __user *user_buf,
  		size_t count, loff_t *off)
  {
  	enum ctype type;
  	char *buf;
  
  	if (count >= PAGE_SIZE)
  		return -EINVAL;
  	if (count < 1)
  		return -EINVAL;
  
  	buf = (char *)__get_free_page(GFP_KERNEL);
  	if (!buf)
  		return -ENOMEM;
  	if (copy_from_user(buf, user_buf, count)) {
  		free_page((unsigned long) buf);
  		return -EFAULT;
  	}
  	/* NULL-terminate and remove enter */
  	buf[count] = '\0';
  	strim(buf);
  
  	type = parse_cp_type(buf, count);
  	free_page((unsigned long) buf);
93e2f585c   Namhyung Kim   lkdtm: prefix enu...
554
  	if (type == CT_NONE)
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
  		return -EINVAL;
  
  	printk(KERN_INFO "lkdtm: Performing direct entry %s
  ",
  			cp_type_to_str(type));
  	lkdtm_do_action(type);
  	*off += count;
  
  	return count;
  }
  
  struct crash_entry {
  	const char *name;
  	const struct file_operations fops;
  };
  
  static const struct crash_entry crash_entries[] = {
  	{"DIRECT", {.read = lkdtm_debugfs_read,
05271ec42   Arnd Bergmann   lkdtm: use generi...
573
  			.llseek = generic_file_llseek,
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
574
575
576
  			.open = lkdtm_debugfs_open,
  			.write = direct_entry} },
  	{"INT_HARDWARE_ENTRY", {.read = lkdtm_debugfs_read,
05271ec42   Arnd Bergmann   lkdtm: use generi...
577
  			.llseek = generic_file_llseek,
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
578
579
580
  			.open = lkdtm_debugfs_open,
  			.write = int_hardware_entry} },
  	{"INT_HW_IRQ_EN", {.read = lkdtm_debugfs_read,
05271ec42   Arnd Bergmann   lkdtm: use generi...
581
  			.llseek = generic_file_llseek,
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
582
583
584
  			.open = lkdtm_debugfs_open,
  			.write = int_hw_irq_en} },
  	{"INT_TASKLET_ENTRY", {.read = lkdtm_debugfs_read,
05271ec42   Arnd Bergmann   lkdtm: use generi...
585
  			.llseek = generic_file_llseek,
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
586
587
588
  			.open = lkdtm_debugfs_open,
  			.write = int_tasklet_entry} },
  	{"FS_DEVRW", {.read = lkdtm_debugfs_read,
05271ec42   Arnd Bergmann   lkdtm: use generi...
589
  			.llseek = generic_file_llseek,
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
590
591
592
  			.open = lkdtm_debugfs_open,
  			.write = fs_devrw_entry} },
  	{"MEM_SWAPOUT", {.read = lkdtm_debugfs_read,
05271ec42   Arnd Bergmann   lkdtm: use generi...
593
  			.llseek = generic_file_llseek,
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
594
595
596
  			.open = lkdtm_debugfs_open,
  			.write = mem_swapout_entry} },
  	{"TIMERADD", {.read = lkdtm_debugfs_read,
05271ec42   Arnd Bergmann   lkdtm: use generi...
597
  			.llseek = generic_file_llseek,
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
598
599
600
  			.open = lkdtm_debugfs_open,
  			.write = timeradd_entry} },
  	{"SCSI_DISPATCH_CMD", {.read = lkdtm_debugfs_read,
05271ec42   Arnd Bergmann   lkdtm: use generi...
601
  			.llseek = generic_file_llseek,
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
602
603
604
  			.open = lkdtm_debugfs_open,
  			.write = scsi_dispatch_cmd_entry} },
  	{"IDE_CORE_CP",	{.read = lkdtm_debugfs_read,
05271ec42   Arnd Bergmann   lkdtm: use generi...
605
  			.llseek = generic_file_llseek,
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
  			.open = lkdtm_debugfs_open,
  			.write = ide_core_cp_entry} },
  };
  
  static struct dentry *lkdtm_debugfs_root;
  
  static int __init lkdtm_module_init(void)
  {
  	int ret = -EINVAL;
  	int n_debugfs_entries = 1; /* Assume only the direct entry */
  	int i;
  
  	/* Register debugfs interface */
  	lkdtm_debugfs_root = debugfs_create_dir("provoke-crash", NULL);
  	if (!lkdtm_debugfs_root) {
  		printk(KERN_ERR "lkdtm: creating root dir failed
  ");
  		return -ENODEV;
  	}
  
  #ifdef CONFIG_KPROBES
  	n_debugfs_entries = ARRAY_SIZE(crash_entries);
  #endif
  
  	for (i = 0; i < n_debugfs_entries; i++) {
  		const struct crash_entry *cur = &crash_entries[i];
  		struct dentry *de;
  
  		de = debugfs_create_file(cur->name, 0644, lkdtm_debugfs_root,
  				NULL, &cur->fops);
  		if (de == NULL) {
  			printk(KERN_ERR "lkdtm: could not create %s
  ",
  					cur->name);
  			goto out_err;
  		}
  	}
  
  	if (lkdtm_parse_commandline() == -EINVAL) {
  		printk(KERN_INFO "lkdtm: Invalid command
  ");
  		goto out_err;
  	}
93e2f585c   Namhyung Kim   lkdtm: prefix enu...
649
  	if (cpoint != CN_INVALID && cptype != CT_NONE) {
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
650
651
652
653
654
655
656
657
658
659
660
661
662
  		ret = lkdtm_register_cpoint(cpoint);
  		if (ret < 0) {
  			printk(KERN_INFO "lkdtm: Invalid crash point %d
  ",
  					cpoint);
  			goto out_err;
  		}
  		printk(KERN_INFO "lkdtm: Crash point %s of type %s registered
  ",
  				cpoint_name, cpoint_type);
  	} else {
  		printk(KERN_INFO "lkdtm: No crash points registered, enable through debugfs
  ");
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
663
  	}
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
664
  	return 0;
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
665
666
667
668
  
  out_err:
  	debugfs_remove_recursive(lkdtm_debugfs_root);
  	return ret;
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
669
  }
2118116e5   Adrian Bunk   drivers/misc/lkdt...
670
  static void __exit lkdtm_module_exit(void)
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
671
  {
0347af4ee   Simon Kagstrom   lkdtm: add debugf...
672
673
674
675
676
  	debugfs_remove_recursive(lkdtm_debugfs_root);
  
  	unregister_jprobe(&lkdtm);
  	printk(KERN_INFO "lkdtm: Crash point unregistered
  ");
8bb31b9d5   Ankita Garg   [PATCH] Linux Ker...
677
678
679
680
681
682
  }
  
  module_init(lkdtm_module_init);
  module_exit(lkdtm_module_exit);
  
  MODULE_LICENSE("GPL");