⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vmwatchdog.c

📁 linux-2.6.15.6
💻 C
字号:
/* * Watchdog implementation based on z/VM Watchdog Timer API * * The user space watchdog daemon can use this driver as * /dev/vmwatchdog to have z/VM execute the specified CP * command when the timeout expires. The default command is * "IPL", which which cause an immediate reboot. */#include <linux/init.h>#include <linux/fs.h>#include <linux/kernel.h>#include <linux/miscdevice.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/watchdog.h>#include <asm/ebcdic.h>#include <asm/io.h>#include <asm/uaccess.h>#define MAX_CMDLEN 240#define MIN_INTERVAL 15static char vmwdt_cmd[MAX_CMDLEN] = "IPL";static int vmwdt_conceal;static int vmwdt_nowayout = WATCHDOG_NOWAYOUT;MODULE_LICENSE("GPL");MODULE_AUTHOR("Arnd Bergmann <arndb@de.ibm.com>");MODULE_DESCRIPTION("z/VM Watchdog Timer");module_param_string(cmd, vmwdt_cmd, MAX_CMDLEN, 0644);MODULE_PARM_DESC(cmd, "CP command that is run when the watchdog triggers");module_param_named(conceal, vmwdt_conceal, bool, 0644);MODULE_PARM_DESC(conceal, "Enable the CONCEAL CP option while the watchdog "		" is active");module_param_named(nowayout, vmwdt_nowayout, bool, 0);MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"		" (default=CONFIG_WATCHDOG_NOWAYOUT)");MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);static unsigned int vmwdt_interval = 60;static unsigned long vmwdt_is_open;static int vmwdt_expect_close;enum vmwdt_func {	/* function codes */	wdt_init   = 0,	wdt_change = 1,	wdt_cancel = 2,	/* flags */	wdt_conceal = 0x80000000,};static int __diag288(enum vmwdt_func func, unsigned int timeout,			    char *cmd, size_t len){	register unsigned long __func asm("2");	register unsigned long __timeout asm("3");	register unsigned long __cmdp asm("4");	register unsigned long __cmdl asm("5");	int err;	__func = func;	__timeout = timeout;	__cmdp = virt_to_phys(cmd);	__cmdl = len;	err = 0;	asm volatile (#ifdef __s390x__		       "diag %2,%4,0x288\n"		"1:	\n"		".section .fixup,\"ax\"\n"		"2:	lghi %0,%1\n"		"	jg 1b\n"		".previous\n"		".section __ex_table,\"a\"\n"		"	.align 8\n"		"	.quad 1b,2b\n"		".previous\n"#else		       "diag %2,%4,0x288\n"		"1:	\n"		".section .fixup,\"ax\"\n"		"2:	lhi %0,%1\n"		"	bras 1,3f\n"		"	.long 1b\n"		"3:	l 1,0(1)\n"		"	br 1\n"		".previous\n"		".section __ex_table,\"a\"\n"		"	.align 4\n"		"	.long 1b,2b\n"		".previous\n"#endif		: "+&d"(err)		: "i"(-EINVAL), "d"(__func), "d"(__timeout),		  "d"(__cmdp), "d"(__cmdl)		: "1", "cc");	return err;}static int vmwdt_keepalive(void){	/* we allocate new memory every time to avoid having	 * to track the state. static allocation is not an	 * option since that might not be contiguous in real	 * storage in case of a modular build */	static char *ebc_cmd;	size_t len;	int ret;	unsigned int func;	ebc_cmd = kmalloc(MAX_CMDLEN, GFP_KERNEL);	if (!ebc_cmd)		return -ENOMEM;	len = strlcpy(ebc_cmd, vmwdt_cmd, MAX_CMDLEN);	ASCEBC(ebc_cmd, MAX_CMDLEN);	EBC_TOUPPER(ebc_cmd, MAX_CMDLEN);	func = vmwdt_conceal ? (wdt_init | wdt_conceal) : wdt_init;	ret = __diag288(func, vmwdt_interval, ebc_cmd, len);	kfree(ebc_cmd);	if (ret) {		printk(KERN_WARNING "%s: problem setting interval %d, "			"cmd %s\n", __FUNCTION__, vmwdt_interval,			vmwdt_cmd);	}	return ret;}static int vmwdt_disable(void){	int ret = __diag288(wdt_cancel, 0, "", 0);	if (ret) {		printk(KERN_WARNING "%s: problem disabling watchdog\n",			__FUNCTION__);	}	return ret;}static int __init vmwdt_probe(void){	/* there is no real way to see if the watchdog is supported,	 * so we try initializing it with a NOP command ("BEGIN")	 * that won't cause any harm even if the following disable	 * fails for some reason */	static char __initdata ebc_begin[] = {		194, 197, 199, 201, 213	};	if (__diag288(wdt_init, 15, ebc_begin, sizeof(ebc_begin)) != 0) {		printk(KERN_INFO "z/VM watchdog not available\n");		return -EINVAL;	}	return vmwdt_disable();}static int vmwdt_open(struct inode *i, struct file *f){	int ret;	if (test_and_set_bit(0, &vmwdt_is_open))		return -EBUSY;	ret = vmwdt_keepalive();	if (ret)		clear_bit(0, &vmwdt_is_open);	return ret ? ret : nonseekable_open(i, f);}static int vmwdt_close(struct inode *i, struct file *f){	if (vmwdt_expect_close == 42)		vmwdt_disable();	vmwdt_expect_close = 0;	clear_bit(0, &vmwdt_is_open);	return 0;}static struct watchdog_info vmwdt_info = {	.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,	.firmware_version = 0,	.identity = "z/VM Watchdog Timer",};static int vmwdt_ioctl(struct inode *i, struct file *f,			  unsigned int cmd, unsigned long arg){	switch (cmd) {	case WDIOC_GETSUPPORT:		if (copy_to_user((void __user *)arg, &vmwdt_info,					sizeof(vmwdt_info)))			return -EFAULT;		return 0;	case WDIOC_GETSTATUS:	case WDIOC_GETBOOTSTATUS:		return put_user(0, (int *)arg);	case WDIOC_GETTEMP:		return -EINVAL;	case WDIOC_SETOPTIONS:		{			int options, ret;			if (get_user(options, (int __user *)arg))				return -EFAULT;			ret = -EINVAL;			if (options & WDIOS_DISABLECARD) {				ret = vmwdt_disable();				if (ret)					return ret;			}			if (options & WDIOS_ENABLECARD) {				ret = vmwdt_keepalive();			}			return ret;		}	case WDIOC_GETTIMEOUT:		return put_user(vmwdt_interval, (int __user *)arg);	case WDIOC_SETTIMEOUT:		{			int interval;			if (get_user(interval, (int __user *)arg))				return -EFAULT;			if (interval < MIN_INTERVAL)				return -EINVAL;			vmwdt_interval = interval;		}		return vmwdt_keepalive();	case WDIOC_KEEPALIVE:		return vmwdt_keepalive();	}	return -EINVAL;}static ssize_t vmwdt_write(struct file *f, const char __user *buf,				size_t count, loff_t *ppos){	if(count) {		if (!vmwdt_nowayout) {			size_t i;			/* note: just in case someone wrote the magic character			 * five months ago... */			vmwdt_expect_close = 0;			for (i = 0; i != count; i++) {				char c;				if (get_user(c, buf+i))					return -EFAULT;				if (c == 'V')					vmwdt_expect_close = 42;			}		}		/* someone wrote to us, we should restart timer */		vmwdt_keepalive();	}	return count;}static struct file_operations vmwdt_fops = {	.open    = &vmwdt_open,	.release = &vmwdt_close,	.ioctl   = &vmwdt_ioctl,	.write   = &vmwdt_write,	.owner   = THIS_MODULE,};static struct miscdevice vmwdt_dev = {	.minor      = WATCHDOG_MINOR,	.name       = "watchdog",	.fops       = &vmwdt_fops,};static int __init vmwdt_init(void){	int ret;	ret = vmwdt_probe();	if (ret)		return ret;	return misc_register(&vmwdt_dev);}module_init(vmwdt_init);static void __exit vmwdt_exit(void){	WARN_ON(misc_deregister(&vmwdt_dev) != 0);}module_exit(vmwdt_exit);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -