|
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);
|