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: | |||
| 127 | * WDOG_DEV_OPEN: this status bit shows whether or not the watchdog device | 127 | * WDOG_DEV_OPEN: this status bit shows whether or not the watchdog device |
| 128 | was opened via /dev/watchdog. | 128 | was opened via /dev/watchdog. |
| 129 | (This bit should only be used by the WatchDog Timer Driver Core). | 129 | (This bit should only be used by the WatchDog Timer Driver Core). |
| 130 | * WDOG_ALLOW_RELEASE: this bit stores whether or not the magic close character | ||
| 131 | has been sent (so that we can support the magic close feature). | ||
| 132 | (This bit should only be used by the WatchDog Timer Driver Core). | ||
| 133 | |||
| 134 | Note: The WatchDog Timer Driver Core supports the magic close feature. To use | ||
| 135 | the magic close feature you must set the WDIOF_MAGICCLOSE bit in the options | ||
| 136 | field of the watchdog's info structure. | ||
| 130 | 137 | ||
| 131 | To get or set driver specific data the following two helper functions should be | 138 | To get or set driver specific data the following two helper functions should be |
| 132 | used: | 139 | 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) | |||
| 122 | * @ppos: pointer to the file offset | 122 | * @ppos: pointer to the file offset |
| 123 | * | 123 | * |
| 124 | * A write to a watchdog device is defined as a keepalive ping. | 124 | * A write to a watchdog device is defined as a keepalive ping. |
| 125 | * Writing the magic 'V' sequence allows the next close to turn | ||
| 126 | * off the watchdog. | ||
| 125 | */ | 127 | */ |
| 126 | 128 | ||
| 127 | static ssize_t watchdog_write(struct file *file, const char __user *data, | 129 | 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, | |||
| 133 | if (len == 0) | 135 | if (len == 0) |
| 134 | return 0; | 136 | return 0; |
| 135 | 137 | ||
| 138 | /* | ||
| 139 | * Note: just in case someone wrote the magic character | ||
| 140 | * five months ago... | ||
| 141 | */ | ||
| 142 | clear_bit(WDOG_ALLOW_RELEASE, &wdd->status); | ||
| 143 | |||
| 144 | /* scan to see whether or not we got the magic character */ | ||
| 136 | for (i = 0; i != len; i++) { | 145 | for (i = 0; i != len; i++) { |
| 137 | if (get_user(c, data + i)) | 146 | if (get_user(c, data + i)) |
| 138 | return -EFAULT; | 147 | return -EFAULT; |
| 148 | if (c == 'V') | ||
| 149 | set_bit(WDOG_ALLOW_RELEASE, &wdd->status); | ||
| 139 | } | 150 | } |
| 140 | 151 | ||
| 141 | /* someone wrote to us, so we send the watchdog a keepalive ping */ | 152 | /* someone wrote to us, so we send the watchdog a keepalive ping */ |
| @@ -259,14 +270,24 @@ out: | |||
| 259 | * @inode: inode of device | 270 | * @inode: inode of device |
| 260 | * @file: file handle to device | 271 | * @file: file handle to device |
| 261 | * | 272 | * |
| 262 | * This is the code for when /dev/watchdog gets closed. | 273 | * This is the code for when /dev/watchdog gets closed. We will only |
| 274 | * stop the watchdog when we have received the magic char, else the | ||
| 275 | * watchdog will keep running. | ||
| 263 | */ | 276 | */ |
| 264 | 277 | ||
| 265 | static int watchdog_release(struct inode *inode, struct file *file) | 278 | static int watchdog_release(struct inode *inode, struct file *file) |
| 266 | { | 279 | { |
| 267 | int err; | 280 | int err = -EBUSY; |
| 281 | |||
| 282 | /* | ||
| 283 | * We only stop the watchdog if we received the magic character | ||
| 284 | * or if WDIOF_MAGICCLOSE is not set | ||
| 285 | */ | ||
| 286 | if (test_and_clear_bit(WDOG_ALLOW_RELEASE, &wdd->status) || | ||
| 287 | !(wdd->info->options & WDIOF_MAGICCLOSE)) | ||
| 288 | err = watchdog_stop(wdd); | ||
| 268 | 289 | ||
| 269 | err = watchdog_stop(wdd); | 290 | /* If the watchdog was not stopped, send a keepalive ping */ |
| 270 | if (err < 0) { | 291 | if (err < 0) { |
| 271 | pr_crit("%s: watchdog did not stop!\n", wdd->info->identity); | 292 | pr_crit("%s: watchdog did not stop!\n", wdd->info->identity); |
| 272 | watchdog_ping(wdd); | 293 | 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 { | |||
| 112 | /* Bit numbers for status flags */ | 112 | /* Bit numbers for status flags */ |
| 113 | #define WDOG_ACTIVE 0 /* Is the watchdog running/active */ | 113 | #define WDOG_ACTIVE 0 /* Is the watchdog running/active */ |
| 114 | #define WDOG_DEV_OPEN 1 /* Opened via /dev/watchdog ? */ | 114 | #define WDOG_DEV_OPEN 1 /* Opened via /dev/watchdog ? */ |
| 115 | #define WDOG_ALLOW_RELEASE 2 /* Did we receive the magic char ? */ | ||
| 115 | }; | 116 | }; |
| 116 | 117 | ||
| 117 | /* Use the following functions to manipulate watchdog driver specific data */ | 118 | /* Use the following functions to manipulate watchdog driver specific data */ |
