softdog.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:5k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * SoftDog 0.05: A Software Watchdog Device
  3.  *
  4.  * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
  5.  * http://www.redhat.com
  6.  *
  7.  * This program is free software; you can redistribute it and/or
  8.  * modify it under the terms of the GNU General Public License
  9.  * as published by the Free Software Foundation; either version
  10.  * 2 of the License, or (at your option) any later version.
  11.  *
  12.  * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide 
  13.  * warranty for any of this software. This material is provided 
  14.  * "AS-IS" and at no charge.
  15.  *
  16.  * (c) Copyright 1995    Alan Cox <alan@lxorguk.ukuu.org.uk>
  17.  *
  18.  * Software only watchdog driver. Unlike its big brother the WDT501P
  19.  * driver this won't always recover a failed machine.
  20.  *
  21.  *  03/96: Angelo Haritsis <ah@doc.ic.ac.uk> :
  22.  * Modularised.
  23.  * Added soft_margin; use upon insmod to change the timer delay.
  24.  * NB: uses same minor as wdt (WATCHDOG_MINOR); we could use separate
  25.  *     minors.
  26.  *
  27.  *  19980911 Alan Cox
  28.  * Made SMP safe for 2.3.x
  29.  *
  30.  *  20011127 Joel Becker (jlbec@evilplan.org>
  31.  * Added soft_noboot; Allows testing the softdog trigger without 
  32.  * requiring a recompile.
  33.  * Added WDIOC_GETTIMEOUT and WDIOC_SETTIMOUT.
  34.  *
  35.  *  20020530 Joel Becker <joel.becker@oracle.com>
  36.  *   Added Matt Domsch's nowayout module option.
  37.  */
  38.  
  39. #include <linux/module.h>
  40. #include <linux/config.h>
  41. #include <linux/types.h>
  42. #include <linux/kernel.h>
  43. #include <linux/fs.h>
  44. #include <linux/mm.h>
  45. #include <linux/miscdevice.h>
  46. #include <linux/watchdog.h>
  47. #include <linux/reboot.h>
  48. #include <linux/smp_lock.h>
  49. #include <linux/init.h>
  50. #include <asm/uaccess.h>
  51. #define TIMER_MARGIN 60 /* (secs) Default is 1 minute */
  52. static int expect_close = 0;
  53. static int soft_margin = TIMER_MARGIN; /* in seconds */
  54. #ifdef ONLY_TESTING
  55. static int soft_noboot = 1;
  56. #else
  57. static int soft_noboot = 0;
  58. #endif  /* ONLY_TESTING */
  59. MODULE_PARM(soft_margin,"i");
  60. MODULE_PARM(soft_noboot,"i");
  61. MODULE_LICENSE("GPL");
  62. #ifdef CONFIG_WATCHDOG_NOWAYOUT
  63. static int nowayout = 1;
  64. #else
  65. static int nowayout = 0;
  66. #endif
  67. MODULE_PARM(nowayout,"i");
  68. MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
  69. /*
  70.  * Our timer
  71.  */
  72.  
  73. static void watchdog_fire(unsigned long);
  74. static struct timer_list watchdog_ticktock = {
  75. function: watchdog_fire,
  76. };
  77. static unsigned long timer_alive;
  78. /*
  79.  * If the timer expires..
  80.  */
  81.  
  82. static void watchdog_fire(unsigned long data)
  83. {
  84. if (soft_noboot)
  85. printk(KERN_CRIT "SOFTDOG: Triggered - Reboot ignored.n");
  86. else
  87. {
  88. printk(KERN_CRIT "SOFTDOG: Initiating system reboot.n");
  89. machine_restart(NULL);
  90. printk("SOFTDOG: Reboot didn't ?????n");
  91. }
  92. }
  93. /*
  94.  * Allow only one person to hold it open
  95.  */
  96.  
  97. static int softdog_open(struct inode *inode, struct file *file)
  98. {
  99. if(test_and_set_bit(0, &timer_alive))
  100. return -EBUSY;
  101. if (nowayout) {
  102. MOD_INC_USE_COUNT;
  103. }
  104. /*
  105.  * Activate timer
  106.  */
  107. mod_timer(&watchdog_ticktock, jiffies+(soft_margin*HZ));
  108. return 0;
  109. }
  110. static int softdog_release(struct inode *inode, struct file *file)
  111. {
  112. /*
  113.  * Shut off the timer.
  114.  *  Lock it in if it's a module and we set nowayout
  115.  */
  116. if (expect_close) {
  117. del_timer(&watchdog_ticktock);
  118. } else {
  119. printk(KERN_CRIT "SOFTDOG: WDT device closed unexpectedly.  WDT will not stop!n");
  120. }
  121. clear_bit(0, &timer_alive);
  122. return 0;
  123. }
  124. static ssize_t softdog_write(struct file *file, const char *data, size_t len, loff_t *ppos)
  125. {
  126. /*  Can't seek (pwrite) on this device  */
  127. if (ppos != &file->f_pos)
  128. return -ESPIPE;
  129. /*
  130.  * Refresh the timer.
  131.  */
  132. if(len) {
  133. if (!nowayout) {
  134. size_t i;
  135. /* In case it was set long ago */
  136. expect_close = 0;
  137. for (i = 0; i != len; i++) {
  138. char c;
  139. if (get_user(c, data + i))
  140. return -EFAULT;
  141. if (c == 'V')
  142. expect_close = 1;
  143. }
  144. }
  145. mod_timer(&watchdog_ticktock, jiffies+(soft_margin*HZ));
  146. return 1;
  147. }
  148. return 0;
  149. }
  150. static int softdog_ioctl(struct inode *inode, struct file *file,
  151. unsigned int cmd, unsigned long arg)
  152. {
  153. int new_margin;
  154. static struct watchdog_info ident = {
  155. WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
  156. 0,
  157. "Software Watchdog"
  158. };
  159. switch (cmd) {
  160. default:
  161. return -ENOTTY;
  162. case WDIOC_GETSUPPORT:
  163. if(copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident)))
  164. return -EFAULT;
  165. return 0;
  166. case WDIOC_GETSTATUS:
  167. case WDIOC_GETBOOTSTATUS:
  168. return put_user(0,(int *)arg);
  169. case WDIOC_KEEPALIVE:
  170. mod_timer(&watchdog_ticktock, jiffies+(soft_margin*HZ));
  171. return 0;
  172. case WDIOC_SETTIMEOUT:
  173. if (get_user(new_margin, (int *)arg))
  174. return -EFAULT;
  175. if (new_margin < 1)
  176. return -EINVAL;
  177. soft_margin = new_margin;
  178. mod_timer(&watchdog_ticktock, jiffies+(soft_margin*HZ));
  179. /* Fall */
  180. case WDIOC_GETTIMEOUT:
  181. return put_user(soft_margin, (int *)arg);
  182. }
  183. }
  184. static struct file_operations softdog_fops = {
  185. owner: THIS_MODULE,
  186. write: softdog_write,
  187. ioctl: softdog_ioctl,
  188. open: softdog_open,
  189. release: softdog_release,
  190. };
  191. static struct miscdevice softdog_miscdev = {
  192. minor: WATCHDOG_MINOR,
  193. name: "watchdog",
  194. fops: &softdog_fops,
  195. };
  196. static char banner[] __initdata = KERN_INFO "Software Watchdog Timer: 0.05, timer margin: %d secn";
  197. static int __init watchdog_init(void)
  198. {
  199. int ret;
  200. ret = misc_register(&softdog_miscdev);
  201. if (ret)
  202. return ret;
  203. printk(banner, soft_margin);
  204. return 0;
  205. }
  206. static void __exit watchdog_exit(void)
  207. {
  208. misc_deregister(&softdog_miscdev);
  209. }
  210. module_init(watchdog_init);
  211. module_exit(watchdog_exit);