Linux之watchdog
Linux之watchdog
使用
都是通过/dev/watchdog
设备节点来操作使用
通过命令
# 写入除大写字母‘V’外的任意字符,开启看门狗,每 44 秒内需要写入一次(喂狗)
echo A > /dev/watchdog
# 开启看门狗,并且内核会每隔 22 秒自动喂一次狗
echo V > /dev/watchdog
通过应用程序
示例如下:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main(void)
{
/*通过open来启动watchdog*/
int fd = open("/dev/watchdog", O_WRONLY);
int ret = 0;
if (fd == -1) {
perror("watchdog");
exit(EXIT_FAILURE);
}
while (1) {
/*通过write来喂狗 等同于 ioctl(fd, WDIOC_KEEPALIVE, 0);*/
ret = write(fd, "\0", 1);
if (ret != 1) {
ret = -1;
break;
}
sleep(10);
}
close(fd);
return ret;
}
使用说明:
- 内部看门狗在使用
open()
函数打开后会立刻开始计时 - 正常情况下
close()
, 内核不再喂狗, 系统会自动超时重启,因为close
并没停止看门狗 write(fd, "V", 1);
再close()
, 即写入大写V(类似echo V > /dev/watchdog
), 且nowayout
未置位,会真正stop看门狗,内核会继续喂狗, 系统不会自动重启- 如果
nowayout
置位,watchdog启动后(即/dev/watchdog被打开后),则将没有办法能够停止,无论是执行close操作还是写入”V”都不行,所以此情况下重复第3点,如果不按时喂狗系统会超时重启
内核主要源码分析
从内核源码分析上面的使用说明,对应看就一目了然了,所以这里就不做过多的文字描述,”talk is cheap”
主要的驱动文件:
//具体的芯片驱动,这里列举的是比较常见的DesignWare的
drivers/watchdog/dw_wdt.c
//watchdog相关的核心功能代码
drivers/watchdog/watchdog_core.c
drivers/watchdog/watchdog_dev.c
drivers/watchdog/watchdog_pretimeout.c
magic 'V'
的处理
写入magic 'V'
时的操作:
/*
* watchdog_write: writes to the watchdog.
* @file: file from VFS
* @data: user address of data
* @len: length of data
* @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 (if 'nowayout' is not set).
*/
static ssize_t watchdog_write(struct file *file, const char __user *data,
size_t len, loff_t *ppos)
{
struct watchdog_core_data *wd_data = file->private_data;
struct watchdog_device *wdd;
int err;
size_t i;
char c;
if (len == 0)
return 0;
/*
* Note: just in case someone wrote the magic character
* five months ago...
*/
clear_bit(_WDOG_ALLOW_RELEASE, &wd_data->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, &wd_data->status);
}
/* someone wrote to us, so we send the watchdog a keepalive ping */
err = -ENODEV;
mutex_lock(&wd_data->lock);
wdd = wd_data->wdd;
if (wdd)
err = watchdog_ping(wdd);
mutex_unlock(&wd_data->lock);
if (err < 0)
return err;
return len;
}
close()
的处理
下面是close()
的处理:
/*
* watchdog_release: release the watchdog device.
* @inode: inode of device
* @file: file handle to device
*
* This is the code for when /dev/watchdog gets closed. We will only
* stop the watchdog when we have received the magic char (and nowayout
* was not set), else the watchdog will keep running.
*/
static int watchdog_release(struct inode *inode, struct file *file)
{
...
/*
* We only stop the watchdog if we received the magic character
* or if WDIOF_MAGICCLOSE is not set. If nowayout was set then
* watchdog_stop will fail.
*/
if (!watchdog_active(wdd))
err = 0;
else if (test_and_clear_bit(_WDOG_ALLOW_RELEASE, &wd_data->status) ||
!(wdd->info->options & WDIOF_MAGICCLOSE))
err = watchdog_stop(wdd);
/* If the watchdog was not stopped, send a keepalive ping */
if (err < 0) {
pr_crit("watchdog%d: watchdog did not stop!\n", wdd->id);
watchdog_ping(wdd);
}
watchdog_update_worker(wdd);
/* make sure that /dev/watchdog can be re-opened */
clear_bit(_WDOG_DEV_OPEN, &wd_data->status);
...
}
/*
* watchdog_stop: wrapper to stop the watchdog.
* @wdd: the watchdog device to stop
*
* The caller must hold wd_data->lock.
*
* Stop the watchdog if it is still active and unmark it active.
* This function returns zero on success or a negative errno code for
* failure.
* If the 'nowayout' feature was set, the watchdog cannot be stopped.
*/
static int watchdog_stop(struct watchdog_device *wdd)
{
int err = 0;
if (!watchdog_active(wdd))
return 0;
if (test_bit(WDOG_NO_WAY_OUT, &wdd->status)) {
pr_info("watchdog%d: nowayout prevents watchdog being stopped!\n",
wdd->id);
return -EBUSY;
}
if (wdd->ops->stop) {
clear_bit(WDOG_HW_RUNNING, &wdd->status);
err = wdd->ops->stop(wdd);
} else {
set_bit(WDOG_HW_RUNNING, &wdd->status);
}
if (err == 0) {
clear_bit(WDOG_ACTIVE, &wdd->status);
watchdog_update_worker(wdd);
watchdog_hrtimer_pretimeout_stop(wdd);
}
return err;
}
nowayout
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) ")");
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 DD'Notes!
评论