Commit 69503e585192fdd84b240f18a0873d20e18a2e0a
Committed by
Wim Van Sebroeck
1 parent
b1301b9022
watchdog: fix UAF in reboot notifier handling in watchdog core code
After the commit 44ea39420fc9 ("drivers/watchdog: make use of devm_register_reboot_notifier()") the struct notifier_block reboot_nb in the struct watchdog_device is removed from the reboot notifiers chain at the time watchdog's chardev is closed. But at least in i6300esb.c case reboot_nb is embedded in the struct esb_dev which can be freed on its device removal and before the chardev is closed, thus UAF at reboot: [ 7.728581] esb_probe: esb_dev.watchdog_device ffff91316f91ab28 ts# uname -r note the address ^^^ 5.5.0-rc5-ae6088-wdog ts# ./openwdog0 & [1] 696 ts# opened /dev/watchdog0, sleeping 10s... ts# echo 1 > /sys/devices/pci0000\:00/0000\:00\:09.0/remove [ 178.086079] devres:rel_nodes: dev ffff91317668a0b0 data ffff91316f91ab28 esb_dev.watchdog_device.reboot_nb memory is freed here ^^^ ts# ...woken up [ 181.459010] devres:rel_nodes: dev ffff913171781000 data ffff913174a1dae8 [ 181.460195] devm_unreg_reboot_notifier: res ffff913174a1dae8 nb ffff91316f91ab78 attempt to use memory already freed ^^^ [ 181.461063] devm_unreg_reboot_notifier: nb->call 6b6b6b6b6b6b6b6b [ 181.461243] devm_unreg_reboot_notifier: nb->next 6b6b6b6b6b6b6b6b freed memory is filled with a slub poison ^^^ [1]+ Done ./openwdog0 ts# reboot [ 229.921862] systemd-shutdown[1]: Rebooting. [ 229.939265] notifier_call_chain: nb ffffffff9c6c2f20 nb->next ffffffff9c6d50c0 [ 229.943080] notifier_call_chain: nb ffffffff9c6d50c0 nb->next 6b6b6b6b6b6b6b6b [ 229.946054] notifier_call_chain: nb 6b6b6b6b6b6b6b6b INVAL [ 229.957584] general protection fault: 0000 [#1] SMP [ 229.958770] CPU: 0 PID: 1 Comm: systemd-shutdow Not tainted 5.5.0-rc5-ae6088-wdog [ 229.960224] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), ... [ 229.963288] RIP: 0010:notifier_call_chain+0x66/0xd0 [ 229.969082] RSP: 0018:ffffb20dc0013d88 EFLAGS: 00010246 [ 229.970812] RAX: 000000000000002e RBX: 6b6b6b6b6b6b6b6b RCX: 00000000000008b3 [ 229.972929] RDX: 0000000000000000 RSI: 0000000000000096 RDI: ffffffff9ccc46ac [ 229.975028] RBP: 0000000000000001 R08: 0000000000000000 R09: 00000000000008b3 [ 229.977039] R10: 0000000000000001 R11: ffffffff9c26c740 R12: 0000000000000000 [ 229.979155] R13: 6b6b6b6b6b6b6b6b R14: 0000000000000000 R15: 00000000fffffffa ... slub_debug=FZP poison ^^^ [ 229.989089] Call Trace: [ 229.990157] blocking_notifier_call_chain+0x43/0x59 [ 229.991401] kernel_restart_prepare+0x14/0x30 [ 229.992607] kernel_restart+0x9/0x30 [ 229.993800] __do_sys_reboot+0x1d2/0x210 [ 230.000149] do_syscall_64+0x3d/0x130 [ 230.001277] entry_SYSCALL_64_after_hwframe+0x44/0xa9 [ 230.002639] RIP: 0033:0x7f5461bdd177 [ 230.016402] Modules linked in: i6300esb [ 230.050261] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b Fix the crash by reverting 44ea39420fc9 so unregister_reboot_notifier() is called when watchdog device is removed. This also makes handling of the reboot notifier unified with the handling of the restart handler, which is freed with unregister_restart_handler() in the same place. Fixes: 44ea39420fc9 ("drivers/watchdog: make use of devm_register_reboot_notifier()") Cc: stable@vger.kernel.org # v4.15+ Signed-off-by: Vladis Dronov <vdronov@redhat.com> Reviewed-by: Guenter Roeck <linux@roeck-us.net> Link: https://lore.kernel.org/r/20200108125347.6067-1-vdronov@redhat.com Signed-off-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Wim Van Sebroeck <wim@linux-watchdog.org>
Showing 2 changed files with 36 additions and 35 deletions Inline Diff
drivers/watchdog/watchdog_core.c
1 | // SPDX-License-Identifier: GPL-2.0+ | 1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | 2 | /* |
3 | * watchdog_core.c | 3 | * watchdog_core.c |
4 | * | 4 | * |
5 | * (c) Copyright 2008-2011 Alan Cox <alan@lxorguk.ukuu.org.uk>, | 5 | * (c) Copyright 2008-2011 Alan Cox <alan@lxorguk.ukuu.org.uk>, |
6 | * All Rights Reserved. | 6 | * All Rights Reserved. |
7 | * | 7 | * |
8 | * (c) Copyright 2008-2011 Wim Van Sebroeck <wim@iguana.be>. | 8 | * (c) Copyright 2008-2011 Wim Van Sebroeck <wim@iguana.be>. |
9 | * | 9 | * |
10 | * This source code is part of the generic code that can be used | 10 | * This source code is part of the generic code that can be used |
11 | * by all the watchdog timer drivers. | 11 | * by all the watchdog timer drivers. |
12 | * | 12 | * |
13 | * Based on source code of the following authors: | 13 | * Based on source code of the following authors: |
14 | * Matt Domsch <Matt_Domsch@dell.com>, | 14 | * Matt Domsch <Matt_Domsch@dell.com>, |
15 | * Rob Radez <rob@osinvestor.com>, | 15 | * Rob Radez <rob@osinvestor.com>, |
16 | * Rusty Lynch <rusty@linux.co.intel.com> | 16 | * Rusty Lynch <rusty@linux.co.intel.com> |
17 | * Satyam Sharma <satyam@infradead.org> | 17 | * Satyam Sharma <satyam@infradead.org> |
18 | * Randy Dunlap <randy.dunlap@oracle.com> | 18 | * Randy Dunlap <randy.dunlap@oracle.com> |
19 | * | 19 | * |
20 | * Neither Alan Cox, CymruNet Ltd., Wim Van Sebroeck nor Iguana vzw. | 20 | * Neither Alan Cox, CymruNet Ltd., Wim Van Sebroeck nor Iguana vzw. |
21 | * admit liability nor provide warranty for any of this software. | 21 | * admit liability nor provide warranty for any of this software. |
22 | * This material is provided "AS-IS" and at no charge. | 22 | * This material is provided "AS-IS" and at no charge. |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 25 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
26 | 26 | ||
27 | #include <linux/module.h> /* For EXPORT_SYMBOL/module stuff/... */ | 27 | #include <linux/module.h> /* For EXPORT_SYMBOL/module stuff/... */ |
28 | #include <linux/types.h> /* For standard types */ | 28 | #include <linux/types.h> /* For standard types */ |
29 | #include <linux/errno.h> /* For the -ENODEV/... values */ | 29 | #include <linux/errno.h> /* For the -ENODEV/... values */ |
30 | #include <linux/kernel.h> /* For printk/panic/... */ | 30 | #include <linux/kernel.h> /* For printk/panic/... */ |
31 | #include <linux/reboot.h> /* For restart handler */ | 31 | #include <linux/reboot.h> /* For restart handler */ |
32 | #include <linux/watchdog.h> /* For watchdog specific items */ | 32 | #include <linux/watchdog.h> /* For watchdog specific items */ |
33 | #include <linux/init.h> /* For __init/__exit/... */ | 33 | #include <linux/init.h> /* For __init/__exit/... */ |
34 | #include <linux/idr.h> /* For ida_* macros */ | 34 | #include <linux/idr.h> /* For ida_* macros */ |
35 | #include <linux/err.h> /* For IS_ERR macros */ | 35 | #include <linux/err.h> /* For IS_ERR macros */ |
36 | #include <linux/of.h> /* For of_get_timeout_sec */ | 36 | #include <linux/of.h> /* For of_get_timeout_sec */ |
37 | 37 | ||
38 | #include "watchdog_core.h" /* For watchdog_dev_register/... */ | 38 | #include "watchdog_core.h" /* For watchdog_dev_register/... */ |
39 | 39 | ||
40 | static DEFINE_IDA(watchdog_ida); | 40 | static DEFINE_IDA(watchdog_ida); |
41 | 41 | ||
42 | /* | 42 | /* |
43 | * Deferred Registration infrastructure. | 43 | * Deferred Registration infrastructure. |
44 | * | 44 | * |
45 | * Sometimes watchdog drivers needs to be loaded as soon as possible, | 45 | * Sometimes watchdog drivers needs to be loaded as soon as possible, |
46 | * for example when it's impossible to disable it. To do so, | 46 | * for example when it's impossible to disable it. To do so, |
47 | * raising the initcall level of the watchdog driver is a solution. | 47 | * raising the initcall level of the watchdog driver is a solution. |
48 | * But in such case, the miscdev is maybe not ready (subsys_initcall), and | 48 | * But in such case, the miscdev is maybe not ready (subsys_initcall), and |
49 | * watchdog_core need miscdev to register the watchdog as a char device. | 49 | * watchdog_core need miscdev to register the watchdog as a char device. |
50 | * | 50 | * |
51 | * The deferred registration infrastructure offer a way for the watchdog | 51 | * The deferred registration infrastructure offer a way for the watchdog |
52 | * subsystem to register a watchdog properly, even before miscdev is ready. | 52 | * subsystem to register a watchdog properly, even before miscdev is ready. |
53 | */ | 53 | */ |
54 | 54 | ||
55 | static DEFINE_MUTEX(wtd_deferred_reg_mutex); | 55 | static DEFINE_MUTEX(wtd_deferred_reg_mutex); |
56 | static LIST_HEAD(wtd_deferred_reg_list); | 56 | static LIST_HEAD(wtd_deferred_reg_list); |
57 | static bool wtd_deferred_reg_done; | 57 | static bool wtd_deferred_reg_done; |
58 | 58 | ||
59 | static void watchdog_deferred_registration_add(struct watchdog_device *wdd) | 59 | static void watchdog_deferred_registration_add(struct watchdog_device *wdd) |
60 | { | 60 | { |
61 | list_add_tail(&wdd->deferred, | 61 | list_add_tail(&wdd->deferred, |
62 | &wtd_deferred_reg_list); | 62 | &wtd_deferred_reg_list); |
63 | } | 63 | } |
64 | 64 | ||
65 | static void watchdog_deferred_registration_del(struct watchdog_device *wdd) | 65 | static void watchdog_deferred_registration_del(struct watchdog_device *wdd) |
66 | { | 66 | { |
67 | struct list_head *p, *n; | 67 | struct list_head *p, *n; |
68 | struct watchdog_device *wdd_tmp; | 68 | struct watchdog_device *wdd_tmp; |
69 | 69 | ||
70 | list_for_each_safe(p, n, &wtd_deferred_reg_list) { | 70 | list_for_each_safe(p, n, &wtd_deferred_reg_list) { |
71 | wdd_tmp = list_entry(p, struct watchdog_device, | 71 | wdd_tmp = list_entry(p, struct watchdog_device, |
72 | deferred); | 72 | deferred); |
73 | if (wdd_tmp == wdd) { | 73 | if (wdd_tmp == wdd) { |
74 | list_del(&wdd_tmp->deferred); | 74 | list_del(&wdd_tmp->deferred); |
75 | break; | 75 | break; |
76 | } | 76 | } |
77 | } | 77 | } |
78 | } | 78 | } |
79 | 79 | ||
80 | static void watchdog_check_min_max_timeout(struct watchdog_device *wdd) | 80 | static void watchdog_check_min_max_timeout(struct watchdog_device *wdd) |
81 | { | 81 | { |
82 | /* | 82 | /* |
83 | * Check that we have valid min and max timeout values, if | 83 | * Check that we have valid min and max timeout values, if |
84 | * not reset them both to 0 (=not used or unknown) | 84 | * not reset them both to 0 (=not used or unknown) |
85 | */ | 85 | */ |
86 | if (!wdd->max_hw_heartbeat_ms && wdd->min_timeout > wdd->max_timeout) { | 86 | if (!wdd->max_hw_heartbeat_ms && wdd->min_timeout > wdd->max_timeout) { |
87 | pr_info("Invalid min and max timeout values, resetting to 0!\n"); | 87 | pr_info("Invalid min and max timeout values, resetting to 0!\n"); |
88 | wdd->min_timeout = 0; | 88 | wdd->min_timeout = 0; |
89 | wdd->max_timeout = 0; | 89 | wdd->max_timeout = 0; |
90 | } | 90 | } |
91 | } | 91 | } |
92 | 92 | ||
93 | /** | 93 | /** |
94 | * watchdog_init_timeout() - initialize the timeout field | 94 | * watchdog_init_timeout() - initialize the timeout field |
95 | * @wdd: watchdog device | 95 | * @wdd: watchdog device |
96 | * @timeout_parm: timeout module parameter | 96 | * @timeout_parm: timeout module parameter |
97 | * @dev: Device that stores the timeout-sec property | 97 | * @dev: Device that stores the timeout-sec property |
98 | * | 98 | * |
99 | * Initialize the timeout field of the watchdog_device struct with either the | 99 | * Initialize the timeout field of the watchdog_device struct with either the |
100 | * timeout module parameter (if it is valid value) or the timeout-sec property | 100 | * timeout module parameter (if it is valid value) or the timeout-sec property |
101 | * (only if it is a valid value and the timeout_parm is out of bounds). | 101 | * (only if it is a valid value and the timeout_parm is out of bounds). |
102 | * If none of them are valid then we keep the old value (which should normally | 102 | * If none of them are valid then we keep the old value (which should normally |
103 | * be the default timeout value). Note that for the module parameter, '0' means | 103 | * be the default timeout value). Note that for the module parameter, '0' means |
104 | * 'use default' while it is an invalid value for the timeout-sec property. | 104 | * 'use default' while it is an invalid value for the timeout-sec property. |
105 | * It should simply be dropped if you want to use the default value then. | 105 | * It should simply be dropped if you want to use the default value then. |
106 | * | 106 | * |
107 | * A zero is returned on success or -EINVAL if all provided values are out of | 107 | * A zero is returned on success or -EINVAL if all provided values are out of |
108 | * bounds. | 108 | * bounds. |
109 | */ | 109 | */ |
110 | int watchdog_init_timeout(struct watchdog_device *wdd, | 110 | int watchdog_init_timeout(struct watchdog_device *wdd, |
111 | unsigned int timeout_parm, struct device *dev) | 111 | unsigned int timeout_parm, struct device *dev) |
112 | { | 112 | { |
113 | const char *dev_str = wdd->parent ? dev_name(wdd->parent) : | 113 | const char *dev_str = wdd->parent ? dev_name(wdd->parent) : |
114 | (const char *)wdd->info->identity; | 114 | (const char *)wdd->info->identity; |
115 | unsigned int t = 0; | 115 | unsigned int t = 0; |
116 | int ret = 0; | 116 | int ret = 0; |
117 | 117 | ||
118 | watchdog_check_min_max_timeout(wdd); | 118 | watchdog_check_min_max_timeout(wdd); |
119 | 119 | ||
120 | /* check the driver supplied value (likely a module parameter) first */ | 120 | /* check the driver supplied value (likely a module parameter) first */ |
121 | if (timeout_parm) { | 121 | if (timeout_parm) { |
122 | if (!watchdog_timeout_invalid(wdd, timeout_parm)) { | 122 | if (!watchdog_timeout_invalid(wdd, timeout_parm)) { |
123 | wdd->timeout = timeout_parm; | 123 | wdd->timeout = timeout_parm; |
124 | return 0; | 124 | return 0; |
125 | } | 125 | } |
126 | pr_err("%s: driver supplied timeout (%u) out of range\n", | 126 | pr_err("%s: driver supplied timeout (%u) out of range\n", |
127 | dev_str, timeout_parm); | 127 | dev_str, timeout_parm); |
128 | ret = -EINVAL; | 128 | ret = -EINVAL; |
129 | } | 129 | } |
130 | 130 | ||
131 | /* try to get the timeout_sec property */ | 131 | /* try to get the timeout_sec property */ |
132 | if (dev && dev->of_node && | 132 | if (dev && dev->of_node && |
133 | of_property_read_u32(dev->of_node, "timeout-sec", &t) == 0) { | 133 | of_property_read_u32(dev->of_node, "timeout-sec", &t) == 0) { |
134 | if (t && !watchdog_timeout_invalid(wdd, t)) { | 134 | if (t && !watchdog_timeout_invalid(wdd, t)) { |
135 | wdd->timeout = t; | 135 | wdd->timeout = t; |
136 | return 0; | 136 | return 0; |
137 | } | 137 | } |
138 | pr_err("%s: DT supplied timeout (%u) out of range\n", dev_str, t); | 138 | pr_err("%s: DT supplied timeout (%u) out of range\n", dev_str, t); |
139 | ret = -EINVAL; | 139 | ret = -EINVAL; |
140 | } | 140 | } |
141 | 141 | ||
142 | if (ret < 0 && wdd->timeout) | 142 | if (ret < 0 && wdd->timeout) |
143 | pr_warn("%s: falling back to default timeout (%u)\n", dev_str, | 143 | pr_warn("%s: falling back to default timeout (%u)\n", dev_str, |
144 | wdd->timeout); | 144 | wdd->timeout); |
145 | 145 | ||
146 | return ret; | 146 | return ret; |
147 | } | 147 | } |
148 | EXPORT_SYMBOL_GPL(watchdog_init_timeout); | 148 | EXPORT_SYMBOL_GPL(watchdog_init_timeout); |
149 | 149 | ||
150 | static int watchdog_reboot_notifier(struct notifier_block *nb, | ||
151 | unsigned long code, void *data) | ||
152 | { | ||
153 | struct watchdog_device *wdd; | ||
154 | |||
155 | wdd = container_of(nb, struct watchdog_device, reboot_nb); | ||
156 | if (code == SYS_DOWN || code == SYS_HALT) { | ||
157 | if (watchdog_active(wdd)) { | ||
158 | int ret; | ||
159 | |||
160 | ret = wdd->ops->stop(wdd); | ||
161 | if (ret) | ||
162 | return NOTIFY_BAD; | ||
163 | } | ||
164 | } | ||
165 | |||
166 | return NOTIFY_DONE; | ||
167 | } | ||
168 | |||
150 | static int watchdog_restart_notifier(struct notifier_block *nb, | 169 | static int watchdog_restart_notifier(struct notifier_block *nb, |
151 | unsigned long action, void *data) | 170 | unsigned long action, void *data) |
152 | { | 171 | { |
153 | struct watchdog_device *wdd = container_of(nb, struct watchdog_device, | 172 | struct watchdog_device *wdd = container_of(nb, struct watchdog_device, |
154 | restart_nb); | 173 | restart_nb); |
155 | 174 | ||
156 | int ret; | 175 | int ret; |
157 | 176 | ||
158 | ret = wdd->ops->restart(wdd, action, data); | 177 | ret = wdd->ops->restart(wdd, action, data); |
159 | if (ret) | 178 | if (ret) |
160 | return NOTIFY_BAD; | 179 | return NOTIFY_BAD; |
161 | 180 | ||
162 | return NOTIFY_DONE; | 181 | return NOTIFY_DONE; |
163 | } | 182 | } |
164 | 183 | ||
165 | /** | 184 | /** |
166 | * watchdog_set_restart_priority - Change priority of restart handler | 185 | * watchdog_set_restart_priority - Change priority of restart handler |
167 | * @wdd: watchdog device | 186 | * @wdd: watchdog device |
168 | * @priority: priority of the restart handler, should follow these guidelines: | 187 | * @priority: priority of the restart handler, should follow these guidelines: |
169 | * 0: use watchdog's restart function as last resort, has limited restart | 188 | * 0: use watchdog's restart function as last resort, has limited restart |
170 | * capabilies | 189 | * capabilies |
171 | * 128: default restart handler, use if no other handler is expected to be | 190 | * 128: default restart handler, use if no other handler is expected to be |
172 | * available and/or if restart is sufficient to restart the entire system | 191 | * available and/or if restart is sufficient to restart the entire system |
173 | * 255: preempt all other handlers | 192 | * 255: preempt all other handlers |
174 | * | 193 | * |
175 | * If a wdd->ops->restart function is provided when watchdog_register_device is | 194 | * If a wdd->ops->restart function is provided when watchdog_register_device is |
176 | * called, it will be registered as a restart handler with the priority given | 195 | * called, it will be registered as a restart handler with the priority given |
177 | * here. | 196 | * here. |
178 | */ | 197 | */ |
179 | void watchdog_set_restart_priority(struct watchdog_device *wdd, int priority) | 198 | void watchdog_set_restart_priority(struct watchdog_device *wdd, int priority) |
180 | { | 199 | { |
181 | wdd->restart_nb.priority = priority; | 200 | wdd->restart_nb.priority = priority; |
182 | } | 201 | } |
183 | EXPORT_SYMBOL_GPL(watchdog_set_restart_priority); | 202 | EXPORT_SYMBOL_GPL(watchdog_set_restart_priority); |
184 | 203 | ||
185 | static int __watchdog_register_device(struct watchdog_device *wdd) | 204 | static int __watchdog_register_device(struct watchdog_device *wdd) |
186 | { | 205 | { |
187 | int ret, id = -1; | 206 | int ret, id = -1; |
188 | 207 | ||
189 | if (wdd == NULL || wdd->info == NULL || wdd->ops == NULL) | 208 | if (wdd == NULL || wdd->info == NULL || wdd->ops == NULL) |
190 | return -EINVAL; | 209 | return -EINVAL; |
191 | 210 | ||
192 | /* Mandatory operations need to be supported */ | 211 | /* Mandatory operations need to be supported */ |
193 | if (!wdd->ops->start || (!wdd->ops->stop && !wdd->max_hw_heartbeat_ms)) | 212 | if (!wdd->ops->start || (!wdd->ops->stop && !wdd->max_hw_heartbeat_ms)) |
194 | return -EINVAL; | 213 | return -EINVAL; |
195 | 214 | ||
196 | watchdog_check_min_max_timeout(wdd); | 215 | watchdog_check_min_max_timeout(wdd); |
197 | 216 | ||
198 | /* | 217 | /* |
199 | * Note: now that all watchdog_device data has been verified, we | 218 | * Note: now that all watchdog_device data has been verified, we |
200 | * will not check this anymore in other functions. If data gets | 219 | * will not check this anymore in other functions. If data gets |
201 | * corrupted in a later stage then we expect a kernel panic! | 220 | * corrupted in a later stage then we expect a kernel panic! |
202 | */ | 221 | */ |
203 | 222 | ||
204 | /* Use alias for watchdog id if possible */ | 223 | /* Use alias for watchdog id if possible */ |
205 | if (wdd->parent) { | 224 | if (wdd->parent) { |
206 | ret = of_alias_get_id(wdd->parent->of_node, "watchdog"); | 225 | ret = of_alias_get_id(wdd->parent->of_node, "watchdog"); |
207 | if (ret >= 0) | 226 | if (ret >= 0) |
208 | id = ida_simple_get(&watchdog_ida, ret, | 227 | id = ida_simple_get(&watchdog_ida, ret, |
209 | ret + 1, GFP_KERNEL); | 228 | ret + 1, GFP_KERNEL); |
210 | } | 229 | } |
211 | 230 | ||
212 | if (id < 0) | 231 | if (id < 0) |
213 | id = ida_simple_get(&watchdog_ida, 0, MAX_DOGS, GFP_KERNEL); | 232 | id = ida_simple_get(&watchdog_ida, 0, MAX_DOGS, GFP_KERNEL); |
214 | 233 | ||
215 | if (id < 0) | 234 | if (id < 0) |
216 | return id; | 235 | return id; |
217 | wdd->id = id; | 236 | wdd->id = id; |
218 | 237 | ||
219 | ret = watchdog_dev_register(wdd); | 238 | ret = watchdog_dev_register(wdd); |
220 | if (ret) { | 239 | if (ret) { |
221 | ida_simple_remove(&watchdog_ida, id); | 240 | ida_simple_remove(&watchdog_ida, id); |
222 | if (!(id == 0 && ret == -EBUSY)) | 241 | if (!(id == 0 && ret == -EBUSY)) |
223 | return ret; | 242 | return ret; |
224 | 243 | ||
225 | /* Retry in case a legacy watchdog module exists */ | 244 | /* Retry in case a legacy watchdog module exists */ |
226 | id = ida_simple_get(&watchdog_ida, 1, MAX_DOGS, GFP_KERNEL); | 245 | id = ida_simple_get(&watchdog_ida, 1, MAX_DOGS, GFP_KERNEL); |
227 | if (id < 0) | 246 | if (id < 0) |
228 | return id; | 247 | return id; |
229 | wdd->id = id; | 248 | wdd->id = id; |
230 | 249 | ||
231 | ret = watchdog_dev_register(wdd); | 250 | ret = watchdog_dev_register(wdd); |
232 | if (ret) { | 251 | if (ret) { |
233 | ida_simple_remove(&watchdog_ida, id); | 252 | ida_simple_remove(&watchdog_ida, id); |
234 | return ret; | 253 | return ret; |
235 | } | 254 | } |
236 | } | 255 | } |
237 | 256 | ||
257 | if (test_bit(WDOG_STOP_ON_REBOOT, &wdd->status)) { | ||
258 | wdd->reboot_nb.notifier_call = watchdog_reboot_notifier; | ||
259 | |||
260 | ret = register_reboot_notifier(&wdd->reboot_nb); | ||
261 | if (ret) { | ||
262 | pr_err("watchdog%d: Cannot register reboot notifier (%d)\n", | ||
263 | wdd->id, ret); | ||
264 | watchdog_dev_unregister(wdd); | ||
265 | ida_simple_remove(&watchdog_ida, id); | ||
266 | return ret; | ||
267 | } | ||
268 | } | ||
269 | |||
238 | if (wdd->ops->restart) { | 270 | if (wdd->ops->restart) { |
239 | wdd->restart_nb.notifier_call = watchdog_restart_notifier; | 271 | wdd->restart_nb.notifier_call = watchdog_restart_notifier; |
240 | 272 | ||
241 | ret = register_restart_handler(&wdd->restart_nb); | 273 | ret = register_restart_handler(&wdd->restart_nb); |
242 | if (ret) | 274 | if (ret) |
243 | pr_warn("watchdog%d: Cannot register restart handler (%d)\n", | 275 | pr_warn("watchdog%d: Cannot register restart handler (%d)\n", |
244 | wdd->id, ret); | 276 | wdd->id, ret); |
245 | } | 277 | } |
246 | 278 | ||
247 | return 0; | 279 | return 0; |
248 | } | 280 | } |
249 | 281 | ||
250 | /** | 282 | /** |
251 | * watchdog_register_device() - register a watchdog device | 283 | * watchdog_register_device() - register a watchdog device |
252 | * @wdd: watchdog device | 284 | * @wdd: watchdog device |
253 | * | 285 | * |
254 | * Register a watchdog device with the kernel so that the | 286 | * Register a watchdog device with the kernel so that the |
255 | * watchdog timer can be accessed from userspace. | 287 | * watchdog timer can be accessed from userspace. |
256 | * | 288 | * |
257 | * A zero is returned on success and a negative errno code for | 289 | * A zero is returned on success and a negative errno code for |
258 | * failure. | 290 | * failure. |
259 | */ | 291 | */ |
260 | 292 | ||
261 | int watchdog_register_device(struct watchdog_device *wdd) | 293 | int watchdog_register_device(struct watchdog_device *wdd) |
262 | { | 294 | { |
263 | const char *dev_str; | 295 | const char *dev_str; |
264 | int ret = 0; | 296 | int ret = 0; |
265 | 297 | ||
266 | mutex_lock(&wtd_deferred_reg_mutex); | 298 | mutex_lock(&wtd_deferred_reg_mutex); |
267 | if (wtd_deferred_reg_done) | 299 | if (wtd_deferred_reg_done) |
268 | ret = __watchdog_register_device(wdd); | 300 | ret = __watchdog_register_device(wdd); |
269 | else | 301 | else |
270 | watchdog_deferred_registration_add(wdd); | 302 | watchdog_deferred_registration_add(wdd); |
271 | mutex_unlock(&wtd_deferred_reg_mutex); | 303 | mutex_unlock(&wtd_deferred_reg_mutex); |
272 | 304 | ||
273 | if (ret) { | 305 | if (ret) { |
274 | dev_str = wdd->parent ? dev_name(wdd->parent) : | 306 | dev_str = wdd->parent ? dev_name(wdd->parent) : |
275 | (const char *)wdd->info->identity; | 307 | (const char *)wdd->info->identity; |
276 | pr_err("%s: failed to register watchdog device (err = %d)\n", | 308 | pr_err("%s: failed to register watchdog device (err = %d)\n", |
277 | dev_str, ret); | 309 | dev_str, ret); |
278 | } | 310 | } |
279 | 311 | ||
280 | return ret; | 312 | return ret; |
281 | } | 313 | } |
282 | EXPORT_SYMBOL_GPL(watchdog_register_device); | 314 | EXPORT_SYMBOL_GPL(watchdog_register_device); |
283 | 315 | ||
284 | static void __watchdog_unregister_device(struct watchdog_device *wdd) | 316 | static void __watchdog_unregister_device(struct watchdog_device *wdd) |
285 | { | 317 | { |
286 | if (wdd == NULL) | 318 | if (wdd == NULL) |
287 | return; | 319 | return; |
288 | 320 | ||
289 | if (wdd->ops->restart) | 321 | if (wdd->ops->restart) |
290 | unregister_restart_handler(&wdd->restart_nb); | 322 | unregister_restart_handler(&wdd->restart_nb); |
323 | |||
324 | if (test_bit(WDOG_STOP_ON_REBOOT, &wdd->status)) | ||
325 | unregister_reboot_notifier(&wdd->reboot_nb); | ||
291 | 326 | ||
292 | watchdog_dev_unregister(wdd); | 327 | watchdog_dev_unregister(wdd); |
293 | ida_simple_remove(&watchdog_ida, wdd->id); | 328 | ida_simple_remove(&watchdog_ida, wdd->id); |
294 | } | 329 | } |
295 | 330 | ||
296 | /** | 331 | /** |
297 | * watchdog_unregister_device() - unregister a watchdog device | 332 | * watchdog_unregister_device() - unregister a watchdog device |
298 | * @wdd: watchdog device to unregister | 333 | * @wdd: watchdog device to unregister |
299 | * | 334 | * |
300 | * Unregister a watchdog device that was previously successfully | 335 | * Unregister a watchdog device that was previously successfully |
301 | * registered with watchdog_register_device(). | 336 | * registered with watchdog_register_device(). |
302 | */ | 337 | */ |
303 | 338 | ||
304 | void watchdog_unregister_device(struct watchdog_device *wdd) | 339 | void watchdog_unregister_device(struct watchdog_device *wdd) |
305 | { | 340 | { |
306 | mutex_lock(&wtd_deferred_reg_mutex); | 341 | mutex_lock(&wtd_deferred_reg_mutex); |
307 | if (wtd_deferred_reg_done) | 342 | if (wtd_deferred_reg_done) |
308 | __watchdog_unregister_device(wdd); | 343 | __watchdog_unregister_device(wdd); |
309 | else | 344 | else |
310 | watchdog_deferred_registration_del(wdd); | 345 | watchdog_deferred_registration_del(wdd); |
311 | mutex_unlock(&wtd_deferred_reg_mutex); | 346 | mutex_unlock(&wtd_deferred_reg_mutex); |
312 | } | 347 | } |
313 | 348 | ||
314 | EXPORT_SYMBOL_GPL(watchdog_unregister_device); | 349 | EXPORT_SYMBOL_GPL(watchdog_unregister_device); |
315 | 350 | ||
316 | static void devm_watchdog_unregister_device(struct device *dev, void *res) | 351 | static void devm_watchdog_unregister_device(struct device *dev, void *res) |
317 | { | 352 | { |
318 | watchdog_unregister_device(*(struct watchdog_device **)res); | 353 | watchdog_unregister_device(*(struct watchdog_device **)res); |
319 | } | 354 | } |
320 | 355 | ||
321 | /** | 356 | /** |
322 | * devm_watchdog_register_device() - resource managed watchdog_register_device() | 357 | * devm_watchdog_register_device() - resource managed watchdog_register_device() |
323 | * @dev: device that is registering this watchdog device | 358 | * @dev: device that is registering this watchdog device |
324 | * @wdd: watchdog device | 359 | * @wdd: watchdog device |
325 | * | 360 | * |
326 | * Managed watchdog_register_device(). For watchdog device registered by this | 361 | * Managed watchdog_register_device(). For watchdog device registered by this |
327 | * function, watchdog_unregister_device() is automatically called on driver | 362 | * function, watchdog_unregister_device() is automatically called on driver |
328 | * detach. See watchdog_register_device() for more information. | 363 | * detach. See watchdog_register_device() for more information. |
329 | */ | 364 | */ |
330 | int devm_watchdog_register_device(struct device *dev, | 365 | int devm_watchdog_register_device(struct device *dev, |
331 | struct watchdog_device *wdd) | 366 | struct watchdog_device *wdd) |
332 | { | 367 | { |
333 | struct watchdog_device **rcwdd; | 368 | struct watchdog_device **rcwdd; |
334 | int ret; | 369 | int ret; |
335 | 370 | ||
336 | rcwdd = devres_alloc(devm_watchdog_unregister_device, sizeof(*rcwdd), | 371 | rcwdd = devres_alloc(devm_watchdog_unregister_device, sizeof(*rcwdd), |
337 | GFP_KERNEL); | 372 | GFP_KERNEL); |
338 | if (!rcwdd) | 373 | if (!rcwdd) |
339 | return -ENOMEM; | 374 | return -ENOMEM; |
340 | 375 | ||
341 | ret = watchdog_register_device(wdd); | 376 | ret = watchdog_register_device(wdd); |
342 | if (!ret) { | 377 | if (!ret) { |
343 | *rcwdd = wdd; | 378 | *rcwdd = wdd; |
344 | devres_add(dev, rcwdd); | 379 | devres_add(dev, rcwdd); |
345 | } else { | 380 | } else { |
346 | devres_free(rcwdd); | 381 | devres_free(rcwdd); |
347 | } | 382 | } |
348 | 383 | ||
349 | return ret; | 384 | return ret; |
350 | } | 385 | } |
351 | EXPORT_SYMBOL_GPL(devm_watchdog_register_device); | 386 | EXPORT_SYMBOL_GPL(devm_watchdog_register_device); |
352 | 387 | ||
353 | static int __init watchdog_deferred_registration(void) | 388 | static int __init watchdog_deferred_registration(void) |
354 | { | 389 | { |
355 | mutex_lock(&wtd_deferred_reg_mutex); | 390 | mutex_lock(&wtd_deferred_reg_mutex); |
356 | wtd_deferred_reg_done = true; | 391 | wtd_deferred_reg_done = true; |
357 | while (!list_empty(&wtd_deferred_reg_list)) { | 392 | while (!list_empty(&wtd_deferred_reg_list)) { |
358 | struct watchdog_device *wdd; | 393 | struct watchdog_device *wdd; |
359 | 394 | ||
360 | wdd = list_first_entry(&wtd_deferred_reg_list, | 395 | wdd = list_first_entry(&wtd_deferred_reg_list, |
361 | struct watchdog_device, deferred); | 396 | struct watchdog_device, deferred); |
362 | list_del(&wdd->deferred); | 397 | list_del(&wdd->deferred); |
363 | __watchdog_register_device(wdd); | 398 | __watchdog_register_device(wdd); |
364 | } | 399 | } |
365 | mutex_unlock(&wtd_deferred_reg_mutex); | 400 | mutex_unlock(&wtd_deferred_reg_mutex); |
366 | return 0; | 401 | return 0; |
367 | } | 402 | } |
368 | 403 | ||
369 | static int __init watchdog_init(void) | 404 | static int __init watchdog_init(void) |
370 | { | 405 | { |
371 | int err; | 406 | int err; |
372 | 407 | ||
373 | err = watchdog_dev_init(); | 408 | err = watchdog_dev_init(); |
374 | if (err < 0) | 409 | if (err < 0) |
375 | return err; | 410 | return err; |
376 | 411 | ||
377 | watchdog_deferred_registration(); | 412 | watchdog_deferred_registration(); |
378 | return 0; | 413 | return 0; |
379 | } | 414 | } |
380 | 415 | ||
381 | static void __exit watchdog_exit(void) | 416 | static void __exit watchdog_exit(void) |
382 | { | 417 | { |
383 | watchdog_dev_exit(); | 418 | watchdog_dev_exit(); |
384 | ida_destroy(&watchdog_ida); | 419 | ida_destroy(&watchdog_ida); |
385 | } | 420 | } |
386 | 421 | ||
387 | subsys_initcall_sync(watchdog_init); | 422 | subsys_initcall_sync(watchdog_init); |
388 | module_exit(watchdog_exit); | 423 | module_exit(watchdog_exit); |
389 | 424 | ||
390 | MODULE_AUTHOR("Alan Cox <alan@lxorguk.ukuu.org.uk>"); | 425 | MODULE_AUTHOR("Alan Cox <alan@lxorguk.ukuu.org.uk>"); |
391 | MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>"); | 426 | MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>"); |
392 | MODULE_DESCRIPTION("WatchDog Timer Driver Core"); | 427 | MODULE_DESCRIPTION("WatchDog Timer Driver Core"); |
393 | MODULE_LICENSE("GPL"); | 428 | MODULE_LICENSE("GPL"); |
394 | 429 |
drivers/watchdog/watchdog_dev.c
1 | // SPDX-License-Identifier: GPL-2.0+ | 1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | 2 | /* |
3 | * watchdog_dev.c | 3 | * watchdog_dev.c |
4 | * | 4 | * |
5 | * (c) Copyright 2008-2011 Alan Cox <alan@lxorguk.ukuu.org.uk>, | 5 | * (c) Copyright 2008-2011 Alan Cox <alan@lxorguk.ukuu.org.uk>, |
6 | * All Rights Reserved. | 6 | * All Rights Reserved. |
7 | * | 7 | * |
8 | * (c) Copyright 2008-2011 Wim Van Sebroeck <wim@iguana.be>. | 8 | * (c) Copyright 2008-2011 Wim Van Sebroeck <wim@iguana.be>. |
9 | * | 9 | * |
10 | * | 10 | * |
11 | * This source code is part of the generic code that can be used | 11 | * This source code is part of the generic code that can be used |
12 | * by all the watchdog timer drivers. | 12 | * by all the watchdog timer drivers. |
13 | * | 13 | * |
14 | * This part of the generic code takes care of the following | 14 | * This part of the generic code takes care of the following |
15 | * misc device: /dev/watchdog. | 15 | * misc device: /dev/watchdog. |
16 | * | 16 | * |
17 | * Based on source code of the following authors: | 17 | * Based on source code of the following authors: |
18 | * Matt Domsch <Matt_Domsch@dell.com>, | 18 | * Matt Domsch <Matt_Domsch@dell.com>, |
19 | * Rob Radez <rob@osinvestor.com>, | 19 | * Rob Radez <rob@osinvestor.com>, |
20 | * Rusty Lynch <rusty@linux.co.intel.com> | 20 | * Rusty Lynch <rusty@linux.co.intel.com> |
21 | * Satyam Sharma <satyam@infradead.org> | 21 | * Satyam Sharma <satyam@infradead.org> |
22 | * Randy Dunlap <randy.dunlap@oracle.com> | 22 | * Randy Dunlap <randy.dunlap@oracle.com> |
23 | * | 23 | * |
24 | * Neither Alan Cox, CymruNet Ltd., Wim Van Sebroeck nor Iguana vzw. | 24 | * Neither Alan Cox, CymruNet Ltd., Wim Van Sebroeck nor Iguana vzw. |
25 | * admit liability nor provide warranty for any of this software. | 25 | * admit liability nor provide warranty for any of this software. |
26 | * This material is provided "AS-IS" and at no charge. | 26 | * This material is provided "AS-IS" and at no charge. |
27 | */ | 27 | */ |
28 | 28 | ||
29 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 29 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
30 | 30 | ||
31 | #include <linux/cdev.h> /* For character device */ | 31 | #include <linux/cdev.h> /* For character device */ |
32 | #include <linux/errno.h> /* For the -ENODEV/... values */ | 32 | #include <linux/errno.h> /* For the -ENODEV/... values */ |
33 | #include <linux/fs.h> /* For file operations */ | 33 | #include <linux/fs.h> /* For file operations */ |
34 | #include <linux/init.h> /* For __init/__exit/... */ | 34 | #include <linux/init.h> /* For __init/__exit/... */ |
35 | #include <linux/hrtimer.h> /* For hrtimers */ | 35 | #include <linux/hrtimer.h> /* For hrtimers */ |
36 | #include <linux/kernel.h> /* For printk/panic/... */ | 36 | #include <linux/kernel.h> /* For printk/panic/... */ |
37 | #include <linux/kthread.h> /* For kthread_work */ | 37 | #include <linux/kthread.h> /* For kthread_work */ |
38 | #include <linux/miscdevice.h> /* For handling misc devices */ | 38 | #include <linux/miscdevice.h> /* For handling misc devices */ |
39 | #include <linux/module.h> /* For module stuff/... */ | 39 | #include <linux/module.h> /* For module stuff/... */ |
40 | #include <linux/mutex.h> /* For mutexes */ | 40 | #include <linux/mutex.h> /* For mutexes */ |
41 | #include <linux/reboot.h> /* For reboot notifier */ | ||
42 | #include <linux/slab.h> /* For memory functions */ | 41 | #include <linux/slab.h> /* For memory functions */ |
43 | #include <linux/types.h> /* For standard types (like size_t) */ | 42 | #include <linux/types.h> /* For standard types (like size_t) */ |
44 | #include <linux/watchdog.h> /* For watchdog specific items */ | 43 | #include <linux/watchdog.h> /* For watchdog specific items */ |
45 | #include <linux/uaccess.h> /* For copy_to_user/put_user/... */ | 44 | #include <linux/uaccess.h> /* For copy_to_user/put_user/... */ |
46 | 45 | ||
47 | #include <uapi/linux/sched/types.h> /* For struct sched_param */ | 46 | #include <uapi/linux/sched/types.h> /* For struct sched_param */ |
48 | 47 | ||
49 | #include "watchdog_core.h" | 48 | #include "watchdog_core.h" |
50 | #include "watchdog_pretimeout.h" | 49 | #include "watchdog_pretimeout.h" |
51 | 50 | ||
52 | /* | 51 | /* |
53 | * struct watchdog_core_data - watchdog core internal data | 52 | * struct watchdog_core_data - watchdog core internal data |
54 | * @dev: The watchdog's internal device | 53 | * @dev: The watchdog's internal device |
55 | * @cdev: The watchdog's Character device. | 54 | * @cdev: The watchdog's Character device. |
56 | * @wdd: Pointer to watchdog device. | 55 | * @wdd: Pointer to watchdog device. |
57 | * @lock: Lock for watchdog core. | 56 | * @lock: Lock for watchdog core. |
58 | * @status: Watchdog core internal status bits. | 57 | * @status: Watchdog core internal status bits. |
59 | */ | 58 | */ |
60 | struct watchdog_core_data { | 59 | struct watchdog_core_data { |
61 | struct device dev; | 60 | struct device dev; |
62 | struct cdev cdev; | 61 | struct cdev cdev; |
63 | struct watchdog_device *wdd; | 62 | struct watchdog_device *wdd; |
64 | struct mutex lock; | 63 | struct mutex lock; |
65 | ktime_t last_keepalive; | 64 | ktime_t last_keepalive; |
66 | ktime_t last_hw_keepalive; | 65 | ktime_t last_hw_keepalive; |
67 | ktime_t open_deadline; | 66 | ktime_t open_deadline; |
68 | struct hrtimer timer; | 67 | struct hrtimer timer; |
69 | struct kthread_work work; | 68 | struct kthread_work work; |
70 | unsigned long status; /* Internal status bits */ | 69 | unsigned long status; /* Internal status bits */ |
71 | #define _WDOG_DEV_OPEN 0 /* Opened ? */ | 70 | #define _WDOG_DEV_OPEN 0 /* Opened ? */ |
72 | #define _WDOG_ALLOW_RELEASE 1 /* Did we receive the magic char ? */ | 71 | #define _WDOG_ALLOW_RELEASE 1 /* Did we receive the magic char ? */ |
73 | #define _WDOG_KEEPALIVE 2 /* Did we receive a keepalive ? */ | 72 | #define _WDOG_KEEPALIVE 2 /* Did we receive a keepalive ? */ |
74 | }; | 73 | }; |
75 | 74 | ||
76 | /* the dev_t structure to store the dynamically allocated watchdog devices */ | 75 | /* the dev_t structure to store the dynamically allocated watchdog devices */ |
77 | static dev_t watchdog_devt; | 76 | static dev_t watchdog_devt; |
78 | /* Reference to watchdog device behind /dev/watchdog */ | 77 | /* Reference to watchdog device behind /dev/watchdog */ |
79 | static struct watchdog_core_data *old_wd_data; | 78 | static struct watchdog_core_data *old_wd_data; |
80 | 79 | ||
81 | static struct kthread_worker *watchdog_kworker; | 80 | static struct kthread_worker *watchdog_kworker; |
82 | 81 | ||
83 | static bool handle_boot_enabled = | 82 | static bool handle_boot_enabled = |
84 | IS_ENABLED(CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED); | 83 | IS_ENABLED(CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED); |
85 | 84 | ||
86 | static unsigned open_timeout = CONFIG_WATCHDOG_OPEN_TIMEOUT; | 85 | static unsigned open_timeout = CONFIG_WATCHDOG_OPEN_TIMEOUT; |
87 | 86 | ||
88 | static bool watchdog_past_open_deadline(struct watchdog_core_data *data) | 87 | static bool watchdog_past_open_deadline(struct watchdog_core_data *data) |
89 | { | 88 | { |
90 | return ktime_after(ktime_get(), data->open_deadline); | 89 | return ktime_after(ktime_get(), data->open_deadline); |
91 | } | 90 | } |
92 | 91 | ||
93 | static void watchdog_set_open_deadline(struct watchdog_core_data *data) | 92 | static void watchdog_set_open_deadline(struct watchdog_core_data *data) |
94 | { | 93 | { |
95 | data->open_deadline = open_timeout ? | 94 | data->open_deadline = open_timeout ? |
96 | ktime_get() + ktime_set(open_timeout, 0) : KTIME_MAX; | 95 | ktime_get() + ktime_set(open_timeout, 0) : KTIME_MAX; |
97 | } | 96 | } |
98 | 97 | ||
99 | static inline bool watchdog_need_worker(struct watchdog_device *wdd) | 98 | static inline bool watchdog_need_worker(struct watchdog_device *wdd) |
100 | { | 99 | { |
101 | /* All variables in milli-seconds */ | 100 | /* All variables in milli-seconds */ |
102 | unsigned int hm = wdd->max_hw_heartbeat_ms; | 101 | unsigned int hm = wdd->max_hw_heartbeat_ms; |
103 | unsigned int t = wdd->timeout * 1000; | 102 | unsigned int t = wdd->timeout * 1000; |
104 | 103 | ||
105 | /* | 104 | /* |
106 | * A worker to generate heartbeat requests is needed if all of the | 105 | * A worker to generate heartbeat requests is needed if all of the |
107 | * following conditions are true. | 106 | * following conditions are true. |
108 | * - Userspace activated the watchdog. | 107 | * - Userspace activated the watchdog. |
109 | * - The driver provided a value for the maximum hardware timeout, and | 108 | * - The driver provided a value for the maximum hardware timeout, and |
110 | * thus is aware that the framework supports generating heartbeat | 109 | * thus is aware that the framework supports generating heartbeat |
111 | * requests. | 110 | * requests. |
112 | * - Userspace requests a longer timeout than the hardware can handle. | 111 | * - Userspace requests a longer timeout than the hardware can handle. |
113 | * | 112 | * |
114 | * Alternatively, if userspace has not opened the watchdog | 113 | * Alternatively, if userspace has not opened the watchdog |
115 | * device, we take care of feeding the watchdog if it is | 114 | * device, we take care of feeding the watchdog if it is |
116 | * running. | 115 | * running. |
117 | */ | 116 | */ |
118 | return (hm && watchdog_active(wdd) && t > hm) || | 117 | return (hm && watchdog_active(wdd) && t > hm) || |
119 | (t && !watchdog_active(wdd) && watchdog_hw_running(wdd)); | 118 | (t && !watchdog_active(wdd) && watchdog_hw_running(wdd)); |
120 | } | 119 | } |
121 | 120 | ||
122 | static ktime_t watchdog_next_keepalive(struct watchdog_device *wdd) | 121 | static ktime_t watchdog_next_keepalive(struct watchdog_device *wdd) |
123 | { | 122 | { |
124 | struct watchdog_core_data *wd_data = wdd->wd_data; | 123 | struct watchdog_core_data *wd_data = wdd->wd_data; |
125 | unsigned int timeout_ms = wdd->timeout * 1000; | 124 | unsigned int timeout_ms = wdd->timeout * 1000; |
126 | ktime_t keepalive_interval; | 125 | ktime_t keepalive_interval; |
127 | ktime_t last_heartbeat, latest_heartbeat; | 126 | ktime_t last_heartbeat, latest_heartbeat; |
128 | ktime_t virt_timeout; | 127 | ktime_t virt_timeout; |
129 | unsigned int hw_heartbeat_ms; | 128 | unsigned int hw_heartbeat_ms; |
130 | 129 | ||
131 | if (watchdog_active(wdd)) | 130 | if (watchdog_active(wdd)) |
132 | virt_timeout = ktime_add(wd_data->last_keepalive, | 131 | virt_timeout = ktime_add(wd_data->last_keepalive, |
133 | ms_to_ktime(timeout_ms)); | 132 | ms_to_ktime(timeout_ms)); |
134 | else | 133 | else |
135 | virt_timeout = wd_data->open_deadline; | 134 | virt_timeout = wd_data->open_deadline; |
136 | 135 | ||
137 | hw_heartbeat_ms = min_not_zero(timeout_ms, wdd->max_hw_heartbeat_ms); | 136 | hw_heartbeat_ms = min_not_zero(timeout_ms, wdd->max_hw_heartbeat_ms); |
138 | keepalive_interval = ms_to_ktime(hw_heartbeat_ms / 2); | 137 | keepalive_interval = ms_to_ktime(hw_heartbeat_ms / 2); |
139 | 138 | ||
140 | /* | 139 | /* |
141 | * To ensure that the watchdog times out wdd->timeout seconds | 140 | * To ensure that the watchdog times out wdd->timeout seconds |
142 | * after the most recent ping from userspace, the last | 141 | * after the most recent ping from userspace, the last |
143 | * worker ping has to come in hw_heartbeat_ms before this timeout. | 142 | * worker ping has to come in hw_heartbeat_ms before this timeout. |
144 | */ | 143 | */ |
145 | last_heartbeat = ktime_sub(virt_timeout, ms_to_ktime(hw_heartbeat_ms)); | 144 | last_heartbeat = ktime_sub(virt_timeout, ms_to_ktime(hw_heartbeat_ms)); |
146 | latest_heartbeat = ktime_sub(last_heartbeat, ktime_get()); | 145 | latest_heartbeat = ktime_sub(last_heartbeat, ktime_get()); |
147 | if (ktime_before(latest_heartbeat, keepalive_interval)) | 146 | if (ktime_before(latest_heartbeat, keepalive_interval)) |
148 | return latest_heartbeat; | 147 | return latest_heartbeat; |
149 | return keepalive_interval; | 148 | return keepalive_interval; |
150 | } | 149 | } |
151 | 150 | ||
152 | static inline void watchdog_update_worker(struct watchdog_device *wdd) | 151 | static inline void watchdog_update_worker(struct watchdog_device *wdd) |
153 | { | 152 | { |
154 | struct watchdog_core_data *wd_data = wdd->wd_data; | 153 | struct watchdog_core_data *wd_data = wdd->wd_data; |
155 | 154 | ||
156 | if (watchdog_need_worker(wdd)) { | 155 | if (watchdog_need_worker(wdd)) { |
157 | ktime_t t = watchdog_next_keepalive(wdd); | 156 | ktime_t t = watchdog_next_keepalive(wdd); |
158 | 157 | ||
159 | if (t > 0) | 158 | if (t > 0) |
160 | hrtimer_start(&wd_data->timer, t, | 159 | hrtimer_start(&wd_data->timer, t, |
161 | HRTIMER_MODE_REL_HARD); | 160 | HRTIMER_MODE_REL_HARD); |
162 | } else { | 161 | } else { |
163 | hrtimer_cancel(&wd_data->timer); | 162 | hrtimer_cancel(&wd_data->timer); |
164 | } | 163 | } |
165 | } | 164 | } |
166 | 165 | ||
167 | static int __watchdog_ping(struct watchdog_device *wdd) | 166 | static int __watchdog_ping(struct watchdog_device *wdd) |
168 | { | 167 | { |
169 | struct watchdog_core_data *wd_data = wdd->wd_data; | 168 | struct watchdog_core_data *wd_data = wdd->wd_data; |
170 | ktime_t earliest_keepalive, now; | 169 | ktime_t earliest_keepalive, now; |
171 | int err; | 170 | int err; |
172 | 171 | ||
173 | earliest_keepalive = ktime_add(wd_data->last_hw_keepalive, | 172 | earliest_keepalive = ktime_add(wd_data->last_hw_keepalive, |
174 | ms_to_ktime(wdd->min_hw_heartbeat_ms)); | 173 | ms_to_ktime(wdd->min_hw_heartbeat_ms)); |
175 | now = ktime_get(); | 174 | now = ktime_get(); |
176 | 175 | ||
177 | if (ktime_after(earliest_keepalive, now)) { | 176 | if (ktime_after(earliest_keepalive, now)) { |
178 | hrtimer_start(&wd_data->timer, | 177 | hrtimer_start(&wd_data->timer, |
179 | ktime_sub(earliest_keepalive, now), | 178 | ktime_sub(earliest_keepalive, now), |
180 | HRTIMER_MODE_REL_HARD); | 179 | HRTIMER_MODE_REL_HARD); |
181 | return 0; | 180 | return 0; |
182 | } | 181 | } |
183 | 182 | ||
184 | wd_data->last_hw_keepalive = now; | 183 | wd_data->last_hw_keepalive = now; |
185 | 184 | ||
186 | if (wdd->ops->ping) | 185 | if (wdd->ops->ping) |
187 | err = wdd->ops->ping(wdd); /* ping the watchdog */ | 186 | err = wdd->ops->ping(wdd); /* ping the watchdog */ |
188 | else | 187 | else |
189 | err = wdd->ops->start(wdd); /* restart watchdog */ | 188 | err = wdd->ops->start(wdd); /* restart watchdog */ |
190 | 189 | ||
191 | watchdog_update_worker(wdd); | 190 | watchdog_update_worker(wdd); |
192 | 191 | ||
193 | return err; | 192 | return err; |
194 | } | 193 | } |
195 | 194 | ||
196 | /* | 195 | /* |
197 | * watchdog_ping: ping the watchdog. | 196 | * watchdog_ping: ping the watchdog. |
198 | * @wdd: the watchdog device to ping | 197 | * @wdd: the watchdog device to ping |
199 | * | 198 | * |
200 | * The caller must hold wd_data->lock. | 199 | * The caller must hold wd_data->lock. |
201 | * | 200 | * |
202 | * If the watchdog has no own ping operation then it needs to be | 201 | * If the watchdog has no own ping operation then it needs to be |
203 | * restarted via the start operation. This wrapper function does | 202 | * restarted via the start operation. This wrapper function does |
204 | * exactly that. | 203 | * exactly that. |
205 | * We only ping when the watchdog device is running. | 204 | * We only ping when the watchdog device is running. |
206 | */ | 205 | */ |
207 | 206 | ||
208 | static int watchdog_ping(struct watchdog_device *wdd) | 207 | static int watchdog_ping(struct watchdog_device *wdd) |
209 | { | 208 | { |
210 | struct watchdog_core_data *wd_data = wdd->wd_data; | 209 | struct watchdog_core_data *wd_data = wdd->wd_data; |
211 | 210 | ||
212 | if (!watchdog_active(wdd) && !watchdog_hw_running(wdd)) | 211 | if (!watchdog_active(wdd) && !watchdog_hw_running(wdd)) |
213 | return 0; | 212 | return 0; |
214 | 213 | ||
215 | set_bit(_WDOG_KEEPALIVE, &wd_data->status); | 214 | set_bit(_WDOG_KEEPALIVE, &wd_data->status); |
216 | 215 | ||
217 | wd_data->last_keepalive = ktime_get(); | 216 | wd_data->last_keepalive = ktime_get(); |
218 | return __watchdog_ping(wdd); | 217 | return __watchdog_ping(wdd); |
219 | } | 218 | } |
220 | 219 | ||
221 | static bool watchdog_worker_should_ping(struct watchdog_core_data *wd_data) | 220 | static bool watchdog_worker_should_ping(struct watchdog_core_data *wd_data) |
222 | { | 221 | { |
223 | struct watchdog_device *wdd = wd_data->wdd; | 222 | struct watchdog_device *wdd = wd_data->wdd; |
224 | 223 | ||
225 | if (!wdd) | 224 | if (!wdd) |
226 | return false; | 225 | return false; |
227 | 226 | ||
228 | if (watchdog_active(wdd)) | 227 | if (watchdog_active(wdd)) |
229 | return true; | 228 | return true; |
230 | 229 | ||
231 | return watchdog_hw_running(wdd) && !watchdog_past_open_deadline(wd_data); | 230 | return watchdog_hw_running(wdd) && !watchdog_past_open_deadline(wd_data); |
232 | } | 231 | } |
233 | 232 | ||
234 | static void watchdog_ping_work(struct kthread_work *work) | 233 | static void watchdog_ping_work(struct kthread_work *work) |
235 | { | 234 | { |
236 | struct watchdog_core_data *wd_data; | 235 | struct watchdog_core_data *wd_data; |
237 | 236 | ||
238 | wd_data = container_of(work, struct watchdog_core_data, work); | 237 | wd_data = container_of(work, struct watchdog_core_data, work); |
239 | 238 | ||
240 | mutex_lock(&wd_data->lock); | 239 | mutex_lock(&wd_data->lock); |
241 | if (watchdog_worker_should_ping(wd_data)) | 240 | if (watchdog_worker_should_ping(wd_data)) |
242 | __watchdog_ping(wd_data->wdd); | 241 | __watchdog_ping(wd_data->wdd); |
243 | mutex_unlock(&wd_data->lock); | 242 | mutex_unlock(&wd_data->lock); |
244 | } | 243 | } |
245 | 244 | ||
246 | static enum hrtimer_restart watchdog_timer_expired(struct hrtimer *timer) | 245 | static enum hrtimer_restart watchdog_timer_expired(struct hrtimer *timer) |
247 | { | 246 | { |
248 | struct watchdog_core_data *wd_data; | 247 | struct watchdog_core_data *wd_data; |
249 | 248 | ||
250 | wd_data = container_of(timer, struct watchdog_core_data, timer); | 249 | wd_data = container_of(timer, struct watchdog_core_data, timer); |
251 | 250 | ||
252 | kthread_queue_work(watchdog_kworker, &wd_data->work); | 251 | kthread_queue_work(watchdog_kworker, &wd_data->work); |
253 | return HRTIMER_NORESTART; | 252 | return HRTIMER_NORESTART; |
254 | } | 253 | } |
255 | 254 | ||
256 | /* | 255 | /* |
257 | * watchdog_start: wrapper to start the watchdog. | 256 | * watchdog_start: wrapper to start the watchdog. |
258 | * @wdd: the watchdog device to start | 257 | * @wdd: the watchdog device to start |
259 | * | 258 | * |
260 | * The caller must hold wd_data->lock. | 259 | * The caller must hold wd_data->lock. |
261 | * | 260 | * |
262 | * Start the watchdog if it is not active and mark it active. | 261 | * Start the watchdog if it is not active and mark it active. |
263 | * This function returns zero on success or a negative errno code for | 262 | * This function returns zero on success or a negative errno code for |
264 | * failure. | 263 | * failure. |
265 | */ | 264 | */ |
266 | 265 | ||
267 | static int watchdog_start(struct watchdog_device *wdd) | 266 | static int watchdog_start(struct watchdog_device *wdd) |
268 | { | 267 | { |
269 | struct watchdog_core_data *wd_data = wdd->wd_data; | 268 | struct watchdog_core_data *wd_data = wdd->wd_data; |
270 | ktime_t started_at; | 269 | ktime_t started_at; |
271 | int err; | 270 | int err; |
272 | 271 | ||
273 | if (watchdog_active(wdd)) | 272 | if (watchdog_active(wdd)) |
274 | return 0; | 273 | return 0; |
275 | 274 | ||
276 | set_bit(_WDOG_KEEPALIVE, &wd_data->status); | 275 | set_bit(_WDOG_KEEPALIVE, &wd_data->status); |
277 | 276 | ||
278 | started_at = ktime_get(); | 277 | started_at = ktime_get(); |
279 | if (watchdog_hw_running(wdd) && wdd->ops->ping) | 278 | if (watchdog_hw_running(wdd) && wdd->ops->ping) |
280 | err = wdd->ops->ping(wdd); | 279 | err = wdd->ops->ping(wdd); |
281 | else | 280 | else |
282 | err = wdd->ops->start(wdd); | 281 | err = wdd->ops->start(wdd); |
283 | if (err == 0) { | 282 | if (err == 0) { |
284 | set_bit(WDOG_ACTIVE, &wdd->status); | 283 | set_bit(WDOG_ACTIVE, &wdd->status); |
285 | wd_data->last_keepalive = started_at; | 284 | wd_data->last_keepalive = started_at; |
286 | watchdog_update_worker(wdd); | 285 | watchdog_update_worker(wdd); |
287 | } | 286 | } |
288 | 287 | ||
289 | return err; | 288 | return err; |
290 | } | 289 | } |
291 | 290 | ||
292 | /* | 291 | /* |
293 | * watchdog_stop: wrapper to stop the watchdog. | 292 | * watchdog_stop: wrapper to stop the watchdog. |
294 | * @wdd: the watchdog device to stop | 293 | * @wdd: the watchdog device to stop |
295 | * | 294 | * |
296 | * The caller must hold wd_data->lock. | 295 | * The caller must hold wd_data->lock. |
297 | * | 296 | * |
298 | * Stop the watchdog if it is still active and unmark it active. | 297 | * Stop the watchdog if it is still active and unmark it active. |
299 | * This function returns zero on success or a negative errno code for | 298 | * This function returns zero on success or a negative errno code for |
300 | * failure. | 299 | * failure. |
301 | * If the 'nowayout' feature was set, the watchdog cannot be stopped. | 300 | * If the 'nowayout' feature was set, the watchdog cannot be stopped. |
302 | */ | 301 | */ |
303 | 302 | ||
304 | static int watchdog_stop(struct watchdog_device *wdd) | 303 | static int watchdog_stop(struct watchdog_device *wdd) |
305 | { | 304 | { |
306 | int err = 0; | 305 | int err = 0; |
307 | 306 | ||
308 | if (!watchdog_active(wdd)) | 307 | if (!watchdog_active(wdd)) |
309 | return 0; | 308 | return 0; |
310 | 309 | ||
311 | if (test_bit(WDOG_NO_WAY_OUT, &wdd->status)) { | 310 | if (test_bit(WDOG_NO_WAY_OUT, &wdd->status)) { |
312 | pr_info("watchdog%d: nowayout prevents watchdog being stopped!\n", | 311 | pr_info("watchdog%d: nowayout prevents watchdog being stopped!\n", |
313 | wdd->id); | 312 | wdd->id); |
314 | return -EBUSY; | 313 | return -EBUSY; |
315 | } | 314 | } |
316 | 315 | ||
317 | if (wdd->ops->stop) { | 316 | if (wdd->ops->stop) { |
318 | clear_bit(WDOG_HW_RUNNING, &wdd->status); | 317 | clear_bit(WDOG_HW_RUNNING, &wdd->status); |
319 | err = wdd->ops->stop(wdd); | 318 | err = wdd->ops->stop(wdd); |
320 | } else { | 319 | } else { |
321 | set_bit(WDOG_HW_RUNNING, &wdd->status); | 320 | set_bit(WDOG_HW_RUNNING, &wdd->status); |
322 | } | 321 | } |
323 | 322 | ||
324 | if (err == 0) { | 323 | if (err == 0) { |
325 | clear_bit(WDOG_ACTIVE, &wdd->status); | 324 | clear_bit(WDOG_ACTIVE, &wdd->status); |
326 | watchdog_update_worker(wdd); | 325 | watchdog_update_worker(wdd); |
327 | } | 326 | } |
328 | 327 | ||
329 | return err; | 328 | return err; |
330 | } | 329 | } |
331 | 330 | ||
332 | /* | 331 | /* |
333 | * watchdog_get_status: wrapper to get the watchdog status | 332 | * watchdog_get_status: wrapper to get the watchdog status |
334 | * @wdd: the watchdog device to get the status from | 333 | * @wdd: the watchdog device to get the status from |
335 | * | 334 | * |
336 | * The caller must hold wd_data->lock. | 335 | * The caller must hold wd_data->lock. |
337 | * | 336 | * |
338 | * Get the watchdog's status flags. | 337 | * Get the watchdog's status flags. |
339 | */ | 338 | */ |
340 | 339 | ||
341 | static unsigned int watchdog_get_status(struct watchdog_device *wdd) | 340 | static unsigned int watchdog_get_status(struct watchdog_device *wdd) |
342 | { | 341 | { |
343 | struct watchdog_core_data *wd_data = wdd->wd_data; | 342 | struct watchdog_core_data *wd_data = wdd->wd_data; |
344 | unsigned int status; | 343 | unsigned int status; |
345 | 344 | ||
346 | if (wdd->ops->status) | 345 | if (wdd->ops->status) |
347 | status = wdd->ops->status(wdd); | 346 | status = wdd->ops->status(wdd); |
348 | else | 347 | else |
349 | status = wdd->bootstatus & (WDIOF_CARDRESET | | 348 | status = wdd->bootstatus & (WDIOF_CARDRESET | |
350 | WDIOF_OVERHEAT | | 349 | WDIOF_OVERHEAT | |
351 | WDIOF_FANFAULT | | 350 | WDIOF_FANFAULT | |
352 | WDIOF_EXTERN1 | | 351 | WDIOF_EXTERN1 | |
353 | WDIOF_EXTERN2 | | 352 | WDIOF_EXTERN2 | |
354 | WDIOF_POWERUNDER | | 353 | WDIOF_POWERUNDER | |
355 | WDIOF_POWEROVER); | 354 | WDIOF_POWEROVER); |
356 | 355 | ||
357 | if (test_bit(_WDOG_ALLOW_RELEASE, &wd_data->status)) | 356 | if (test_bit(_WDOG_ALLOW_RELEASE, &wd_data->status)) |
358 | status |= WDIOF_MAGICCLOSE; | 357 | status |= WDIOF_MAGICCLOSE; |
359 | 358 | ||
360 | if (test_and_clear_bit(_WDOG_KEEPALIVE, &wd_data->status)) | 359 | if (test_and_clear_bit(_WDOG_KEEPALIVE, &wd_data->status)) |
361 | status |= WDIOF_KEEPALIVEPING; | 360 | status |= WDIOF_KEEPALIVEPING; |
362 | 361 | ||
363 | return status; | 362 | return status; |
364 | } | 363 | } |
365 | 364 | ||
366 | /* | 365 | /* |
367 | * watchdog_set_timeout: set the watchdog timer timeout | 366 | * watchdog_set_timeout: set the watchdog timer timeout |
368 | * @wdd: the watchdog device to set the timeout for | 367 | * @wdd: the watchdog device to set the timeout for |
369 | * @timeout: timeout to set in seconds | 368 | * @timeout: timeout to set in seconds |
370 | * | 369 | * |
371 | * The caller must hold wd_data->lock. | 370 | * The caller must hold wd_data->lock. |
372 | */ | 371 | */ |
373 | 372 | ||
374 | static int watchdog_set_timeout(struct watchdog_device *wdd, | 373 | static int watchdog_set_timeout(struct watchdog_device *wdd, |
375 | unsigned int timeout) | 374 | unsigned int timeout) |
376 | { | 375 | { |
377 | int err = 0; | 376 | int err = 0; |
378 | 377 | ||
379 | if (!(wdd->info->options & WDIOF_SETTIMEOUT)) | 378 | if (!(wdd->info->options & WDIOF_SETTIMEOUT)) |
380 | return -EOPNOTSUPP; | 379 | return -EOPNOTSUPP; |
381 | 380 | ||
382 | if (watchdog_timeout_invalid(wdd, timeout)) | 381 | if (watchdog_timeout_invalid(wdd, timeout)) |
383 | return -EINVAL; | 382 | return -EINVAL; |
384 | 383 | ||
385 | if (wdd->ops->set_timeout) { | 384 | if (wdd->ops->set_timeout) { |
386 | err = wdd->ops->set_timeout(wdd, timeout); | 385 | err = wdd->ops->set_timeout(wdd, timeout); |
387 | } else { | 386 | } else { |
388 | wdd->timeout = timeout; | 387 | wdd->timeout = timeout; |
389 | /* Disable pretimeout if it doesn't fit the new timeout */ | 388 | /* Disable pretimeout if it doesn't fit the new timeout */ |
390 | if (wdd->pretimeout >= wdd->timeout) | 389 | if (wdd->pretimeout >= wdd->timeout) |
391 | wdd->pretimeout = 0; | 390 | wdd->pretimeout = 0; |
392 | } | 391 | } |
393 | 392 | ||
394 | watchdog_update_worker(wdd); | 393 | watchdog_update_worker(wdd); |
395 | 394 | ||
396 | return err; | 395 | return err; |
397 | } | 396 | } |
398 | 397 | ||
399 | /* | 398 | /* |
400 | * watchdog_set_pretimeout: set the watchdog timer pretimeout | 399 | * watchdog_set_pretimeout: set the watchdog timer pretimeout |
401 | * @wdd: the watchdog device to set the timeout for | 400 | * @wdd: the watchdog device to set the timeout for |
402 | * @timeout: pretimeout to set in seconds | 401 | * @timeout: pretimeout to set in seconds |
403 | */ | 402 | */ |
404 | 403 | ||
405 | static int watchdog_set_pretimeout(struct watchdog_device *wdd, | 404 | static int watchdog_set_pretimeout(struct watchdog_device *wdd, |
406 | unsigned int timeout) | 405 | unsigned int timeout) |
407 | { | 406 | { |
408 | int err = 0; | 407 | int err = 0; |
409 | 408 | ||
410 | if (!(wdd->info->options & WDIOF_PRETIMEOUT)) | 409 | if (!(wdd->info->options & WDIOF_PRETIMEOUT)) |
411 | return -EOPNOTSUPP; | 410 | return -EOPNOTSUPP; |
412 | 411 | ||
413 | if (watchdog_pretimeout_invalid(wdd, timeout)) | 412 | if (watchdog_pretimeout_invalid(wdd, timeout)) |
414 | return -EINVAL; | 413 | return -EINVAL; |
415 | 414 | ||
416 | if (wdd->ops->set_pretimeout) | 415 | if (wdd->ops->set_pretimeout) |
417 | err = wdd->ops->set_pretimeout(wdd, timeout); | 416 | err = wdd->ops->set_pretimeout(wdd, timeout); |
418 | else | 417 | else |
419 | wdd->pretimeout = timeout; | 418 | wdd->pretimeout = timeout; |
420 | 419 | ||
421 | return err; | 420 | return err; |
422 | } | 421 | } |
423 | 422 | ||
424 | /* | 423 | /* |
425 | * watchdog_get_timeleft: wrapper to get the time left before a reboot | 424 | * watchdog_get_timeleft: wrapper to get the time left before a reboot |
426 | * @wdd: the watchdog device to get the remaining time from | 425 | * @wdd: the watchdog device to get the remaining time from |
427 | * @timeleft: the time that's left | 426 | * @timeleft: the time that's left |
428 | * | 427 | * |
429 | * The caller must hold wd_data->lock. | 428 | * The caller must hold wd_data->lock. |
430 | * | 429 | * |
431 | * Get the time before a watchdog will reboot (if not pinged). | 430 | * Get the time before a watchdog will reboot (if not pinged). |
432 | */ | 431 | */ |
433 | 432 | ||
434 | static int watchdog_get_timeleft(struct watchdog_device *wdd, | 433 | static int watchdog_get_timeleft(struct watchdog_device *wdd, |
435 | unsigned int *timeleft) | 434 | unsigned int *timeleft) |
436 | { | 435 | { |
437 | *timeleft = 0; | 436 | *timeleft = 0; |
438 | 437 | ||
439 | if (!wdd->ops->get_timeleft) | 438 | if (!wdd->ops->get_timeleft) |
440 | return -EOPNOTSUPP; | 439 | return -EOPNOTSUPP; |
441 | 440 | ||
442 | *timeleft = wdd->ops->get_timeleft(wdd); | 441 | *timeleft = wdd->ops->get_timeleft(wdd); |
443 | 442 | ||
444 | return 0; | 443 | return 0; |
445 | } | 444 | } |
446 | 445 | ||
447 | #ifdef CONFIG_WATCHDOG_SYSFS | 446 | #ifdef CONFIG_WATCHDOG_SYSFS |
448 | static ssize_t nowayout_show(struct device *dev, struct device_attribute *attr, | 447 | static ssize_t nowayout_show(struct device *dev, struct device_attribute *attr, |
449 | char *buf) | 448 | char *buf) |
450 | { | 449 | { |
451 | struct watchdog_device *wdd = dev_get_drvdata(dev); | 450 | struct watchdog_device *wdd = dev_get_drvdata(dev); |
452 | 451 | ||
453 | return sprintf(buf, "%d\n", !!test_bit(WDOG_NO_WAY_OUT, &wdd->status)); | 452 | return sprintf(buf, "%d\n", !!test_bit(WDOG_NO_WAY_OUT, &wdd->status)); |
454 | } | 453 | } |
455 | 454 | ||
456 | static ssize_t nowayout_store(struct device *dev, struct device_attribute *attr, | 455 | static ssize_t nowayout_store(struct device *dev, struct device_attribute *attr, |
457 | const char *buf, size_t len) | 456 | const char *buf, size_t len) |
458 | { | 457 | { |
459 | struct watchdog_device *wdd = dev_get_drvdata(dev); | 458 | struct watchdog_device *wdd = dev_get_drvdata(dev); |
460 | unsigned int value; | 459 | unsigned int value; |
461 | int ret; | 460 | int ret; |
462 | 461 | ||
463 | ret = kstrtouint(buf, 0, &value); | 462 | ret = kstrtouint(buf, 0, &value); |
464 | if (ret) | 463 | if (ret) |
465 | return ret; | 464 | return ret; |
466 | if (value > 1) | 465 | if (value > 1) |
467 | return -EINVAL; | 466 | return -EINVAL; |
468 | /* nowayout cannot be disabled once set */ | 467 | /* nowayout cannot be disabled once set */ |
469 | if (test_bit(WDOG_NO_WAY_OUT, &wdd->status) && !value) | 468 | if (test_bit(WDOG_NO_WAY_OUT, &wdd->status) && !value) |
470 | return -EPERM; | 469 | return -EPERM; |
471 | watchdog_set_nowayout(wdd, value); | 470 | watchdog_set_nowayout(wdd, value); |
472 | return len; | 471 | return len; |
473 | } | 472 | } |
474 | static DEVICE_ATTR_RW(nowayout); | 473 | static DEVICE_ATTR_RW(nowayout); |
475 | 474 | ||
476 | static ssize_t status_show(struct device *dev, struct device_attribute *attr, | 475 | static ssize_t status_show(struct device *dev, struct device_attribute *attr, |
477 | char *buf) | 476 | char *buf) |
478 | { | 477 | { |
479 | struct watchdog_device *wdd = dev_get_drvdata(dev); | 478 | struct watchdog_device *wdd = dev_get_drvdata(dev); |
480 | struct watchdog_core_data *wd_data = wdd->wd_data; | 479 | struct watchdog_core_data *wd_data = wdd->wd_data; |
481 | unsigned int status; | 480 | unsigned int status; |
482 | 481 | ||
483 | mutex_lock(&wd_data->lock); | 482 | mutex_lock(&wd_data->lock); |
484 | status = watchdog_get_status(wdd); | 483 | status = watchdog_get_status(wdd); |
485 | mutex_unlock(&wd_data->lock); | 484 | mutex_unlock(&wd_data->lock); |
486 | 485 | ||
487 | return sprintf(buf, "0x%x\n", status); | 486 | return sprintf(buf, "0x%x\n", status); |
488 | } | 487 | } |
489 | static DEVICE_ATTR_RO(status); | 488 | static DEVICE_ATTR_RO(status); |
490 | 489 | ||
491 | static ssize_t bootstatus_show(struct device *dev, | 490 | static ssize_t bootstatus_show(struct device *dev, |
492 | struct device_attribute *attr, char *buf) | 491 | struct device_attribute *attr, char *buf) |
493 | { | 492 | { |
494 | struct watchdog_device *wdd = dev_get_drvdata(dev); | 493 | struct watchdog_device *wdd = dev_get_drvdata(dev); |
495 | 494 | ||
496 | return sprintf(buf, "%u\n", wdd->bootstatus); | 495 | return sprintf(buf, "%u\n", wdd->bootstatus); |
497 | } | 496 | } |
498 | static DEVICE_ATTR_RO(bootstatus); | 497 | static DEVICE_ATTR_RO(bootstatus); |
499 | 498 | ||
500 | static ssize_t timeleft_show(struct device *dev, struct device_attribute *attr, | 499 | static ssize_t timeleft_show(struct device *dev, struct device_attribute *attr, |
501 | char *buf) | 500 | char *buf) |
502 | { | 501 | { |
503 | struct watchdog_device *wdd = dev_get_drvdata(dev); | 502 | struct watchdog_device *wdd = dev_get_drvdata(dev); |
504 | struct watchdog_core_data *wd_data = wdd->wd_data; | 503 | struct watchdog_core_data *wd_data = wdd->wd_data; |
505 | ssize_t status; | 504 | ssize_t status; |
506 | unsigned int val; | 505 | unsigned int val; |
507 | 506 | ||
508 | mutex_lock(&wd_data->lock); | 507 | mutex_lock(&wd_data->lock); |
509 | status = watchdog_get_timeleft(wdd, &val); | 508 | status = watchdog_get_timeleft(wdd, &val); |
510 | mutex_unlock(&wd_data->lock); | 509 | mutex_unlock(&wd_data->lock); |
511 | if (!status) | 510 | if (!status) |
512 | status = sprintf(buf, "%u\n", val); | 511 | status = sprintf(buf, "%u\n", val); |
513 | 512 | ||
514 | return status; | 513 | return status; |
515 | } | 514 | } |
516 | static DEVICE_ATTR_RO(timeleft); | 515 | static DEVICE_ATTR_RO(timeleft); |
517 | 516 | ||
518 | static ssize_t timeout_show(struct device *dev, struct device_attribute *attr, | 517 | static ssize_t timeout_show(struct device *dev, struct device_attribute *attr, |
519 | char *buf) | 518 | char *buf) |
520 | { | 519 | { |
521 | struct watchdog_device *wdd = dev_get_drvdata(dev); | 520 | struct watchdog_device *wdd = dev_get_drvdata(dev); |
522 | 521 | ||
523 | return sprintf(buf, "%u\n", wdd->timeout); | 522 | return sprintf(buf, "%u\n", wdd->timeout); |
524 | } | 523 | } |
525 | static DEVICE_ATTR_RO(timeout); | 524 | static DEVICE_ATTR_RO(timeout); |
526 | 525 | ||
527 | static ssize_t pretimeout_show(struct device *dev, | 526 | static ssize_t pretimeout_show(struct device *dev, |
528 | struct device_attribute *attr, char *buf) | 527 | struct device_attribute *attr, char *buf) |
529 | { | 528 | { |
530 | struct watchdog_device *wdd = dev_get_drvdata(dev); | 529 | struct watchdog_device *wdd = dev_get_drvdata(dev); |
531 | 530 | ||
532 | return sprintf(buf, "%u\n", wdd->pretimeout); | 531 | return sprintf(buf, "%u\n", wdd->pretimeout); |
533 | } | 532 | } |
534 | static DEVICE_ATTR_RO(pretimeout); | 533 | static DEVICE_ATTR_RO(pretimeout); |
535 | 534 | ||
536 | static ssize_t identity_show(struct device *dev, struct device_attribute *attr, | 535 | static ssize_t identity_show(struct device *dev, struct device_attribute *attr, |
537 | char *buf) | 536 | char *buf) |
538 | { | 537 | { |
539 | struct watchdog_device *wdd = dev_get_drvdata(dev); | 538 | struct watchdog_device *wdd = dev_get_drvdata(dev); |
540 | 539 | ||
541 | return sprintf(buf, "%s\n", wdd->info->identity); | 540 | return sprintf(buf, "%s\n", wdd->info->identity); |
542 | } | 541 | } |
543 | static DEVICE_ATTR_RO(identity); | 542 | static DEVICE_ATTR_RO(identity); |
544 | 543 | ||
545 | static ssize_t state_show(struct device *dev, struct device_attribute *attr, | 544 | static ssize_t state_show(struct device *dev, struct device_attribute *attr, |
546 | char *buf) | 545 | char *buf) |
547 | { | 546 | { |
548 | struct watchdog_device *wdd = dev_get_drvdata(dev); | 547 | struct watchdog_device *wdd = dev_get_drvdata(dev); |
549 | 548 | ||
550 | if (watchdog_active(wdd)) | 549 | if (watchdog_active(wdd)) |
551 | return sprintf(buf, "active\n"); | 550 | return sprintf(buf, "active\n"); |
552 | 551 | ||
553 | return sprintf(buf, "inactive\n"); | 552 | return sprintf(buf, "inactive\n"); |
554 | } | 553 | } |
555 | static DEVICE_ATTR_RO(state); | 554 | static DEVICE_ATTR_RO(state); |
556 | 555 | ||
557 | static ssize_t pretimeout_available_governors_show(struct device *dev, | 556 | static ssize_t pretimeout_available_governors_show(struct device *dev, |
558 | struct device_attribute *attr, char *buf) | 557 | struct device_attribute *attr, char *buf) |
559 | { | 558 | { |
560 | return watchdog_pretimeout_available_governors_get(buf); | 559 | return watchdog_pretimeout_available_governors_get(buf); |
561 | } | 560 | } |
562 | static DEVICE_ATTR_RO(pretimeout_available_governors); | 561 | static DEVICE_ATTR_RO(pretimeout_available_governors); |
563 | 562 | ||
564 | static ssize_t pretimeout_governor_show(struct device *dev, | 563 | static ssize_t pretimeout_governor_show(struct device *dev, |
565 | struct device_attribute *attr, | 564 | struct device_attribute *attr, |
566 | char *buf) | 565 | char *buf) |
567 | { | 566 | { |
568 | struct watchdog_device *wdd = dev_get_drvdata(dev); | 567 | struct watchdog_device *wdd = dev_get_drvdata(dev); |
569 | 568 | ||
570 | return watchdog_pretimeout_governor_get(wdd, buf); | 569 | return watchdog_pretimeout_governor_get(wdd, buf); |
571 | } | 570 | } |
572 | 571 | ||
573 | static ssize_t pretimeout_governor_store(struct device *dev, | 572 | static ssize_t pretimeout_governor_store(struct device *dev, |
574 | struct device_attribute *attr, | 573 | struct device_attribute *attr, |
575 | const char *buf, size_t count) | 574 | const char *buf, size_t count) |
576 | { | 575 | { |
577 | struct watchdog_device *wdd = dev_get_drvdata(dev); | 576 | struct watchdog_device *wdd = dev_get_drvdata(dev); |
578 | int ret = watchdog_pretimeout_governor_set(wdd, buf); | 577 | int ret = watchdog_pretimeout_governor_set(wdd, buf); |
579 | 578 | ||
580 | if (!ret) | 579 | if (!ret) |
581 | ret = count; | 580 | ret = count; |
582 | 581 | ||
583 | return ret; | 582 | return ret; |
584 | } | 583 | } |
585 | static DEVICE_ATTR_RW(pretimeout_governor); | 584 | static DEVICE_ATTR_RW(pretimeout_governor); |
586 | 585 | ||
587 | static umode_t wdt_is_visible(struct kobject *kobj, struct attribute *attr, | 586 | static umode_t wdt_is_visible(struct kobject *kobj, struct attribute *attr, |
588 | int n) | 587 | int n) |
589 | { | 588 | { |
590 | struct device *dev = container_of(kobj, struct device, kobj); | 589 | struct device *dev = container_of(kobj, struct device, kobj); |
591 | struct watchdog_device *wdd = dev_get_drvdata(dev); | 590 | struct watchdog_device *wdd = dev_get_drvdata(dev); |
592 | umode_t mode = attr->mode; | 591 | umode_t mode = attr->mode; |
593 | 592 | ||
594 | if (attr == &dev_attr_timeleft.attr && !wdd->ops->get_timeleft) | 593 | if (attr == &dev_attr_timeleft.attr && !wdd->ops->get_timeleft) |
595 | mode = 0; | 594 | mode = 0; |
596 | else if (attr == &dev_attr_pretimeout.attr && | 595 | else if (attr == &dev_attr_pretimeout.attr && |
597 | !(wdd->info->options & WDIOF_PRETIMEOUT)) | 596 | !(wdd->info->options & WDIOF_PRETIMEOUT)) |
598 | mode = 0; | 597 | mode = 0; |
599 | else if ((attr == &dev_attr_pretimeout_governor.attr || | 598 | else if ((attr == &dev_attr_pretimeout_governor.attr || |
600 | attr == &dev_attr_pretimeout_available_governors.attr) && | 599 | attr == &dev_attr_pretimeout_available_governors.attr) && |
601 | (!(wdd->info->options & WDIOF_PRETIMEOUT) || | 600 | (!(wdd->info->options & WDIOF_PRETIMEOUT) || |
602 | !IS_ENABLED(CONFIG_WATCHDOG_PRETIMEOUT_GOV))) | 601 | !IS_ENABLED(CONFIG_WATCHDOG_PRETIMEOUT_GOV))) |
603 | mode = 0; | 602 | mode = 0; |
604 | 603 | ||
605 | return mode; | 604 | return mode; |
606 | } | 605 | } |
607 | static struct attribute *wdt_attrs[] = { | 606 | static struct attribute *wdt_attrs[] = { |
608 | &dev_attr_state.attr, | 607 | &dev_attr_state.attr, |
609 | &dev_attr_identity.attr, | 608 | &dev_attr_identity.attr, |
610 | &dev_attr_timeout.attr, | 609 | &dev_attr_timeout.attr, |
611 | &dev_attr_pretimeout.attr, | 610 | &dev_attr_pretimeout.attr, |
612 | &dev_attr_timeleft.attr, | 611 | &dev_attr_timeleft.attr, |
613 | &dev_attr_bootstatus.attr, | 612 | &dev_attr_bootstatus.attr, |
614 | &dev_attr_status.attr, | 613 | &dev_attr_status.attr, |
615 | &dev_attr_nowayout.attr, | 614 | &dev_attr_nowayout.attr, |
616 | &dev_attr_pretimeout_governor.attr, | 615 | &dev_attr_pretimeout_governor.attr, |
617 | &dev_attr_pretimeout_available_governors.attr, | 616 | &dev_attr_pretimeout_available_governors.attr, |
618 | NULL, | 617 | NULL, |
619 | }; | 618 | }; |
620 | 619 | ||
621 | static const struct attribute_group wdt_group = { | 620 | static const struct attribute_group wdt_group = { |
622 | .attrs = wdt_attrs, | 621 | .attrs = wdt_attrs, |
623 | .is_visible = wdt_is_visible, | 622 | .is_visible = wdt_is_visible, |
624 | }; | 623 | }; |
625 | __ATTRIBUTE_GROUPS(wdt); | 624 | __ATTRIBUTE_GROUPS(wdt); |
626 | #else | 625 | #else |
627 | #define wdt_groups NULL | 626 | #define wdt_groups NULL |
628 | #endif | 627 | #endif |
629 | 628 | ||
630 | /* | 629 | /* |
631 | * watchdog_ioctl_op: call the watchdog drivers ioctl op if defined | 630 | * watchdog_ioctl_op: call the watchdog drivers ioctl op if defined |
632 | * @wdd: the watchdog device to do the ioctl on | 631 | * @wdd: the watchdog device to do the ioctl on |
633 | * @cmd: watchdog command | 632 | * @cmd: watchdog command |
634 | * @arg: argument pointer | 633 | * @arg: argument pointer |
635 | * | 634 | * |
636 | * The caller must hold wd_data->lock. | 635 | * The caller must hold wd_data->lock. |
637 | */ | 636 | */ |
638 | 637 | ||
639 | static int watchdog_ioctl_op(struct watchdog_device *wdd, unsigned int cmd, | 638 | static int watchdog_ioctl_op(struct watchdog_device *wdd, unsigned int cmd, |
640 | unsigned long arg) | 639 | unsigned long arg) |
641 | { | 640 | { |
642 | if (!wdd->ops->ioctl) | 641 | if (!wdd->ops->ioctl) |
643 | return -ENOIOCTLCMD; | 642 | return -ENOIOCTLCMD; |
644 | 643 | ||
645 | return wdd->ops->ioctl(wdd, cmd, arg); | 644 | return wdd->ops->ioctl(wdd, cmd, arg); |
646 | } | 645 | } |
647 | 646 | ||
648 | /* | 647 | /* |
649 | * watchdog_write: writes to the watchdog. | 648 | * watchdog_write: writes to the watchdog. |
650 | * @file: file from VFS | 649 | * @file: file from VFS |
651 | * @data: user address of data | 650 | * @data: user address of data |
652 | * @len: length of data | 651 | * @len: length of data |
653 | * @ppos: pointer to the file offset | 652 | * @ppos: pointer to the file offset |
654 | * | 653 | * |
655 | * A write to a watchdog device is defined as a keepalive ping. | 654 | * A write to a watchdog device is defined as a keepalive ping. |
656 | * Writing the magic 'V' sequence allows the next close to turn | 655 | * Writing the magic 'V' sequence allows the next close to turn |
657 | * off the watchdog (if 'nowayout' is not set). | 656 | * off the watchdog (if 'nowayout' is not set). |
658 | */ | 657 | */ |
659 | 658 | ||
660 | static ssize_t watchdog_write(struct file *file, const char __user *data, | 659 | static ssize_t watchdog_write(struct file *file, const char __user *data, |
661 | size_t len, loff_t *ppos) | 660 | size_t len, loff_t *ppos) |
662 | { | 661 | { |
663 | struct watchdog_core_data *wd_data = file->private_data; | 662 | struct watchdog_core_data *wd_data = file->private_data; |
664 | struct watchdog_device *wdd; | 663 | struct watchdog_device *wdd; |
665 | int err; | 664 | int err; |
666 | size_t i; | 665 | size_t i; |
667 | char c; | 666 | char c; |
668 | 667 | ||
669 | if (len == 0) | 668 | if (len == 0) |
670 | return 0; | 669 | return 0; |
671 | 670 | ||
672 | /* | 671 | /* |
673 | * Note: just in case someone wrote the magic character | 672 | * Note: just in case someone wrote the magic character |
674 | * five months ago... | 673 | * five months ago... |
675 | */ | 674 | */ |
676 | clear_bit(_WDOG_ALLOW_RELEASE, &wd_data->status); | 675 | clear_bit(_WDOG_ALLOW_RELEASE, &wd_data->status); |
677 | 676 | ||
678 | /* scan to see whether or not we got the magic character */ | 677 | /* scan to see whether or not we got the magic character */ |
679 | for (i = 0; i != len; i++) { | 678 | for (i = 0; i != len; i++) { |
680 | if (get_user(c, data + i)) | 679 | if (get_user(c, data + i)) |
681 | return -EFAULT; | 680 | return -EFAULT; |
682 | if (c == 'V') | 681 | if (c == 'V') |
683 | set_bit(_WDOG_ALLOW_RELEASE, &wd_data->status); | 682 | set_bit(_WDOG_ALLOW_RELEASE, &wd_data->status); |
684 | } | 683 | } |
685 | 684 | ||
686 | /* someone wrote to us, so we send the watchdog a keepalive ping */ | 685 | /* someone wrote to us, so we send the watchdog a keepalive ping */ |
687 | 686 | ||
688 | err = -ENODEV; | 687 | err = -ENODEV; |
689 | mutex_lock(&wd_data->lock); | 688 | mutex_lock(&wd_data->lock); |
690 | wdd = wd_data->wdd; | 689 | wdd = wd_data->wdd; |
691 | if (wdd) | 690 | if (wdd) |
692 | err = watchdog_ping(wdd); | 691 | err = watchdog_ping(wdd); |
693 | mutex_unlock(&wd_data->lock); | 692 | mutex_unlock(&wd_data->lock); |
694 | 693 | ||
695 | if (err < 0) | 694 | if (err < 0) |
696 | return err; | 695 | return err; |
697 | 696 | ||
698 | return len; | 697 | return len; |
699 | } | 698 | } |
700 | 699 | ||
701 | /* | 700 | /* |
702 | * watchdog_ioctl: handle the different ioctl's for the watchdog device. | 701 | * watchdog_ioctl: handle the different ioctl's for the watchdog device. |
703 | * @file: file handle to the device | 702 | * @file: file handle to the device |
704 | * @cmd: watchdog command | 703 | * @cmd: watchdog command |
705 | * @arg: argument pointer | 704 | * @arg: argument pointer |
706 | * | 705 | * |
707 | * The watchdog API defines a common set of functions for all watchdogs | 706 | * The watchdog API defines a common set of functions for all watchdogs |
708 | * according to their available features. | 707 | * according to their available features. |
709 | */ | 708 | */ |
710 | 709 | ||
711 | static long watchdog_ioctl(struct file *file, unsigned int cmd, | 710 | static long watchdog_ioctl(struct file *file, unsigned int cmd, |
712 | unsigned long arg) | 711 | unsigned long arg) |
713 | { | 712 | { |
714 | struct watchdog_core_data *wd_data = file->private_data; | 713 | struct watchdog_core_data *wd_data = file->private_data; |
715 | void __user *argp = (void __user *)arg; | 714 | void __user *argp = (void __user *)arg; |
716 | struct watchdog_device *wdd; | 715 | struct watchdog_device *wdd; |
717 | int __user *p = argp; | 716 | int __user *p = argp; |
718 | unsigned int val; | 717 | unsigned int val; |
719 | int err; | 718 | int err; |
720 | 719 | ||
721 | mutex_lock(&wd_data->lock); | 720 | mutex_lock(&wd_data->lock); |
722 | 721 | ||
723 | wdd = wd_data->wdd; | 722 | wdd = wd_data->wdd; |
724 | if (!wdd) { | 723 | if (!wdd) { |
725 | err = -ENODEV; | 724 | err = -ENODEV; |
726 | goto out_ioctl; | 725 | goto out_ioctl; |
727 | } | 726 | } |
728 | 727 | ||
729 | err = watchdog_ioctl_op(wdd, cmd, arg); | 728 | err = watchdog_ioctl_op(wdd, cmd, arg); |
730 | if (err != -ENOIOCTLCMD) | 729 | if (err != -ENOIOCTLCMD) |
731 | goto out_ioctl; | 730 | goto out_ioctl; |
732 | 731 | ||
733 | switch (cmd) { | 732 | switch (cmd) { |
734 | case WDIOC_GETSUPPORT: | 733 | case WDIOC_GETSUPPORT: |
735 | err = copy_to_user(argp, wdd->info, | 734 | err = copy_to_user(argp, wdd->info, |
736 | sizeof(struct watchdog_info)) ? -EFAULT : 0; | 735 | sizeof(struct watchdog_info)) ? -EFAULT : 0; |
737 | break; | 736 | break; |
738 | case WDIOC_GETSTATUS: | 737 | case WDIOC_GETSTATUS: |
739 | val = watchdog_get_status(wdd); | 738 | val = watchdog_get_status(wdd); |
740 | err = put_user(val, p); | 739 | err = put_user(val, p); |
741 | break; | 740 | break; |
742 | case WDIOC_GETBOOTSTATUS: | 741 | case WDIOC_GETBOOTSTATUS: |
743 | err = put_user(wdd->bootstatus, p); | 742 | err = put_user(wdd->bootstatus, p); |
744 | break; | 743 | break; |
745 | case WDIOC_SETOPTIONS: | 744 | case WDIOC_SETOPTIONS: |
746 | if (get_user(val, p)) { | 745 | if (get_user(val, p)) { |
747 | err = -EFAULT; | 746 | err = -EFAULT; |
748 | break; | 747 | break; |
749 | } | 748 | } |
750 | if (val & WDIOS_DISABLECARD) { | 749 | if (val & WDIOS_DISABLECARD) { |
751 | err = watchdog_stop(wdd); | 750 | err = watchdog_stop(wdd); |
752 | if (err < 0) | 751 | if (err < 0) |
753 | break; | 752 | break; |
754 | } | 753 | } |
755 | if (val & WDIOS_ENABLECARD) | 754 | if (val & WDIOS_ENABLECARD) |
756 | err = watchdog_start(wdd); | 755 | err = watchdog_start(wdd); |
757 | break; | 756 | break; |
758 | case WDIOC_KEEPALIVE: | 757 | case WDIOC_KEEPALIVE: |
759 | if (!(wdd->info->options & WDIOF_KEEPALIVEPING)) { | 758 | if (!(wdd->info->options & WDIOF_KEEPALIVEPING)) { |
760 | err = -EOPNOTSUPP; | 759 | err = -EOPNOTSUPP; |
761 | break; | 760 | break; |
762 | } | 761 | } |
763 | err = watchdog_ping(wdd); | 762 | err = watchdog_ping(wdd); |
764 | break; | 763 | break; |
765 | case WDIOC_SETTIMEOUT: | 764 | case WDIOC_SETTIMEOUT: |
766 | if (get_user(val, p)) { | 765 | if (get_user(val, p)) { |
767 | err = -EFAULT; | 766 | err = -EFAULT; |
768 | break; | 767 | break; |
769 | } | 768 | } |
770 | err = watchdog_set_timeout(wdd, val); | 769 | err = watchdog_set_timeout(wdd, val); |
771 | if (err < 0) | 770 | if (err < 0) |
772 | break; | 771 | break; |
773 | /* If the watchdog is active then we send a keepalive ping | 772 | /* If the watchdog is active then we send a keepalive ping |
774 | * to make sure that the watchdog keep's running (and if | 773 | * to make sure that the watchdog keep's running (and if |
775 | * possible that it takes the new timeout) */ | 774 | * possible that it takes the new timeout) */ |
776 | err = watchdog_ping(wdd); | 775 | err = watchdog_ping(wdd); |
777 | if (err < 0) | 776 | if (err < 0) |
778 | break; | 777 | break; |
779 | /* fall through */ | 778 | /* fall through */ |
780 | case WDIOC_GETTIMEOUT: | 779 | case WDIOC_GETTIMEOUT: |
781 | /* timeout == 0 means that we don't know the timeout */ | 780 | /* timeout == 0 means that we don't know the timeout */ |
782 | if (wdd->timeout == 0) { | 781 | if (wdd->timeout == 0) { |
783 | err = -EOPNOTSUPP; | 782 | err = -EOPNOTSUPP; |
784 | break; | 783 | break; |
785 | } | 784 | } |
786 | err = put_user(wdd->timeout, p); | 785 | err = put_user(wdd->timeout, p); |
787 | break; | 786 | break; |
788 | case WDIOC_GETTIMELEFT: | 787 | case WDIOC_GETTIMELEFT: |
789 | err = watchdog_get_timeleft(wdd, &val); | 788 | err = watchdog_get_timeleft(wdd, &val); |
790 | if (err < 0) | 789 | if (err < 0) |
791 | break; | 790 | break; |
792 | err = put_user(val, p); | 791 | err = put_user(val, p); |
793 | break; | 792 | break; |
794 | case WDIOC_SETPRETIMEOUT: | 793 | case WDIOC_SETPRETIMEOUT: |
795 | if (get_user(val, p)) { | 794 | if (get_user(val, p)) { |
796 | err = -EFAULT; | 795 | err = -EFAULT; |
797 | break; | 796 | break; |
798 | } | 797 | } |
799 | err = watchdog_set_pretimeout(wdd, val); | 798 | err = watchdog_set_pretimeout(wdd, val); |
800 | break; | 799 | break; |
801 | case WDIOC_GETPRETIMEOUT: | 800 | case WDIOC_GETPRETIMEOUT: |
802 | err = put_user(wdd->pretimeout, p); | 801 | err = put_user(wdd->pretimeout, p); |
803 | break; | 802 | break; |
804 | default: | 803 | default: |
805 | err = -ENOTTY; | 804 | err = -ENOTTY; |
806 | break; | 805 | break; |
807 | } | 806 | } |
808 | 807 | ||
809 | out_ioctl: | 808 | out_ioctl: |
810 | mutex_unlock(&wd_data->lock); | 809 | mutex_unlock(&wd_data->lock); |
811 | return err; | 810 | return err; |
812 | } | 811 | } |
813 | 812 | ||
814 | /* | 813 | /* |
815 | * watchdog_open: open the /dev/watchdog* devices. | 814 | * watchdog_open: open the /dev/watchdog* devices. |
816 | * @inode: inode of device | 815 | * @inode: inode of device |
817 | * @file: file handle to device | 816 | * @file: file handle to device |
818 | * | 817 | * |
819 | * When the /dev/watchdog* device gets opened, we start the watchdog. | 818 | * When the /dev/watchdog* device gets opened, we start the watchdog. |
820 | * Watch out: the /dev/watchdog device is single open, so we make sure | 819 | * Watch out: the /dev/watchdog device is single open, so we make sure |
821 | * it can only be opened once. | 820 | * it can only be opened once. |
822 | */ | 821 | */ |
823 | 822 | ||
824 | static int watchdog_open(struct inode *inode, struct file *file) | 823 | static int watchdog_open(struct inode *inode, struct file *file) |
825 | { | 824 | { |
826 | struct watchdog_core_data *wd_data; | 825 | struct watchdog_core_data *wd_data; |
827 | struct watchdog_device *wdd; | 826 | struct watchdog_device *wdd; |
828 | bool hw_running; | 827 | bool hw_running; |
829 | int err; | 828 | int err; |
830 | 829 | ||
831 | /* Get the corresponding watchdog device */ | 830 | /* Get the corresponding watchdog device */ |
832 | if (imajor(inode) == MISC_MAJOR) | 831 | if (imajor(inode) == MISC_MAJOR) |
833 | wd_data = old_wd_data; | 832 | wd_data = old_wd_data; |
834 | else | 833 | else |
835 | wd_data = container_of(inode->i_cdev, struct watchdog_core_data, | 834 | wd_data = container_of(inode->i_cdev, struct watchdog_core_data, |
836 | cdev); | 835 | cdev); |
837 | 836 | ||
838 | /* the watchdog is single open! */ | 837 | /* the watchdog is single open! */ |
839 | if (test_and_set_bit(_WDOG_DEV_OPEN, &wd_data->status)) | 838 | if (test_and_set_bit(_WDOG_DEV_OPEN, &wd_data->status)) |
840 | return -EBUSY; | 839 | return -EBUSY; |
841 | 840 | ||
842 | wdd = wd_data->wdd; | 841 | wdd = wd_data->wdd; |
843 | 842 | ||
844 | /* | 843 | /* |
845 | * If the /dev/watchdog device is open, we don't want the module | 844 | * If the /dev/watchdog device is open, we don't want the module |
846 | * to be unloaded. | 845 | * to be unloaded. |
847 | */ | 846 | */ |
848 | hw_running = watchdog_hw_running(wdd); | 847 | hw_running = watchdog_hw_running(wdd); |
849 | if (!hw_running && !try_module_get(wdd->ops->owner)) { | 848 | if (!hw_running && !try_module_get(wdd->ops->owner)) { |
850 | err = -EBUSY; | 849 | err = -EBUSY; |
851 | goto out_clear; | 850 | goto out_clear; |
852 | } | 851 | } |
853 | 852 | ||
854 | err = watchdog_start(wdd); | 853 | err = watchdog_start(wdd); |
855 | if (err < 0) | 854 | if (err < 0) |
856 | goto out_mod; | 855 | goto out_mod; |
857 | 856 | ||
858 | file->private_data = wd_data; | 857 | file->private_data = wd_data; |
859 | 858 | ||
860 | if (!hw_running) | 859 | if (!hw_running) |
861 | get_device(&wd_data->dev); | 860 | get_device(&wd_data->dev); |
862 | 861 | ||
863 | /* | 862 | /* |
864 | * open_timeout only applies for the first open from | 863 | * open_timeout only applies for the first open from |
865 | * userspace. Set open_deadline to infinity so that the kernel | 864 | * userspace. Set open_deadline to infinity so that the kernel |
866 | * will take care of an always-running hardware watchdog in | 865 | * will take care of an always-running hardware watchdog in |
867 | * case the device gets magic-closed or WDIOS_DISABLECARD is | 866 | * case the device gets magic-closed or WDIOS_DISABLECARD is |
868 | * applied. | 867 | * applied. |
869 | */ | 868 | */ |
870 | wd_data->open_deadline = KTIME_MAX; | 869 | wd_data->open_deadline = KTIME_MAX; |
871 | 870 | ||
872 | /* dev/watchdog is a virtual (and thus non-seekable) filesystem */ | 871 | /* dev/watchdog is a virtual (and thus non-seekable) filesystem */ |
873 | return stream_open(inode, file); | 872 | return stream_open(inode, file); |
874 | 873 | ||
875 | out_mod: | 874 | out_mod: |
876 | module_put(wd_data->wdd->ops->owner); | 875 | module_put(wd_data->wdd->ops->owner); |
877 | out_clear: | 876 | out_clear: |
878 | clear_bit(_WDOG_DEV_OPEN, &wd_data->status); | 877 | clear_bit(_WDOG_DEV_OPEN, &wd_data->status); |
879 | return err; | 878 | return err; |
880 | } | 879 | } |
881 | 880 | ||
882 | static void watchdog_core_data_release(struct device *dev) | 881 | static void watchdog_core_data_release(struct device *dev) |
883 | { | 882 | { |
884 | struct watchdog_core_data *wd_data; | 883 | struct watchdog_core_data *wd_data; |
885 | 884 | ||
886 | wd_data = container_of(dev, struct watchdog_core_data, dev); | 885 | wd_data = container_of(dev, struct watchdog_core_data, dev); |
887 | 886 | ||
888 | kfree(wd_data); | 887 | kfree(wd_data); |
889 | } | 888 | } |
890 | 889 | ||
891 | /* | 890 | /* |
892 | * watchdog_release: release the watchdog device. | 891 | * watchdog_release: release the watchdog device. |
893 | * @inode: inode of device | 892 | * @inode: inode of device |
894 | * @file: file handle to device | 893 | * @file: file handle to device |
895 | * | 894 | * |
896 | * This is the code for when /dev/watchdog gets closed. We will only | 895 | * This is the code for when /dev/watchdog gets closed. We will only |
897 | * stop the watchdog when we have received the magic char (and nowayout | 896 | * stop the watchdog when we have received the magic char (and nowayout |
898 | * was not set), else the watchdog will keep running. | 897 | * was not set), else the watchdog will keep running. |
899 | */ | 898 | */ |
900 | 899 | ||
901 | static int watchdog_release(struct inode *inode, struct file *file) | 900 | static int watchdog_release(struct inode *inode, struct file *file) |
902 | { | 901 | { |
903 | struct watchdog_core_data *wd_data = file->private_data; | 902 | struct watchdog_core_data *wd_data = file->private_data; |
904 | struct watchdog_device *wdd; | 903 | struct watchdog_device *wdd; |
905 | int err = -EBUSY; | 904 | int err = -EBUSY; |
906 | bool running; | 905 | bool running; |
907 | 906 | ||
908 | mutex_lock(&wd_data->lock); | 907 | mutex_lock(&wd_data->lock); |
909 | 908 | ||
910 | wdd = wd_data->wdd; | 909 | wdd = wd_data->wdd; |
911 | if (!wdd) | 910 | if (!wdd) |
912 | goto done; | 911 | goto done; |
913 | 912 | ||
914 | /* | 913 | /* |
915 | * We only stop the watchdog if we received the magic character | 914 | * We only stop the watchdog if we received the magic character |
916 | * or if WDIOF_MAGICCLOSE is not set. If nowayout was set then | 915 | * or if WDIOF_MAGICCLOSE is not set. If nowayout was set then |
917 | * watchdog_stop will fail. | 916 | * watchdog_stop will fail. |
918 | */ | 917 | */ |
919 | if (!test_bit(WDOG_ACTIVE, &wdd->status)) | 918 | if (!test_bit(WDOG_ACTIVE, &wdd->status)) |
920 | err = 0; | 919 | err = 0; |
921 | else if (test_and_clear_bit(_WDOG_ALLOW_RELEASE, &wd_data->status) || | 920 | else if (test_and_clear_bit(_WDOG_ALLOW_RELEASE, &wd_data->status) || |
922 | !(wdd->info->options & WDIOF_MAGICCLOSE)) | 921 | !(wdd->info->options & WDIOF_MAGICCLOSE)) |
923 | err = watchdog_stop(wdd); | 922 | err = watchdog_stop(wdd); |
924 | 923 | ||
925 | /* If the watchdog was not stopped, send a keepalive ping */ | 924 | /* If the watchdog was not stopped, send a keepalive ping */ |
926 | if (err < 0) { | 925 | if (err < 0) { |
927 | pr_crit("watchdog%d: watchdog did not stop!\n", wdd->id); | 926 | pr_crit("watchdog%d: watchdog did not stop!\n", wdd->id); |
928 | watchdog_ping(wdd); | 927 | watchdog_ping(wdd); |
929 | } | 928 | } |
930 | 929 | ||
931 | watchdog_update_worker(wdd); | 930 | watchdog_update_worker(wdd); |
932 | 931 | ||
933 | /* make sure that /dev/watchdog can be re-opened */ | 932 | /* make sure that /dev/watchdog can be re-opened */ |
934 | clear_bit(_WDOG_DEV_OPEN, &wd_data->status); | 933 | clear_bit(_WDOG_DEV_OPEN, &wd_data->status); |
935 | 934 | ||
936 | done: | 935 | done: |
937 | running = wdd && watchdog_hw_running(wdd); | 936 | running = wdd && watchdog_hw_running(wdd); |
938 | mutex_unlock(&wd_data->lock); | 937 | mutex_unlock(&wd_data->lock); |
939 | /* | 938 | /* |
940 | * Allow the owner module to be unloaded again unless the watchdog | 939 | * Allow the owner module to be unloaded again unless the watchdog |
941 | * is still running. If the watchdog is still running, it can not | 940 | * is still running. If the watchdog is still running, it can not |
942 | * be stopped, and its driver must not be unloaded. | 941 | * be stopped, and its driver must not be unloaded. |
943 | */ | 942 | */ |
944 | if (!running) { | 943 | if (!running) { |
945 | module_put(wd_data->cdev.owner); | 944 | module_put(wd_data->cdev.owner); |
946 | put_device(&wd_data->dev); | 945 | put_device(&wd_data->dev); |
947 | } | 946 | } |
948 | return 0; | 947 | return 0; |
949 | } | 948 | } |
950 | 949 | ||
951 | static const struct file_operations watchdog_fops = { | 950 | static const struct file_operations watchdog_fops = { |
952 | .owner = THIS_MODULE, | 951 | .owner = THIS_MODULE, |
953 | .write = watchdog_write, | 952 | .write = watchdog_write, |
954 | .unlocked_ioctl = watchdog_ioctl, | 953 | .unlocked_ioctl = watchdog_ioctl, |
955 | .compat_ioctl = compat_ptr_ioctl, | 954 | .compat_ioctl = compat_ptr_ioctl, |
956 | .open = watchdog_open, | 955 | .open = watchdog_open, |
957 | .release = watchdog_release, | 956 | .release = watchdog_release, |
958 | }; | 957 | }; |
959 | 958 | ||
960 | static struct miscdevice watchdog_miscdev = { | 959 | static struct miscdevice watchdog_miscdev = { |
961 | .minor = WATCHDOG_MINOR, | 960 | .minor = WATCHDOG_MINOR, |
962 | .name = "watchdog", | 961 | .name = "watchdog", |
963 | .fops = &watchdog_fops, | 962 | .fops = &watchdog_fops, |
964 | }; | 963 | }; |
965 | 964 | ||
966 | static struct class watchdog_class = { | 965 | static struct class watchdog_class = { |
967 | .name = "watchdog", | 966 | .name = "watchdog", |
968 | .owner = THIS_MODULE, | 967 | .owner = THIS_MODULE, |
969 | .dev_groups = wdt_groups, | 968 | .dev_groups = wdt_groups, |
970 | }; | 969 | }; |
971 | 970 | ||
972 | /* | 971 | /* |
973 | * watchdog_cdev_register: register watchdog character device | 972 | * watchdog_cdev_register: register watchdog character device |
974 | * @wdd: watchdog device | 973 | * @wdd: watchdog device |
975 | * | 974 | * |
976 | * Register a watchdog character device including handling the legacy | 975 | * Register a watchdog character device including handling the legacy |
977 | * /dev/watchdog node. /dev/watchdog is actually a miscdevice and | 976 | * /dev/watchdog node. /dev/watchdog is actually a miscdevice and |
978 | * thus we set it up like that. | 977 | * thus we set it up like that. |
979 | */ | 978 | */ |
980 | 979 | ||
981 | static int watchdog_cdev_register(struct watchdog_device *wdd) | 980 | static int watchdog_cdev_register(struct watchdog_device *wdd) |
982 | { | 981 | { |
983 | struct watchdog_core_data *wd_data; | 982 | struct watchdog_core_data *wd_data; |
984 | int err; | 983 | int err; |
985 | 984 | ||
986 | wd_data = kzalloc(sizeof(struct watchdog_core_data), GFP_KERNEL); | 985 | wd_data = kzalloc(sizeof(struct watchdog_core_data), GFP_KERNEL); |
987 | if (!wd_data) | 986 | if (!wd_data) |
988 | return -ENOMEM; | 987 | return -ENOMEM; |
989 | mutex_init(&wd_data->lock); | 988 | mutex_init(&wd_data->lock); |
990 | 989 | ||
991 | wd_data->wdd = wdd; | 990 | wd_data->wdd = wdd; |
992 | wdd->wd_data = wd_data; | 991 | wdd->wd_data = wd_data; |
993 | 992 | ||
994 | if (IS_ERR_OR_NULL(watchdog_kworker)) | 993 | if (IS_ERR_OR_NULL(watchdog_kworker)) |
995 | return -ENODEV; | 994 | return -ENODEV; |
996 | 995 | ||
997 | kthread_init_work(&wd_data->work, watchdog_ping_work); | 996 | kthread_init_work(&wd_data->work, watchdog_ping_work); |
998 | hrtimer_init(&wd_data->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD); | 997 | hrtimer_init(&wd_data->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD); |
999 | wd_data->timer.function = watchdog_timer_expired; | 998 | wd_data->timer.function = watchdog_timer_expired; |
1000 | 999 | ||
1001 | if (wdd->id == 0) { | 1000 | if (wdd->id == 0) { |
1002 | old_wd_data = wd_data; | 1001 | old_wd_data = wd_data; |
1003 | watchdog_miscdev.parent = wdd->parent; | 1002 | watchdog_miscdev.parent = wdd->parent; |
1004 | err = misc_register(&watchdog_miscdev); | 1003 | err = misc_register(&watchdog_miscdev); |
1005 | if (err != 0) { | 1004 | if (err != 0) { |
1006 | pr_err("%s: cannot register miscdev on minor=%d (err=%d).\n", | 1005 | pr_err("%s: cannot register miscdev on minor=%d (err=%d).\n", |
1007 | wdd->info->identity, WATCHDOG_MINOR, err); | 1006 | wdd->info->identity, WATCHDOG_MINOR, err); |
1008 | if (err == -EBUSY) | 1007 | if (err == -EBUSY) |
1009 | pr_err("%s: a legacy watchdog module is probably present.\n", | 1008 | pr_err("%s: a legacy watchdog module is probably present.\n", |
1010 | wdd->info->identity); | 1009 | wdd->info->identity); |
1011 | old_wd_data = NULL; | 1010 | old_wd_data = NULL; |
1012 | kfree(wd_data); | 1011 | kfree(wd_data); |
1013 | return err; | 1012 | return err; |
1014 | } | 1013 | } |
1015 | } | 1014 | } |
1016 | 1015 | ||
1017 | device_initialize(&wd_data->dev); | 1016 | device_initialize(&wd_data->dev); |
1018 | wd_data->dev.devt = MKDEV(MAJOR(watchdog_devt), wdd->id); | 1017 | wd_data->dev.devt = MKDEV(MAJOR(watchdog_devt), wdd->id); |
1019 | wd_data->dev.class = &watchdog_class; | 1018 | wd_data->dev.class = &watchdog_class; |
1020 | wd_data->dev.parent = wdd->parent; | 1019 | wd_data->dev.parent = wdd->parent; |
1021 | wd_data->dev.groups = wdd->groups; | 1020 | wd_data->dev.groups = wdd->groups; |
1022 | wd_data->dev.release = watchdog_core_data_release; | 1021 | wd_data->dev.release = watchdog_core_data_release; |
1023 | dev_set_drvdata(&wd_data->dev, wdd); | 1022 | dev_set_drvdata(&wd_data->dev, wdd); |
1024 | dev_set_name(&wd_data->dev, "watchdog%d", wdd->id); | 1023 | dev_set_name(&wd_data->dev, "watchdog%d", wdd->id); |
1025 | 1024 | ||
1026 | /* Fill in the data structures */ | 1025 | /* Fill in the data structures */ |
1027 | cdev_init(&wd_data->cdev, &watchdog_fops); | 1026 | cdev_init(&wd_data->cdev, &watchdog_fops); |
1028 | 1027 | ||
1029 | /* Add the device */ | 1028 | /* Add the device */ |
1030 | err = cdev_device_add(&wd_data->cdev, &wd_data->dev); | 1029 | err = cdev_device_add(&wd_data->cdev, &wd_data->dev); |
1031 | if (err) { | 1030 | if (err) { |
1032 | pr_err("watchdog%d unable to add device %d:%d\n", | 1031 | pr_err("watchdog%d unable to add device %d:%d\n", |
1033 | wdd->id, MAJOR(watchdog_devt), wdd->id); | 1032 | wdd->id, MAJOR(watchdog_devt), wdd->id); |
1034 | if (wdd->id == 0) { | 1033 | if (wdd->id == 0) { |
1035 | misc_deregister(&watchdog_miscdev); | 1034 | misc_deregister(&watchdog_miscdev); |
1036 | old_wd_data = NULL; | 1035 | old_wd_data = NULL; |
1037 | put_device(&wd_data->dev); | 1036 | put_device(&wd_data->dev); |
1038 | } | 1037 | } |
1039 | return err; | 1038 | return err; |
1040 | } | 1039 | } |
1041 | 1040 | ||
1042 | wd_data->cdev.owner = wdd->ops->owner; | 1041 | wd_data->cdev.owner = wdd->ops->owner; |
1043 | 1042 | ||
1044 | /* Record time of most recent heartbeat as 'just before now'. */ | 1043 | /* Record time of most recent heartbeat as 'just before now'. */ |
1045 | wd_data->last_hw_keepalive = ktime_sub(ktime_get(), 1); | 1044 | wd_data->last_hw_keepalive = ktime_sub(ktime_get(), 1); |
1046 | watchdog_set_open_deadline(wd_data); | 1045 | watchdog_set_open_deadline(wd_data); |
1047 | 1046 | ||
1048 | /* | 1047 | /* |
1049 | * If the watchdog is running, prevent its driver from being unloaded, | 1048 | * If the watchdog is running, prevent its driver from being unloaded, |
1050 | * and schedule an immediate ping. | 1049 | * and schedule an immediate ping. |
1051 | */ | 1050 | */ |
1052 | if (watchdog_hw_running(wdd)) { | 1051 | if (watchdog_hw_running(wdd)) { |
1053 | __module_get(wdd->ops->owner); | 1052 | __module_get(wdd->ops->owner); |
1054 | get_device(&wd_data->dev); | 1053 | get_device(&wd_data->dev); |
1055 | if (handle_boot_enabled) | 1054 | if (handle_boot_enabled) |
1056 | hrtimer_start(&wd_data->timer, 0, | 1055 | hrtimer_start(&wd_data->timer, 0, |
1057 | HRTIMER_MODE_REL_HARD); | 1056 | HRTIMER_MODE_REL_HARD); |
1058 | else | 1057 | else |
1059 | pr_info("watchdog%d running and kernel based pre-userspace handler disabled\n", | 1058 | pr_info("watchdog%d running and kernel based pre-userspace handler disabled\n", |
1060 | wdd->id); | 1059 | wdd->id); |
1061 | } | 1060 | } |
1062 | 1061 | ||
1063 | return 0; | 1062 | return 0; |
1064 | } | 1063 | } |
1065 | 1064 | ||
1066 | /* | 1065 | /* |
1067 | * watchdog_cdev_unregister: unregister watchdog character device | 1066 | * watchdog_cdev_unregister: unregister watchdog character device |
1068 | * @watchdog: watchdog device | 1067 | * @watchdog: watchdog device |
1069 | * | 1068 | * |
1070 | * Unregister watchdog character device and if needed the legacy | 1069 | * Unregister watchdog character device and if needed the legacy |
1071 | * /dev/watchdog device. | 1070 | * /dev/watchdog device. |
1072 | */ | 1071 | */ |
1073 | 1072 | ||
1074 | static void watchdog_cdev_unregister(struct watchdog_device *wdd) | 1073 | static void watchdog_cdev_unregister(struct watchdog_device *wdd) |
1075 | { | 1074 | { |
1076 | struct watchdog_core_data *wd_data = wdd->wd_data; | 1075 | struct watchdog_core_data *wd_data = wdd->wd_data; |
1077 | 1076 | ||
1078 | cdev_device_del(&wd_data->cdev, &wd_data->dev); | 1077 | cdev_device_del(&wd_data->cdev, &wd_data->dev); |
1079 | if (wdd->id == 0) { | 1078 | if (wdd->id == 0) { |
1080 | misc_deregister(&watchdog_miscdev); | 1079 | misc_deregister(&watchdog_miscdev); |
1081 | old_wd_data = NULL; | 1080 | old_wd_data = NULL; |
1082 | } | 1081 | } |
1083 | 1082 | ||
1084 | if (watchdog_active(wdd) && | 1083 | if (watchdog_active(wdd) && |
1085 | test_bit(WDOG_STOP_ON_UNREGISTER, &wdd->status)) { | 1084 | test_bit(WDOG_STOP_ON_UNREGISTER, &wdd->status)) { |
1086 | watchdog_stop(wdd); | 1085 | watchdog_stop(wdd); |
1087 | } | 1086 | } |
1088 | 1087 | ||
1089 | mutex_lock(&wd_data->lock); | 1088 | mutex_lock(&wd_data->lock); |
1090 | wd_data->wdd = NULL; | 1089 | wd_data->wdd = NULL; |
1091 | wdd->wd_data = NULL; | 1090 | wdd->wd_data = NULL; |
1092 | mutex_unlock(&wd_data->lock); | 1091 | mutex_unlock(&wd_data->lock); |
1093 | 1092 | ||
1094 | hrtimer_cancel(&wd_data->timer); | 1093 | hrtimer_cancel(&wd_data->timer); |
1095 | kthread_cancel_work_sync(&wd_data->work); | 1094 | kthread_cancel_work_sync(&wd_data->work); |
1096 | 1095 | ||
1097 | put_device(&wd_data->dev); | 1096 | put_device(&wd_data->dev); |
1098 | } | 1097 | } |
1099 | 1098 | ||
1100 | static int watchdog_reboot_notifier(struct notifier_block *nb, | ||
1101 | unsigned long code, void *data) | ||
1102 | { | ||
1103 | struct watchdog_device *wdd; | ||
1104 | |||
1105 | wdd = container_of(nb, struct watchdog_device, reboot_nb); | ||
1106 | if (code == SYS_DOWN || code == SYS_HALT) { | ||
1107 | if (watchdog_active(wdd)) { | ||
1108 | int ret; | ||
1109 | |||
1110 | ret = wdd->ops->stop(wdd); | ||
1111 | if (ret) | ||
1112 | return NOTIFY_BAD; | ||
1113 | } | ||
1114 | } | ||
1115 | |||
1116 | return NOTIFY_DONE; | ||
1117 | } | ||
1118 | |||
1119 | /* | 1099 | /* |
1120 | * watchdog_dev_register: register a watchdog device | 1100 | * watchdog_dev_register: register a watchdog device |
1121 | * @wdd: watchdog device | 1101 | * @wdd: watchdog device |
1122 | * | 1102 | * |
1123 | * Register a watchdog device including handling the legacy | 1103 | * Register a watchdog device including handling the legacy |
1124 | * /dev/watchdog node. /dev/watchdog is actually a miscdevice and | 1104 | * /dev/watchdog node. /dev/watchdog is actually a miscdevice and |
1125 | * thus we set it up like that. | 1105 | * thus we set it up like that. |
1126 | */ | 1106 | */ |
1127 | 1107 | ||
1128 | int watchdog_dev_register(struct watchdog_device *wdd) | 1108 | int watchdog_dev_register(struct watchdog_device *wdd) |
1129 | { | 1109 | { |
1130 | int ret; | 1110 | int ret; |
1131 | 1111 | ||
1132 | ret = watchdog_cdev_register(wdd); | 1112 | ret = watchdog_cdev_register(wdd); |
1133 | if (ret) | 1113 | if (ret) |
1134 | return ret; | 1114 | return ret; |
1135 | 1115 | ||
1136 | ret = watchdog_register_pretimeout(wdd); | 1116 | ret = watchdog_register_pretimeout(wdd); |
1137 | if (ret) { | 1117 | if (ret) |
1138 | watchdog_cdev_unregister(wdd); | 1118 | watchdog_cdev_unregister(wdd); |
1139 | return ret; | ||
1140 | } | ||
1141 | |||
1142 | if (test_bit(WDOG_STOP_ON_REBOOT, &wdd->status)) { | ||
1143 | wdd->reboot_nb.notifier_call = watchdog_reboot_notifier; | ||
1144 | |||
1145 | ret = devm_register_reboot_notifier(&wdd->wd_data->dev, | ||
1146 | &wdd->reboot_nb); | ||
1147 | if (ret) { | ||
1148 | pr_err("watchdog%d: Cannot register reboot notifier (%d)\n", | ||
1149 | wdd->id, ret); | ||
1150 | watchdog_dev_unregister(wdd); | ||
1151 | } | ||
1152 | } | ||
1153 | 1119 | ||
1154 | return ret; | 1120 | return ret; |
1155 | } | 1121 | } |
1156 | 1122 | ||
1157 | /* | 1123 | /* |
1158 | * watchdog_dev_unregister: unregister a watchdog device | 1124 | * watchdog_dev_unregister: unregister a watchdog device |
1159 | * @watchdog: watchdog device | 1125 | * @watchdog: watchdog device |
1160 | * | 1126 | * |
1161 | * Unregister watchdog device and if needed the legacy | 1127 | * Unregister watchdog device and if needed the legacy |
1162 | * /dev/watchdog device. | 1128 | * /dev/watchdog device. |
1163 | */ | 1129 | */ |
1164 | 1130 | ||
1165 | void watchdog_dev_unregister(struct watchdog_device *wdd) | 1131 | void watchdog_dev_unregister(struct watchdog_device *wdd) |
1166 | { | 1132 | { |
1167 | watchdog_unregister_pretimeout(wdd); | 1133 | watchdog_unregister_pretimeout(wdd); |
1168 | watchdog_cdev_unregister(wdd); | 1134 | watchdog_cdev_unregister(wdd); |
1169 | } | 1135 | } |
1170 | 1136 | ||
1171 | /* | 1137 | /* |
1172 | * watchdog_dev_init: init dev part of watchdog core | 1138 | * watchdog_dev_init: init dev part of watchdog core |
1173 | * | 1139 | * |
1174 | * Allocate a range of chardev nodes to use for watchdog devices | 1140 | * Allocate a range of chardev nodes to use for watchdog devices |
1175 | */ | 1141 | */ |
1176 | 1142 | ||
1177 | int __init watchdog_dev_init(void) | 1143 | int __init watchdog_dev_init(void) |
1178 | { | 1144 | { |
1179 | int err; | 1145 | int err; |
1180 | struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1,}; | 1146 | struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1,}; |
1181 | 1147 | ||
1182 | watchdog_kworker = kthread_create_worker(0, "watchdogd"); | 1148 | watchdog_kworker = kthread_create_worker(0, "watchdogd"); |
1183 | if (IS_ERR(watchdog_kworker)) { | 1149 | if (IS_ERR(watchdog_kworker)) { |
1184 | pr_err("Failed to create watchdog kworker\n"); | 1150 | pr_err("Failed to create watchdog kworker\n"); |
1185 | return PTR_ERR(watchdog_kworker); | 1151 | return PTR_ERR(watchdog_kworker); |
1186 | } | 1152 | } |
1187 | sched_setscheduler(watchdog_kworker->task, SCHED_FIFO, ¶m); | 1153 | sched_setscheduler(watchdog_kworker->task, SCHED_FIFO, ¶m); |
1188 | 1154 | ||
1189 | err = class_register(&watchdog_class); | 1155 | err = class_register(&watchdog_class); |
1190 | if (err < 0) { | 1156 | if (err < 0) { |
1191 | pr_err("couldn't register class\n"); | 1157 | pr_err("couldn't register class\n"); |
1192 | goto err_register; | 1158 | goto err_register; |
1193 | } | 1159 | } |
1194 | 1160 | ||
1195 | err = alloc_chrdev_region(&watchdog_devt, 0, MAX_DOGS, "watchdog"); | 1161 | err = alloc_chrdev_region(&watchdog_devt, 0, MAX_DOGS, "watchdog"); |
1196 | if (err < 0) { | 1162 | if (err < 0) { |
1197 | pr_err("watchdog: unable to allocate char dev region\n"); | 1163 | pr_err("watchdog: unable to allocate char dev region\n"); |
1198 | goto err_alloc; | 1164 | goto err_alloc; |
1199 | } | 1165 | } |
1200 | 1166 | ||
1201 | return 0; | 1167 | return 0; |
1202 | 1168 | ||
1203 | err_alloc: | 1169 | err_alloc: |
1204 | class_unregister(&watchdog_class); | 1170 | class_unregister(&watchdog_class); |
1205 | err_register: | 1171 | err_register: |
1206 | kthread_destroy_worker(watchdog_kworker); | 1172 | kthread_destroy_worker(watchdog_kworker); |
1207 | return err; | 1173 | return err; |
1208 | } | 1174 | } |
1209 | 1175 | ||
1210 | /* | 1176 | /* |
1211 | * watchdog_dev_exit: exit dev part of watchdog core | 1177 | * watchdog_dev_exit: exit dev part of watchdog core |
1212 | * | 1178 | * |
1213 | * Release the range of chardev nodes used for watchdog devices | 1179 | * Release the range of chardev nodes used for watchdog devices |
1214 | */ | 1180 | */ |
1215 | 1181 | ||
1216 | void __exit watchdog_dev_exit(void) | 1182 | void __exit watchdog_dev_exit(void) |
1217 | { | 1183 | { |
1218 | unregister_chrdev_region(watchdog_devt, MAX_DOGS); | 1184 | unregister_chrdev_region(watchdog_devt, MAX_DOGS); |
1219 | class_unregister(&watchdog_class); | 1185 | class_unregister(&watchdog_class); |
1220 | kthread_destroy_worker(watchdog_kworker); | 1186 | kthread_destroy_worker(watchdog_kworker); |
1221 | } | 1187 | } |
1222 | 1188 | ||
1223 | module_param(handle_boot_enabled, bool, 0444); | 1189 | module_param(handle_boot_enabled, bool, 0444); |
1224 | MODULE_PARM_DESC(handle_boot_enabled, | 1190 | MODULE_PARM_DESC(handle_boot_enabled, |
1225 | "Watchdog core auto-updates boot enabled watchdogs before userspace takes over (default=" | 1191 | "Watchdog core auto-updates boot enabled watchdogs before userspace takes over (default=" |
1226 | __MODULE_STRING(IS_ENABLED(CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED)) ")"); | 1192 | __MODULE_STRING(IS_ENABLED(CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED)) ")"); |
1227 | 1193 | ||
1228 | module_param(open_timeout, uint, 0644); | 1194 | module_param(open_timeout, uint, 0644); |
1229 | MODULE_PARM_DESC(open_timeout, | 1195 | MODULE_PARM_DESC(open_timeout, |
1230 | "Maximum time (in seconds, 0 means infinity) for userspace to take over a running watchdog (default=" | 1196 | "Maximum time (in seconds, 0 means infinity) for userspace to take over a running watchdog (default=" |
1231 | __MODULE_STRING(CONFIG_WATCHDOG_OPEN_TIMEOUT) ")"); | 1197 | __MODULE_STRING(CONFIG_WATCHDOG_OPEN_TIMEOUT) ")"); |
1232 | 1198 |