Chris L Mason fd30a8
From: Chris Mason <mason@suse.com>
Jiri Slaby 57989d
Subject: Crashing and slab testing module
Jiri Slaby 57989d
Patch-mainline: Not yet, probably not applicable
Jiri Slaby 57989d
Jiri Slaby 57989d
js:
Jiri Slaby 57989d
* make it 'depends on m' explicitly instead of help text note
Jiri Slaby 57989d
* trigger the crash from the timer context if requested
Jiri Slaby 57989d
* use prandom_u32* from kernel, no self-designed
Jiri Slaby 57989d
* simplify the code heavily
Jiri Slaby 57989d
* use DECLARE_COMPLETION, init_completion not needed
Jiri Slaby 57989d
* use bitmap to deny compiler optimizations on module_exiting
Jiri Slaby 57989d
* do not use set_current_state, use schedule_timeout_interruptible
Jiri Slaby 57989d
* order includes
Jiri Slaby 57989d
* proper types for parameters
Jiri Slaby 57989d
* use ARRAY_SIZE
Jiri Slaby 57989d
* constify 'sizes' array
Jiri Slaby 57989d
* prepend "crasher: " to prints
Jiri Slaby 57989d
* printk -> proper pr_* level conversion
Jiri Slaby 57989d
* whitespace cleanup
Jiri Slaby 57989d
Jiri Slaby 57989d
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Chris L Mason fd30a8
Olaf Hering 932795
---
Michal Kubecek 4e61ec
 drivers/char/Kconfig   |   6 ++
Michal Kubecek 4e61ec
 drivers/char/Makefile  |   1 +
Michal Kubecek 549a5b
 drivers/char/crasher.c | 235 +++++++++++++++++++++++++++++++++++++++++
Jiri Slaby 57989d
 3 files changed, 242 insertions(+)
Michal Kubecek 4e61ec
 create mode 100644 drivers/char/crasher.c
Olaf Hering 932795
Greg Kroah-Hartman ac6cda
--- a/drivers/char/Kconfig
Greg Kroah-Hartman ac6cda
+++ b/drivers/char/Kconfig
Michal Kubecek 4e61ec
@@ -538,6 +538,12 @@ config DEVPORT
Jeff Mahoney 3f461b
 
Jeff Mahoney 3f461b
 source "drivers/s390/char/Kconfig"
Chris L Mason fd30a8
 
Chris L Mason fd30a8
+config CRASHER
Chris L Mason fd30a8
+	tristate "Crasher Module"
Jiri Slaby 57989d
+	depends on m
Chris L Mason fd30a8
+	help
Jiri Slaby 57989d
+	  Slab cache memory tester and crasher on will.
Chris L Mason fd30a8
+
Michal Kubecek 4e61ec
 source "drivers/char/xillybus/Kconfig"
Michal Kubecek 4e61ec
 
Michal Kubecek 549a5b
 config ADI
Greg Kroah-Hartman ac6cda
--- a/drivers/char/Makefile
Greg Kroah-Hartman ac6cda
+++ b/drivers/char/Makefile
Michal Kubecek 4e61ec
@@ -49,6 +49,7 @@ obj-$(CONFIG_PCMCIA)		+= pcmcia/
Greg Kroah-Hartman a4b1da
 
Greg Kroah-Hartman a4b1da
 obj-$(CONFIG_HANGCHECK_TIMER)	+= hangcheck-timer.o
Greg Kroah-Hartman a4b1da
 obj-$(CONFIG_TCG_TPM)		+= tpm/
Greg Kroah-Hartman a4b1da
+obj-$(CONFIG_CRASHER)		+= crasher.o
Chris L Mason fd30a8
 
Greg Kroah-Hartman 799aa5
 obj-$(CONFIG_PS3_FLASH)		+= ps3flash.o
Jeff Mahoney 3f461b
 
