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!
 评论


 
