misc: nct1008: Refactor power rail control
[linux-2.6.git] / drivers / misc / lkdtm.c
index ef34de7..28adefe 100644 (file)
 #define REC_NUM_DEFAULT 10
 
 enum cname {
-       INVALID,
-       INT_HARDWARE_ENTRY,
-       INT_HW_IRQ_EN,
-       INT_TASKLET_ENTRY,
-       FS_DEVRW,
-       MEM_SWAPOUT,
-       TIMERADD,
-       SCSI_DISPATCH_CMD,
-       IDE_CORE_CP,
-       DIRECT,
+       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,
 };
 
 enum ctype {
-       NONE,
-       PANIC,
-       BUG,
-       EXCEPTION,
-       LOOP,
-       OVERFLOW,
-       CORRUPT_STACK,
-       UNALIGNED_LOAD_STORE_WRITE,
-       OVERWRITE_ALLOCATION,
-       WRITE_AFTER_FREE,
-       SOFTLOCKUP,
-       HARDLOCKUP,
-       HUNG_TASK,
+       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,
 };
 
 static char* cp_name[] = {
@@ -117,9 +117,10 @@ static char* cpoint_type;
 static int cpoint_count = DEFAULT_COUNT;
 static int recur_count = REC_NUM_DEFAULT;
 
-static enum cname cpoint = INVALID;
-static enum ctype cptype = NONE;
+static enum cname cpoint = CN_INVALID;
+static enum ctype cptype = CT_NONE;
 static int count = DEFAULT_COUNT;
+static DEFINE_SPINLOCK(count_lock);
 
 module_param(recur_count, int, 0644);
 MODULE_PARM_DESC(recur_count, " Recursion level for the stack overflow test, "\
@@ -207,12 +208,12 @@ static enum ctype parse_cp_type(const char *what, size_t count)
                        return i + 1;
        }
 
-       return NONE;
+       return CT_NONE;
 }
 
 static const char *cp_type_to_str(enum ctype type)
 {
-       if (type == NONE || type < 0 || type > ARRAY_SIZE(cp_type))
+       if (type == CT_NONE || type < 0 || type > ARRAY_SIZE(cp_type))
                return "None";
 
        return cp_type[type - 1];
@@ -220,7 +221,7 @@ static const char *cp_type_to_str(enum ctype type)
 
 static const char *cp_name_to_str(enum cname name)
 {
-       if (name == INVALID || name < 0 || name > ARRAY_SIZE(cp_name))
+       if (name == CN_INVALID || name < 0 || name > ARRAY_SIZE(cp_name))
                return "INVALID";
 
        return cp_name[name - 1];
@@ -230,11 +231,14 @@ static const char *cp_name_to_str(enum cname name)
 static int lkdtm_parse_commandline(void)
 {
        int i;
+       unsigned long flags;
 
        if (cpoint_count < 1 || recur_count < 1)
                return -EINVAL;
 
+       spin_lock_irqsave(&count_lock, flags);
        count = cpoint_count;
+       spin_unlock_irqrestore(&count_lock, flags);
 
        /* No special parameters */
        if (!cpoint_type && !cpoint_name)
@@ -245,7 +249,7 @@ static int lkdtm_parse_commandline(void)
                return -EINVAL;
 
        cptype = parse_cp_type(cpoint_type, strlen(cpoint_type));
-       if (cptype == NONE)
+       if (cptype == CT_NONE)
                return -EINVAL;
 
        for (i = 0; i < ARRAY_SIZE(cp_name); i++) {
@@ -274,30 +278,30 @@ static int recursive_loop(int a)
 static void lkdtm_do_action(enum ctype which)
 {
        switch (which) {
-       case PANIC:
+       case CT_PANIC:
                panic("dumptest");
                break;
-       case BUG:
+       case CT_BUG:
                BUG();
                break;
-       case EXCEPTION:
+       case CT_EXCEPTION:
                *((int *) 0) = 0;
                break;
-       case LOOP:
+       case CT_LOOP:
                for (;;)
                        ;
                break;
-       case OVERFLOW:
+       case CT_OVERFLOW:
                (void) recursive_loop(0);
                break;
-       case CORRUPT_STACK: {
+       case CT_CORRUPT_STACK: {
                volatile u32 data[8];
                volatile u32 *p = data;
 
                p[12] = 0x12345678;
                break;
        }
-       case UNALIGNED_LOAD_STORE_WRITE: {
+       case CT_UNALIGNED_LOAD_STORE_WRITE: {
                static u8 data[5] __attribute__((aligned(4))) = {1, 2,
                                3, 4, 5};
                u32 *p;
@@ -309,7 +313,7 @@ static void lkdtm_do_action(enum ctype which)
                *p = val;
                 break;
        }
-       case OVERWRITE_ALLOCATION: {
+       case CT_OVERWRITE_ALLOCATION: {
                size_t len = 1020;
                u32 *data = kmalloc(len, GFP_KERNEL);
 
@@ -317,7 +321,7 @@ static void lkdtm_do_action(enum ctype which)
                kfree(data);
                break;
        }
-       case WRITE_AFTER_FREE: {
+       case CT_WRITE_AFTER_FREE: {
                size_t len = 1024;
                u32 *data = kmalloc(len, GFP_KERNEL);
 
@@ -326,21 +330,21 @@ static void lkdtm_do_action(enum ctype which)
                memset(data, 0x78, len);
                break;
        }
-       case SOFTLOCKUP:
+       case CT_SOFTLOCKUP:
                preempt_disable();
                for (;;)
                        cpu_relax();
                break;
-       case HARDLOCKUP:
+       case CT_HARDLOCKUP:
                local_irq_disable();
                for (;;)
                        cpu_relax();
                break;
-       case HUNG_TASK:
+       case CT_HUNG_TASK:
                set_current_state(TASK_UNINTERRUPTIBLE);
                schedule();
                break;
-       case NONE:
+       case CT_NONE:
        default:
                break;
        }
@@ -349,57 +353,65 @@ static void lkdtm_do_action(enum ctype which)
 
 static void lkdtm_handler(void)
 {
+       unsigned long flags;
+       bool do_it = false;
+
+       spin_lock_irqsave(&count_lock, flags);
        count--;
        printk(KERN_INFO "lkdtm: Crash point %s of type %s hit, trigger in %d rounds\n",
                        cp_name_to_str(cpoint), cp_type_to_str(cptype), count);
 
        if (count == 0) {
-               lkdtm_do_action(cptype);
+               do_it = true;
                count = cpoint_count;
        }
+       spin_unlock_irqrestore(&count_lock, flags);
+
+       if (do_it)
+               lkdtm_do_action(cptype);
 }
 
 static int lkdtm_register_cpoint(enum cname which)
 {
        int ret;
 
-       cpoint = INVALID;
+       cpoint = CN_INVALID;
        if (lkdtm.entry != NULL)
                unregister_jprobe(&lkdtm);
 
        switch (which) {
-       case DIRECT:
+       case CN_DIRECT:
                lkdtm_do_action(cptype);
                return 0;
-       case INT_HARDWARE_ENTRY:
+       case CN_INT_HARDWARE_ENTRY:
                lkdtm.kp.symbol_name = "do_IRQ";
                lkdtm.entry = (kprobe_opcode_t*) jp_do_irq;
                break;
-       case INT_HW_IRQ_EN:
+       case CN_INT_HW_IRQ_EN:
                lkdtm.kp.symbol_name = "handle_IRQ_event";
                lkdtm.entry = (kprobe_opcode_t*) jp_handle_irq_event;
                break;
-       case INT_TASKLET_ENTRY:
+       case CN_INT_TASKLET_ENTRY:
                lkdtm.kp.symbol_name = "tasklet_action";
                lkdtm.entry = (kprobe_opcode_t*) jp_tasklet_action;
                break;
-       case FS_DEVRW:
+       case CN_FS_DEVRW:
                lkdtm.kp.symbol_name = "ll_rw_block";
                lkdtm.entry = (kprobe_opcode_t*) jp_ll_rw_block;
                break;
-       case MEM_SWAPOUT:
+       case CN_MEM_SWAPOUT:
                lkdtm.kp.symbol_name = "shrink_inactive_list";
                lkdtm.entry = (kprobe_opcode_t*) jp_shrink_inactive_list;
                break;
-       case TIMERADD:
+       case CN_TIMERADD:
                lkdtm.kp.symbol_name = "hrtimer_start";
                lkdtm.entry = (kprobe_opcode_t*) jp_hrtimer_start;
                break;
-       case SCSI_DISPATCH_CMD:
+       case CN_SCSI_DISPATCH_CMD:
                lkdtm.kp.symbol_name = "scsi_dispatch_cmd";
                lkdtm.entry = (kprobe_opcode_t*) jp_scsi_dispatch_cmd;
                break;
-       case IDE_CORE_CP:
+       case CN_IDE_CORE_CP:
 #ifdef CONFIG_IDE
                lkdtm.kp.symbol_name = "generic_ide_ioctl";
                lkdtm.entry = (kprobe_opcode_t*) jp_generic_ide_ioctl;
@@ -416,7 +428,7 @@ static int lkdtm_register_cpoint(enum cname which)
        cpoint = which;
        if ((ret = register_jprobe(&lkdtm)) < 0) {
                printk(KERN_INFO "lkdtm: Couldn't register jprobe\n");
-               cpoint = INVALID;
+               cpoint = CN_INVALID;
        }
 
        return ret;
@@ -445,7 +457,7 @@ static ssize_t do_register_entry(enum cname which, struct file *f,
        cptype = parse_cp_type(buf, count);
        free_page((unsigned long) buf);
 
-       if (cptype == NONE)
+       if (cptype == CT_NONE)
                return -EINVAL;
 
        err = lkdtm_register_cpoint(which);
@@ -487,49 +499,49 @@ static int lkdtm_debugfs_open(struct inode *inode, struct file *file)
 static ssize_t int_hardware_entry(struct file *f, const char __user *buf,
                size_t count, loff_t *off)
 {
-       return do_register_entry(INT_HARDWARE_ENTRY, f, buf, count, off);
+       return do_register_entry(CN_INT_HARDWARE_ENTRY, f, buf, count, off);
 }
 
 static ssize_t int_hw_irq_en(struct file *f, const char __user *buf,
                size_t count, loff_t *off)
 {
-       return do_register_entry(INT_HW_IRQ_EN, f, buf, count, off);
+       return do_register_entry(CN_INT_HW_IRQ_EN, f, buf, count, off);
 }
 
 static ssize_t int_tasklet_entry(struct file *f, const char __user *buf,
                size_t count, loff_t *off)
 {
-       return do_register_entry(INT_TASKLET_ENTRY, f, buf, count, off);
+       return do_register_entry(CN_INT_TASKLET_ENTRY, f, buf, count, off);
 }
 
 static ssize_t fs_devrw_entry(struct file *f, const char __user *buf,
                size_t count, loff_t *off)
 {
-       return do_register_entry(FS_DEVRW, f, buf, count, off);
+       return do_register_entry(CN_FS_DEVRW, f, buf, count, off);
 }
 
 static ssize_t mem_swapout_entry(struct file *f, const char __user *buf,
                size_t count, loff_t *off)
 {
-       return do_register_entry(MEM_SWAPOUT, f, buf, count, off);
+       return do_register_entry(CN_MEM_SWAPOUT, f, buf, count, off);
 }
 
 static ssize_t timeradd_entry(struct file *f, const char __user *buf,
                size_t count, loff_t *off)
 {
-       return do_register_entry(TIMERADD, f, buf, count, off);
+       return do_register_entry(CN_TIMERADD, f, buf, count, off);
 }
 
 static ssize_t scsi_dispatch_cmd_entry(struct file *f,
                const char __user *buf, size_t count, loff_t *off)
 {
-       return do_register_entry(SCSI_DISPATCH_CMD, f, buf, count, off);
+       return do_register_entry(CN_SCSI_DISPATCH_CMD, f, buf, count, off);
 }
 
 static ssize_t ide_core_cp_entry(struct file *f, const char __user *buf,
                size_t count, loff_t *off)
 {
-       return do_register_entry(IDE_CORE_CP, f, buf, count, off);
+       return do_register_entry(CN_IDE_CORE_CP, f, buf, count, off);
 }
 
 /* Special entry to just crash directly. Available without KPROBEs */
@@ -557,7 +569,7 @@ static ssize_t direct_entry(struct file *f, const char __user *user_buf,
 
        type = parse_cp_type(buf, count);
        free_page((unsigned long) buf);
-       if (type == NONE)
+       if (type == CT_NONE)
                return -EINVAL;
 
        printk(KERN_INFO "lkdtm: Performing direct entry %s\n",
@@ -575,30 +587,39 @@ struct crash_entry {
 
 static const struct crash_entry crash_entries[] = {
        {"DIRECT", {.read = lkdtm_debugfs_read,
+                       .llseek = generic_file_llseek,
                        .open = lkdtm_debugfs_open,
                        .write = direct_entry} },
        {"INT_HARDWARE_ENTRY", {.read = lkdtm_debugfs_read,
+                       .llseek = generic_file_llseek,
                        .open = lkdtm_debugfs_open,
                        .write = int_hardware_entry} },
        {"INT_HW_IRQ_EN", {.read = lkdtm_debugfs_read,
+                       .llseek = generic_file_llseek,
                        .open = lkdtm_debugfs_open,
                        .write = int_hw_irq_en} },
        {"INT_TASKLET_ENTRY", {.read = lkdtm_debugfs_read,
+                       .llseek = generic_file_llseek,
                        .open = lkdtm_debugfs_open,
                        .write = int_tasklet_entry} },
        {"FS_DEVRW", {.read = lkdtm_debugfs_read,
+                       .llseek = generic_file_llseek,
                        .open = lkdtm_debugfs_open,
                        .write = fs_devrw_entry} },
        {"MEM_SWAPOUT", {.read = lkdtm_debugfs_read,
+                       .llseek = generic_file_llseek,
                        .open = lkdtm_debugfs_open,
                        .write = mem_swapout_entry} },
        {"TIMERADD", {.read = lkdtm_debugfs_read,
+                       .llseek = generic_file_llseek,
                        .open = lkdtm_debugfs_open,
                        .write = timeradd_entry} },
        {"SCSI_DISPATCH_CMD", {.read = lkdtm_debugfs_read,
+                       .llseek = generic_file_llseek,
                        .open = lkdtm_debugfs_open,
                        .write = scsi_dispatch_cmd_entry} },
        {"IDE_CORE_CP", {.read = lkdtm_debugfs_read,
+                       .llseek = generic_file_llseek,
                        .open = lkdtm_debugfs_open,
                        .write = ide_core_cp_entry} },
 };
@@ -640,7 +661,7 @@ static int __init lkdtm_module_init(void)
                goto out_err;
        }
 
-       if (cpoint != INVALID && cptype != NONE) {
+       if (cpoint != CN_INVALID && cptype != CT_NONE) {
                ret = lkdtm_register_cpoint(cpoint);
                if (ret < 0) {
                        printk(KERN_INFO "lkdtm: Invalid crash point %d\n",