Greg Kroah-Hartman 482cce
--- /dev/null
Greg Kroah-Hartman ac6cda
+++ b/drivers/char/crasher.c
Jiri Slaby 57989d
@@ -0,0 +1,235 @@
Chris L Mason fd30a8
+/*
Chris L Mason fd30a8
+ * crasher.c, it breaks things
Chris L Mason fd30a8
+ */
Chris L Mason fd30a8
+
Olaf Hering c03a4b
+#include <linux/completion.h>
Jiri Slaby 57989d
+#include <linux/init.h>
Olaf Hering c03a4b
+#include <linux/jiffies.h>
Jiri Slaby 57989d
+#include <linux/kernel.h>
Jeff Mahoney b8b35a
+#include <linux/kthread.h>
Jiri Slaby 57989d
+#include <linux/module.h>
Jiri Slaby 57989d
+#include <linux/moduleparam.h>
Jiri Slaby 57989d
+#include <linux/random.h>
Jiri Slaby 57989d
+#include <linux/sched.h>
Jiri Slaby 57989d
+#include <linux/slab.h>
Jiri Slaby 57989d
+#include <linux/timer.h>
Jiri Slaby 57989d
+#include <linux/types.h>
Chris L Mason fd30a8
+
Jiri Slaby 57989d
+static DECLARE_BITMAP(module_exiting, 1);
Jiri Slaby 57989d
+static DECLARE_COMPLETION(startup);
Jiri Slaby 57989d
+static unsigned int threads = 1;
Jiri Slaby 57989d
+static unsigned int timer;
Jan Beulich 67c3c8
+static bool call_panic, call_bug, call_warn;
Jan Beulich 67c3c8
+static bool trap_null, call_null, jump_null;
Jiri Slaby 57989d
+static unsigned long trap_read, trap_write, call_bad, jump_bad;
Chris L Mason fd30a8
+
Jiri Slaby 57989d
+module_param(timer, uint, 0);
Jan Beulich bf3e01
+module_param(call_panic, bool, 0);
Jan Beulich bf3e01
+module_param(call_bug, bool, 0);
Jan Beulich 359dfa
+module_param(call_warn, bool, 0);
Jan Beulich bf3e01
+module_param(trap_null, bool, 0);
Jiri Slaby 57989d
+module_param(trap_read, ulong, 0);
Jiri Slaby 57989d
+module_param(trap_write, ulong, 0);
Jan Beulich bf3e01
+module_param(call_null, bool, 0);
Jiri Slaby 57989d
+module_param(call_bad, ulong, 0);
Jan Beulich bf3e01
+module_param(jump_null, bool, 0);
Jiri Slaby 57989d
+module_param(jump_bad, ulong, 0);
Jiri Slaby 57989d
+module_param(threads, uint, 0);
Jiri Slaby 57989d
+MODULE_PARM_DESC(timer, "perform the selected crash action from the timer context in the specified number of ms");
Olaf Hering 932795
+MODULE_PARM_DESC(call_panic, "test option. call panic() and render the system unusable.");
Olaf Hering 932795
+MODULE_PARM_DESC(call_bug, "test option. call BUG() and render the system unusable.");
Jan Beulich 359dfa
+MODULE_PARM_DESC(call_warn, "test option. call WARN() and leave the system usable.");
Jan Beulich bf3e01
+MODULE_PARM_DESC(trap_null, "test option. dereference a NULL pointer to simulate a crash and render the system unusable.");
Jan Beulich bf3e01
+MODULE_PARM_DESC(trap_read, "test option. read from an invalid address to simulate a crash and render the system unusable.");
Jan Beulich bf3e01
+MODULE_PARM_DESC(trap_write, "test option. write to an invalid address to simulate a crash and render the system unusable.");
Jan Beulich bf3e01
+MODULE_PARM_DESC(call_null, "test option. call a NULL pointer to simulate a crash and render the system unusable.");
Jan Beulich 0c58bf
+MODULE_PARM_DESC(call_bad, "test option. call an invalid address to simulate a crash and render the system unusable.");
Jan Beulich bf3e01
+MODULE_PARM_DESC(jump_null, "test option. jump to a NULL pointer to simulate a crash and render the system unusable.");
Jan Beulich 0c58bf
+MODULE_PARM_DESC(jump_bad, "test option. jump to an invalid address to simulate a crash and render the system unusable.");
Chris L Mason fd30a8
+MODULE_PARM_DESC(threads, "number of threads to run");
Chris L Mason fd30a8
+MODULE_LICENSE("GPL");
Chris L Mason fd30a8
+
Chris L Mason fd30a8
+#define NUM_ALLOC 24
Jiri Slaby 57989d
+static const unsigned int sizes[] = { 32, 64, 128, 192, 256, 1024, 2048, 4096 };
Jiri Slaby 57989d
+#define NUM_SIZES ARRAY_SIZE(sizes)
Chris L Mason fd30a8
+
Chris L Mason fd30a8
+struct mem_buf {
Hannes Reinecke 73f521
+	char *buf;
Jiri Slaby 57989d
+	unsigned int size;
Chris L Mason fd30a8
+};
Chris L Mason fd30a8
+
Jiri Slaby 57989d
+static inline char crasher_hash(unsigned int i)
Chris L Mason fd30a8
+{
Jiri Slaby 57989d
+	return (i % 119) + 8;
Chris L Mason fd30a8
+}
Chris L Mason fd30a8
+
Jiri Slaby 57989d
+static void mem_alloc(struct mem_buf *b)
Chris L Mason fd30a8
+{
Michal Kubecek 769d7a
+	unsigned int i, size = sizes[get_random_u32_below(NUM_SIZES)];
Jiri Slaby 57989d
+
Jiri Slaby 57989d
+	b->buf = kmalloc(size, GFP_KERNEL);
Jiri Slaby 57989d
+	if (!b->buf)
Jiri Slaby 57989d
+		return;
Jiri Slaby 57989d
+
Jiri Slaby 57989d
+	b->size = size;
Chris L Mason fd30a8
+
Chris L Mason fd30a8
+	for (i = 0 ; i < size; i++)
Jiri Slaby 57989d
+		b->buf[i] = crasher_hash(i);
Chris L Mason fd30a8
+}
Chris L Mason fd30a8
+
Jiri Slaby 57989d
+static void mem_check_free(struct mem_buf *b)
Jiri Slaby 57989d
+{
Jiri Slaby 57989d
+	unsigned int i;
Jiri Slaby 57989d
+
Jiri Slaby 57989d
+	for (i = 0 ; i < b->size; i++) {
Jiri Slaby 57989d
+		if (b->buf[i] != crasher_hash(i)) {
Jiri Slaby 57989d
+			pr_crit("crasher: verify error at %p, offset %u, wanted %d, found %d, size %u\n",
Jiri Slaby 57989d
+					&b->buf[i], i, crasher_hash(i),
Jiri Slaby 57989d
+					b->buf[i], b->size);
Chris L Mason fd30a8
+		}
Chris L Mason fd30a8
+	}
Jiri Slaby 57989d
+	kfree(b->buf);
Jiri Slaby 57989d
+	b->buf = NULL;
Jiri Slaby 57989d
+	b->size = 0;
Chris L Mason fd30a8
+}
Chris L Mason fd30a8
+
Jiri Slaby 57989d
+static void mem_verify(void)
Jiri Slaby 57989d
+{
Jiri Slaby 57989d
+	struct mem_buf *b, bufs[NUM_ALLOC] = {};
Jiri Slaby 57989d
+
Jiri Slaby 57989d
+	while (!test_bit(0, module_exiting)) {
Michal Kubecek 769d7a
+		b = &bufs[get_random_u32_below(NUM_ALLOC)];
Jiri Slaby 57989d
+		if (b->size)
Jiri Slaby 57989d
+			mem_check_free(b);
Jiri Slaby 57989d
+		else
Jiri Slaby 57989d
+			mem_alloc(b);
Michal Kubecek 769d7a
+		schedule_timeout_interruptible(get_random_u32_below(HZ / 10));
Chris L Mason fd30a8
+	}
Jiri Slaby 57989d
+
Jiri Slaby 57989d
+	for (b = bufs; b < &bufs[NUM_ALLOC]; b++)
Jiri Slaby 57989d
+		if (b->size)
Jiri Slaby 57989d
+			mem_check_free(b);
Chris L Mason fd30a8
+}
Chris L Mason fd30a8
+
Olaf Hering 932795
+static int crasher_thread(void *unused)
Chris L Mason fd30a8
+{
Chris L Mason fd30a8
+	complete(&startup);
Chris L Mason fd30a8
+	mem_verify();
Chris L Mason fd30a8
+	complete(&startup);
Jiri Slaby 57989d
+
Chris L Mason fd30a8
+	return 0;
Chris L Mason fd30a8
+}
Chris L Mason fd30a8
+
Jiri Slaby 57989d
+static int crash_now(void)
Chris L Mason fd30a8
+{
Olaf Hering 932795
+	if (call_panic) {
Jiri Slaby 57989d
+		panic("test panic from crasher module. Good luck!");
Olaf Hering 932795
+		return -EFAULT;
Olaf Hering 932795
+	}
Olaf Hering 932795
+	if (call_bug) {
Jiri Slaby 57989d
+		pr_crit("crasher: triggering BUG\n");
Jiri Slaby 57989d
+		BUG();
Olaf Hering 932795
+		return -EFAULT;
Olaf Hering 932795
+	}
Jiri Slaby 57989d
+	if (WARN(call_warn, "crasher: triggering WARN\n"))
Jan Beulich 359dfa
+		return -EFAULT;
Jan Beulich bf3e01
+
Jan Beulich bf3e01
+	if (trap_null) {
Jan Beulich bf3e01
+		volatile char *p = NULL;
Jiri Slaby 57989d
+		pr_crit("crasher: dereferencing NULL pointer\n");
Olaf Hering 932795
+		p[0] = '\n';
Olaf Hering 932795
+		return -EFAULT;
Olaf Hering 932795
+	}
Jan Beulich bf3e01
+	if (trap_read) {
Jan Beulich bf3e01
+		const volatile char *p = (char *)trap_read;
Jiri Slaby 57989d
+		pr_crit("crasher: reading from invalid(?) address %p\n", p);
Jan Beulich bf3e01
+		return p[0] ? -EFAULT : -EACCES;
Jan Beulich bf3e01
+	}
Jan Beulich bf3e01
+	if (trap_write) {
Jan Beulich bf3e01
+		volatile char *p = (char *)trap_write;
Jiri Slaby 57989d
+		pr_crit("crasher: writing to invalid(?) address %p\n", p);
Jan Beulich bf3e01
+		p[0] = ' ';
Jan Beulich bf3e01
+		return -EFAULT;
Jan Beulich bf3e01
+	}
Jan Beulich bf3e01
+
Jan Beulich bf3e01
+	if (call_null) {
Jiri Slaby 57989d
+		void (*f)(void) = NULL;
Jiri Slaby 57989d
+		pr_crit("crasher: calling NULL pointer\n");
Jan Beulich bf3e01
+		f();
Jan Beulich bf3e01
+		return -EFAULT;
Jan Beulich bf3e01
+	}
Jan Beulich bf3e01
+	if (call_bad) {
Jiri Slaby 57989d
+		void (*f)(void) = (void(*)(void))call_bad;
Jiri Slaby 57989d
+		pr_crit("crasher: calling invalid(?) address %p\n", f);
Jan Beulich bf3e01
+		f();
Jan Beulich bf3e01
+		return -EFAULT;
Jan Beulich bf3e01
+	}
Jan Beulich bf3e01
+
Jiri Slaby 57989d
+	/* These two depend on the compiler doing tail call optimization */
Jan Beulich bf3e01
+	if (jump_null) {
Jiri Slaby 57989d
+		int (*f)(void) = NULL;
Jiri Slaby 57989d
+		pr_crit("crasher: jumping to NULL\n");
Jan Beulich bf3e01
+		return f();
Jan Beulich bf3e01
+	}
Jan Beulich bf3e01
+	if (jump_bad) {
Jiri Slaby 57989d
+		int (*f)(void) = (int(*)(void))jump_bad;
Jiri Slaby 57989d
+		pr_crit("crasher: jumping to invalid(?) address %p\n", f);
Jan Beulich bf3e01
+		return f();
Jan Beulich bf3e01
+	}
Olaf Hering 932795
+
Jiri Slaby 57989d
+	return 0;
Jiri Slaby 57989d
+}
Jiri Slaby 57989d
+
Jeff Mahoney bc47c4
+static void crash_timer_cb(struct timer_list *unused)
Jiri Slaby 57989d
+{
Jiri Slaby 57989d
+	crash_now();
Jiri Slaby 57989d
+}
Jiri Slaby 57989d
+
Jeff Mahoney bc47c4
+static DEFINE_TIMER(crash_timer, crash_timer_cb);
Jiri Slaby 57989d
+
Jiri Slaby 57989d
+static int __init crasher_init(void)
Jiri Slaby 57989d
+{
Jiri Slaby 57989d
+	int ret, i;
Jiri Slaby 57989d
+
Jiri Slaby 57989d
+	if (timer) {
Jiri Slaby 57989d
+		pr_info("crasher: crashing in %u miliseconds...\n", timer);
Jiri Slaby 57989d
+		mod_timer(&crash_timer, jiffies + msecs_to_jiffies(timer));
Jiri Slaby 57989d
+		return 0;
Jiri Slaby 57989d
+	}
Jiri Slaby 57989d
+
Jiri Slaby 57989d
+	ret = crash_now();
Jiri Slaby 57989d
+	if (ret)
Jiri Slaby 57989d
+		return ret;
Jiri Slaby 57989d
+
Jiri Slaby 57989d
+	pr_info("crasher: running %u threads. Testing sizes: ", threads);
Jiri Slaby 57989d
+	for (i = 0; i < NUM_SIZES; i++)
Jiri Slaby 57989d
+		pr_cont("%u ", sizes[i]);
Jiri Slaby 57989d
+	pr_cont("\n");
Chris L Mason fd30a8
+
Jiri Slaby 57989d
+	for (i = 0; i < threads; i++)
Jiri Slaby 57989d
+		kthread_run(crasher_thread, NULL, "crasher");
Jiri Slaby 57989d
+	for (i = 0; i < threads; i++)
Chris L Mason fd30a8
+		wait_for_completion(&startup);
Jiri Slaby 57989d
+
Chris L Mason fd30a8
+	return 0;
Chris L Mason fd30a8
+}
Chris L Mason fd30a8
+
Chris L Mason fd30a8
+static void __exit crasher_exit(void)
Chris L Mason fd30a8
+{
Jiri Slaby 57989d
+	unsigned int i;
Jiri Slaby 57989d
+
Jiri Slaby 57989d
+	if (timer) {
Jiri Slaby 57989d
+		del_timer_sync(&crash_timer);
Jiri Slaby 57989d
+		return;
Jiri Slaby 57989d
+	}
Jiri Slaby 57989d
+
Jiri Slaby 57989d
+	set_bit(0, module_exiting);
Jiri Slaby 57989d
+
Jiri Slaby 57989d
+	for (i = 0; i < threads; i++)
Chris L Mason fd30a8
+		wait_for_completion(&startup);
Jiri Slaby 57989d
+
Jiri Slaby 57989d
+	pr_info("crasher: all threads done\n");
Chris L Mason fd30a8
+}
Chris L Mason fd30a8
+
Chris L Mason fd30a8
+module_init(crasher_init);
Chris L Mason fd30a8
+module_exit(crasher_exit);