diff options
author | Ingo Molnar <mingo@kernel.org> | 2012-04-14 13:18:27 +0200 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2012-04-14 13:19:04 +0200 |
commit | 6ac1ef482d7ae0c690f1640bf6eb818ff9a2d91e (patch) | |
tree | 021cc9f6b477146fcebe6f3be4752abfa2ba18a9 /drivers/watchdog/softdog.c | |
parent | 682968e0c425c60f0dde37977e5beb2b12ddc4cc (diff) | |
parent | a385ec4f11bdcf81af094c03e2444ee9b7fad2e5 (diff) |
Merge branch 'perf/core' into perf/uprobes
Merge in latest upstream (and the latest perf development tree),
to prepare for tooling changes, and also to pick up v3.4 MM
changes that the uprobes code needs to take care of.
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'drivers/watchdog/softdog.c')
-rw-r--r-- | drivers/watchdog/softdog.c | 211 |
1 files changed, 47 insertions, 164 deletions
diff --git a/drivers/watchdog/softdog.c b/drivers/watchdog/softdog.c index bf16ffb4d21..fe83beb8f1b 100644 --- a/drivers/watchdog/softdog.c +++ b/drivers/watchdog/softdog.c @@ -1,5 +1,5 @@ /* - * SoftDog 0.07: A Software Watchdog Device + * SoftDog: A Software Watchdog Device * * (c) Copyright 1996 Alan Cox <alan@lxorguk.ukuu.org.uk>, * All Rights Reserved. @@ -36,45 +36,37 @@ * Added Matt Domsch's nowayout module option. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/types.h> #include <linux/timer.h> #include <linux/miscdevice.h> #include <linux/watchdog.h> -#include <linux/fs.h> #include <linux/notifier.h> #include <linux/reboot.h> #include <linux/init.h> #include <linux/jiffies.h> -#include <linux/uaccess.h> #include <linux/kernel.h> -#define PFX "SoftDog: " - #define TIMER_MARGIN 60 /* Default is 60 seconds */ -static int soft_margin = TIMER_MARGIN; /* in seconds */ -module_param(soft_margin, int, 0); +static unsigned int soft_margin = TIMER_MARGIN; /* in seconds */ +module_param(soft_margin, uint, 0); MODULE_PARM_DESC(soft_margin, "Watchdog soft_margin in seconds. (0 < soft_margin < 65536, default=" __MODULE_STRING(TIMER_MARGIN) ")"); -static int nowayout = WATCHDOG_NOWAYOUT; -module_param(nowayout, int, 0); +static bool nowayout = WATCHDOG_NOWAYOUT; +module_param(nowayout, bool, 0); MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); -#ifdef ONLY_TESTING -static int soft_noboot = 1; -#else static int soft_noboot = 0; -#endif /* ONLY_TESTING */ - module_param(soft_noboot, int, 0); MODULE_PARM_DESC(soft_noboot, - "Softdog action, set to 1 to ignore reboots, 0 to reboot " - "(default depends on ONLY_TESTING)"); + "Softdog action, set to 1 to ignore reboots, 0 to reboot (default=0)"); static int soft_panic; module_param(soft_panic, int, 0); @@ -89,9 +81,6 @@ static void watchdog_fire(unsigned long); static struct timer_list watchdog_ticktock = TIMER_INITIALIZER(watchdog_fire, 0, 0); -static unsigned long driver_open, orphan_timer; -static char expect_close; - /* * If the timer expires.. @@ -99,18 +88,15 @@ static char expect_close; static void watchdog_fire(unsigned long data) { - if (test_and_clear_bit(0, &orphan_timer)) - module_put(THIS_MODULE); - if (soft_noboot) - printk(KERN_CRIT PFX "Triggered - Reboot ignored.\n"); + pr_crit("Triggered - Reboot ignored\n"); else if (soft_panic) { - printk(KERN_CRIT PFX "Initiating panic.\n"); - panic("Software Watchdog Timer expired."); + pr_crit("Initiating panic\n"); + panic("Software Watchdog Timer expired"); } else { - printk(KERN_CRIT PFX "Initiating system reboot.\n"); + pr_crit("Initiating system reboot\n"); emergency_restart(); - printk(KERN_CRIT PFX "Reboot didn't ?????\n"); + pr_crit("Reboot didn't ?????\n"); } } @@ -118,127 +104,24 @@ static void watchdog_fire(unsigned long data) * Softdog operations */ -static int softdog_keepalive(void) +static int softdog_ping(struct watchdog_device *w) { - mod_timer(&watchdog_ticktock, jiffies+(soft_margin*HZ)); + mod_timer(&watchdog_ticktock, jiffies+(w->timeout*HZ)); return 0; } -static int softdog_stop(void) +static int softdog_stop(struct watchdog_device *w) { del_timer(&watchdog_ticktock); return 0; } -static int softdog_set_heartbeat(int t) -{ - if ((t < 0x0001) || (t > 0xFFFF)) - return -EINVAL; - - soft_margin = t; - return 0; -} - -/* - * /dev/watchdog handling - */ - -static int softdog_open(struct inode *inode, struct file *file) -{ - if (test_and_set_bit(0, &driver_open)) - return -EBUSY; - if (!test_and_clear_bit(0, &orphan_timer)) - __module_get(THIS_MODULE); - /* - * Activate timer - */ - softdog_keepalive(); - return nonseekable_open(inode, file); -} - -static int softdog_release(struct inode *inode, struct file *file) +static int softdog_set_timeout(struct watchdog_device *w, unsigned int t) { - /* - * Shut off the timer. - * Lock it in if it's a module and we set nowayout - */ - if (expect_close == 42) { - softdog_stop(); - module_put(THIS_MODULE); - } else { - printk(KERN_CRIT PFX - "Unexpected close, not stopping watchdog!\n"); - set_bit(0, &orphan_timer); - softdog_keepalive(); - } - clear_bit(0, &driver_open); - expect_close = 0; + w->timeout = t; return 0; } -static ssize_t softdog_write(struct file *file, const char __user *data, - size_t len, loff_t *ppos) -{ - /* - * Refresh the timer. - */ - if (len) { - if (!nowayout) { - size_t i; - - /* In case it was set long ago */ - expect_close = 0; - - for (i = 0; i != len; i++) { - char c; - - if (get_user(c, data + i)) - return -EFAULT; - if (c == 'V') - expect_close = 42; - } - } - softdog_keepalive(); - } - return len; -} - -static long softdog_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - void __user *argp = (void __user *)arg; - int __user *p = argp; - int new_margin; - static const struct watchdog_info ident = { - .options = WDIOF_SETTIMEOUT | - WDIOF_KEEPALIVEPING | - WDIOF_MAGICCLOSE, - .firmware_version = 0, - .identity = "Software Watchdog", - }; - switch (cmd) { - case WDIOC_GETSUPPORT: - return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; - case WDIOC_GETSTATUS: - case WDIOC_GETBOOTSTATUS: - return put_user(0, p); - case WDIOC_KEEPALIVE: - softdog_keepalive(); - return 0; - case WDIOC_SETTIMEOUT: - if (get_user(new_margin, p)) - return -EFAULT; - if (softdog_set_heartbeat(new_margin)) - return -EINVAL; - softdog_keepalive(); - /* Fall */ - case WDIOC_GETTIMEOUT: - return put_user(soft_margin, p); - default: - return -ENOTTY; - } -} - /* * Notifier for system down */ @@ -248,7 +131,7 @@ static int softdog_notify_sys(struct notifier_block *this, unsigned long code, { if (code == SYS_DOWN || code == SYS_HALT) /* Turn the WDT off */ - softdog_stop(); + softdog_stop(NULL); return NOTIFY_DONE; } @@ -256,28 +139,29 @@ static int softdog_notify_sys(struct notifier_block *this, unsigned long code, * Kernel Interfaces */ -static const struct file_operations softdog_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .write = softdog_write, - .unlocked_ioctl = softdog_ioctl, - .open = softdog_open, - .release = softdog_release, +static struct notifier_block softdog_notifier = { + .notifier_call = softdog_notify_sys, }; -static struct miscdevice softdog_miscdev = { - .minor = WATCHDOG_MINOR, - .name = "watchdog", - .fops = &softdog_fops, +static struct watchdog_info softdog_info = { + .identity = "Software Watchdog", + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, }; -static struct notifier_block softdog_notifier = { - .notifier_call = softdog_notify_sys, +static struct watchdog_ops softdog_ops = { + .owner = THIS_MODULE, + .start = softdog_ping, + .stop = softdog_stop, + .ping = softdog_ping, + .set_timeout = softdog_set_timeout, }; -static char banner[] __initdata = KERN_INFO "Software Watchdog Timer: 0.07 " - "initialized. soft_noboot=%d soft_margin=%d sec soft_panic=%d " - "(nowayout= %d)\n"; +static struct watchdog_device softdog_dev = { + .info = &softdog_info, + .ops = &softdog_ops, + .min_timeout = 1, + .max_timeout = 0xFFFF +}; static int __init watchdog_init(void) { @@ -285,37 +169,36 @@ static int __init watchdog_init(void) /* Check that the soft_margin value is within it's range; if not reset to the default */ - if (softdog_set_heartbeat(soft_margin)) { - softdog_set_heartbeat(TIMER_MARGIN); - printk(KERN_INFO PFX - "soft_margin must be 0 < soft_margin < 65536, using %d\n", + if (soft_margin < 1 || soft_margin > 65535) { + pr_info("soft_margin must be 0 < soft_margin < 65536, using %d\n", TIMER_MARGIN); + return -EINVAL; } + softdog_dev.timeout = soft_margin; + + watchdog_set_nowayout(&softdog_dev, nowayout); ret = register_reboot_notifier(&softdog_notifier); if (ret) { - printk(KERN_ERR PFX - "cannot register reboot notifier (err=%d)\n", ret); + pr_err("cannot register reboot notifier (err=%d)\n", ret); return ret; } - ret = misc_register(&softdog_miscdev); + ret = watchdog_register_device(&softdog_dev); if (ret) { - printk(KERN_ERR PFX - "cannot register miscdev on minor=%d (err=%d)\n", - WATCHDOG_MINOR, ret); unregister_reboot_notifier(&softdog_notifier); return ret; } - printk(banner, soft_noboot, soft_margin, soft_panic, nowayout); + pr_info("Software Watchdog Timer: 0.08 initialized. soft_noboot=%d soft_margin=%d sec soft_panic=%d (nowayout=%d)\n", + soft_noboot, soft_margin, soft_panic, nowayout); return 0; } static void __exit watchdog_exit(void) { - misc_deregister(&softdog_miscdev); + watchdog_unregister_device(&softdog_dev); unregister_reboot_notifier(&softdog_notifier); } |