diff options
-rw-r--r-- | Documentation/watchdog/watchdog-kernel-api.txt | 7 | ||||
-rw-r--r-- | drivers/watchdog/watchdog_dev.c | 27 | ||||
-rw-r--r-- | include/linux/watchdog.h | 1 |
3 files changed, 32 insertions, 3 deletions
diff --git a/Documentation/watchdog/watchdog-kernel-api.txt b/Documentation/watchdog/watchdog-kernel-api.txt index acdee39fb08a..41d552698ada 100644 --- a/Documentation/watchdog/watchdog-kernel-api.txt +++ b/Documentation/watchdog/watchdog-kernel-api.txt @@ -127,6 +127,13 @@ bit-operations. The status bits that are defined are: * WDOG_DEV_OPEN: this status bit shows whether or not the watchdog device was opened via /dev/watchdog. (This bit should only be used by the WatchDog Timer Driver Core). +* WDOG_ALLOW_RELEASE: this bit stores whether or not the magic close character + has been sent (so that we can support the magic close feature). + (This bit should only be used by the WatchDog Timer Driver Core). + +Note: The WatchDog Timer Driver Core supports the magic close feature. To use +the magic close feature you must set the WDIOF_MAGICCLOSE bit in the options +field of the watchdog's info structure. To get or set driver specific data the following two helper functions should be used: diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c index 2c0289deaadd..db40c6c79ef8 100644 --- a/drivers/watchdog/watchdog_dev.c +++ b/drivers/watchdog/watchdog_dev.c @@ -122,6 +122,8 @@ static int watchdog_stop(struct watchdog_device *wddev) * @ppos: pointer to the file offset * * A write to a watchdog device is defined as a keepalive ping. + * Writing the magic 'V' sequence allows the next close to turn + * off the watchdog. */ static ssize_t watchdog_write(struct file *file, const char __user *data, @@ -133,9 +135,18 @@ static ssize_t watchdog_write(struct file *file, const char __user *data, if (len == 0) return 0; + /* + * Note: just in case someone wrote the magic character + * five months ago... + */ + clear_bit(WDOG_ALLOW_RELEASE, &wdd->status); + + /* scan to see whether or not we got the magic character */ for (i = 0; i != len; i++) { if (get_user(c, data + i)) return -EFAULT; + if (c == 'V') + set_bit(WDOG_ALLOW_RELEASE, &wdd->status); } /* someone wrote to us, so we send the watchdog a keepalive ping */ @@ -259,14 +270,24 @@ out: * @inode: inode of device * @file: file handle to device * - * This is the code for when /dev/watchdog gets closed. + * This is the code for when /dev/watchdog gets closed. We will only + * stop the watchdog when we have received the magic char, else the + * watchdog will keep running. */ static int watchdog_release(struct inode *inode, struct file *file) { - int err; + int err = -EBUSY; + + /* + * We only stop the watchdog if we received the magic character + * or if WDIOF_MAGICCLOSE is not set + */ + if (test_and_clear_bit(WDOG_ALLOW_RELEASE, &wdd->status) || + !(wdd->info->options & WDIOF_MAGICCLOSE)) + err = watchdog_stop(wdd); - err = watchdog_stop(wdd); + /* If the watchdog was not stopped, send a keepalive ping */ if (err < 0) { pr_crit("%s: watchdog did not stop!\n", wdd->info->identity); watchdog_ping(wdd); diff --git a/include/linux/watchdog.h b/include/linux/watchdog.h index 9f33efe199d1..e9881ca2452b 100644 --- a/include/linux/watchdog.h +++ b/include/linux/watchdog.h @@ -112,6 +112,7 @@ struct watchdog_device { /* Bit numbers for status flags */ #define WDOG_ACTIVE 0 /* Is the watchdog running/active */ #define WDOG_DEV_OPEN 1 /* Opened via /dev/watchdog ? */ +#define WDOG_ALLOW_RELEASE 2 /* Did we receive the magic char ? */ }; /* Use the following functions to manipulate watchdog driver specific data */ |