Whamcloud - gitweb
file jbd-stats-2.6.9.patch was initially added on branch b1_4.
[fs/lustre-release.git] / lnet / libcfs / watchdog.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * Copyright (C) 2004 Cluster File Systems, Inc.
5  *   Author: Jacob Berkman <jacob@clusterfs.com>
6  *
7  *   This file is part of Lustre, http://www.lustre.org.
8  *
9  *   Lustre is free software; you can redistribute it and/or
10  *   modify it under the terms of version 2 of the GNU General Public
11  *   License as published by the Free Software Foundation.
12  *
13  *   Lustre is distributed in the hope that it will be useful,
14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *   GNU General Public License for more details.
17  *
18  *   You should have received a copy of the GNU General Public License
19  *   along with Lustre; if not, write to the Free Software
20  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  */
22
23 #define DEBUG_SUBSYSTEM S_PORTALS
24
25 #include <libcfs/kp30.h>
26 #include <libcfs/libcfs.h>
27 #include <libcfs/linux/portals_compat25.h>
28
29
30
31 struct lc_watchdog {
32         struct timer_list lcw_timer; /* kernel timer */
33         struct list_head  lcw_list;
34         struct timeval    lcw_last_touched;
35         struct task_struct *lcw_task;
36
37         void (*lcw_callback)(struct lc_watchdog *,
38                              struct task_struct *,
39                              void *data);
40         void *lcw_data;
41
42         int lcw_pid;
43         int lcw_time; /* time until watchdog fires, in ms */
44
45         enum {
46                 LC_WATCHDOG_DISABLED,
47                 LC_WATCHDOG_ENABLED,
48                 LC_WATCHDOG_EXPIRED
49         } lcw_state;
50 };
51
52 /*
53  * The dispatcher will complete lcw_start_completion when it starts,
54  * and lcw_stop_completion when it exits.
55  * Wake lcw_event_waitq to signal timer callback dispatches.
56  */
57 static struct completion lcw_start_completion;
58 static struct completion lcw_stop_completion;
59 static wait_queue_head_t lcw_event_waitq;
60
61 /*
62  * Set this and wake lcw_event_waitq to stop the dispatcher.
63  */
64 enum {
65         LCW_FLAG_STOP = 0
66 };
67 static unsigned long lcw_flags = 0;
68
69 /*
70  * Number of outstanding watchdogs.
71  * When it hits 1, we start the dispatcher.
72  * When it hits 0, we stop the distpatcher.
73  */
74 static __u32         lcw_refcount = 0;
75 static DECLARE_MUTEX(lcw_refcount_sem);
76
77 /*
78  * List of timers that have fired that need their callbacks run by the
79  * dispatcher.
80  */
81 static spinlock_t       lcw_pending_timers_lock = SPIN_LOCK_UNLOCKED;
82 static struct list_head lcw_pending_timers = \
83         LIST_HEAD_INIT(lcw_pending_timers);
84
85 static struct task_struct *lcw_lookup_task(struct lc_watchdog *lcw)
86 {
87         struct task_struct *tsk;
88         unsigned long flags;
89         ENTRY;
90
91         read_lock_irqsave(&tasklist_lock, flags);
92         tsk = find_task_by_pid(lcw->lcw_pid);
93         read_unlock_irqrestore(&tasklist_lock, flags);
94         if (!tsk) {
95                 CWARN("Process %d was not found in the task list; "
96                       "watchdog callback may be incomplete\n", lcw->lcw_pid);
97         } else if (tsk != lcw->lcw_task) {
98                 tsk = NULL;
99                 CWARN("The current process %d did not set the watchdog; "
100                       "watchdog callback may be incomplete\n", lcw->lcw_pid);
101         }
102
103         RETURN(tsk);
104 }
105
106 static void lcw_cb(unsigned long data)
107 {
108         struct lc_watchdog *lcw = (struct lc_watchdog *)data;
109         struct task_struct *tsk;
110         unsigned long flags;
111
112         ENTRY;
113
114         if (lcw->lcw_state != LC_WATCHDOG_ENABLED) {
115                 EXIT;
116                 return;
117         }
118
119         lcw->lcw_state = LC_WATCHDOG_EXPIRED;
120
121         CWARN("Watchdog triggered for pid %d: it was inactive for %dms\n",
122               lcw->lcw_pid, (lcw->lcw_time * 1000) / HZ);
123
124         tsk = lcw_lookup_task(lcw);
125         if (tsk != NULL)
126                 portals_debug_dumpstack(tsk);
127
128         spin_lock_irqsave(&lcw_pending_timers_lock, flags);
129         if (list_empty(&lcw->lcw_list)) {
130                 list_add(&lcw->lcw_list, &lcw_pending_timers);
131                 wake_up(&lcw_event_waitq);
132         }
133         spin_unlock_irqrestore(&lcw_pending_timers_lock, flags);
134
135         EXIT;
136 }
137
138 static int is_watchdog_fired(void)
139 {
140         unsigned long flags;
141         int rc;
142
143         if (test_bit(LCW_FLAG_STOP, &lcw_flags))
144                 return 1;
145
146         spin_lock_irqsave(&lcw_pending_timers_lock, flags);
147         rc = !list_empty(&lcw_pending_timers);
148         spin_unlock_irqrestore(&lcw_pending_timers_lock, flags);
149         return rc;
150 }
151
152 static int lcw_dispatch_main(void *data)
153 {
154         int rc = 0;
155         unsigned long flags;
156         struct lc_watchdog *lcw;
157         struct task_struct *tsk;
158
159         ENTRY;
160
161         kportal_daemonize("lc_watchdogd");
162
163         SIGNAL_MASK_LOCK(current, flags);
164         sigfillset(&current->blocked);
165         RECALC_SIGPENDING;
166         SIGNAL_MASK_UNLOCK(current, flags);
167
168         complete(&lcw_start_completion);
169
170         while (1) {
171                 wait_event_interruptible(lcw_event_waitq, is_watchdog_fired());
172                 CDEBUG(D_INFO, "Watchdog got woken up...\n");
173                 if (test_bit(LCW_FLAG_STOP, &lcw_flags)) {
174                         CDEBUG(D_INFO, "LCW_FLAG_STOP was set, shutting down...\n");
175
176                         spin_lock_irqsave(&lcw_pending_timers_lock, flags);
177                         rc = !list_empty(&lcw_pending_timers);
178                         spin_unlock_irqrestore(&lcw_pending_timers_lock, flags);
179                         if (rc) {
180                                 CERROR("pending timers list was not empty at "
181                                        "time of watchdog dispatch shutdown\n");
182                         }
183                         break;
184                 }
185
186                 spin_lock_irqsave(&lcw_pending_timers_lock, flags);
187                 while (!list_empty(&lcw_pending_timers)) {
188
189                         lcw = list_entry(lcw_pending_timers.next,
190                                          struct lc_watchdog,
191                                          lcw_list);
192                         list_del_init(&lcw->lcw_list);
193                         spin_unlock_irqrestore(&lcw_pending_timers_lock, flags);
194
195                         CDEBUG(D_INFO, "found lcw for pid %d\n", lcw->lcw_pid);
196
197                         if (lcw->lcw_state != LC_WATCHDOG_DISABLED) {
198                                 /*
199                                  * sanity check the task against our
200                                  * watchdog
201                                  */
202                                 tsk = lcw_lookup_task(lcw);
203                                 lcw->lcw_callback(lcw, tsk, lcw->lcw_data);
204                         }
205
206                         spin_lock_irqsave(&lcw_pending_timers_lock, flags);
207                 }
208                 spin_unlock_irqrestore(&lcw_pending_timers_lock, flags);
209         }
210
211         complete(&lcw_stop_completion);
212
213         RETURN(rc);
214 }
215
216 static void lcw_dispatch_start(void)
217 {
218         int rc;
219
220         ENTRY;
221         LASSERT(lcw_refcount == 1);
222
223         init_completion(&lcw_stop_completion);
224         init_completion(&lcw_start_completion);
225         init_waitqueue_head(&lcw_event_waitq);
226
227         CDEBUG(D_INFO, "starting dispatch thread\n");
228         rc = kernel_thread(lcw_dispatch_main, NULL, 0);
229         if (rc < 0) {
230                 CERROR("error spawning watchdog dispatch thread: %d\n", rc);
231                 EXIT;
232                 return;
233         }
234         wait_for_completion(&lcw_start_completion);
235         CDEBUG(D_INFO, "watchdog dispatcher initialization complete.\n");
236
237         EXIT;
238 }
239
240 static void lcw_dispatch_stop(void)
241 {
242         ENTRY;
243         LASSERT(lcw_refcount == 0);
244
245         CDEBUG(D_INFO, "trying to stop watchdog dispatcher.\n");
246
247         set_bit(LCW_FLAG_STOP, &lcw_flags);
248         wake_up(&lcw_event_waitq);
249
250         wait_for_completion(&lcw_stop_completion);
251
252         CDEBUG(D_INFO, "watchdog dispatcher has shut down.\n");
253
254         EXIT;
255 }
256
257 struct lc_watchdog *lc_watchdog_add(int timeout_ms,
258                                     void (*callback)(struct lc_watchdog *,
259                                                      struct task_struct *,
260                                                      void *),
261                                     void *data)
262 {
263         struct lc_watchdog *lcw = NULL;
264         ENTRY;
265
266         PORTAL_ALLOC(lcw, sizeof(*lcw));
267         if (!lcw) {
268                 CDEBUG(D_INFO, "Could not allocate new lc_watchdog\n");
269                 RETURN(ERR_PTR(-ENOMEM));
270         }
271
272         lcw->lcw_task = cfs_current();
273         lcw->lcw_pid = cfs_curproc_pid();
274         lcw->lcw_time = (timeout_ms * HZ) / 1000;
275         lcw->lcw_callback = callback ? callback : lc_watchdog_dumplog;
276         lcw->lcw_data = data;
277         lcw->lcw_state = LC_WATCHDOG_DISABLED;
278
279         INIT_LIST_HEAD(&lcw->lcw_list);
280
281         lcw->lcw_timer.function = lcw_cb;
282         lcw->lcw_timer.data = (unsigned long)lcw;
283         lcw->lcw_timer.expires = jiffies + lcw->lcw_time;
284         init_timer(&lcw->lcw_timer);
285
286         down(&lcw_refcount_sem);
287         if (++lcw_refcount == 1)
288                 lcw_dispatch_start();
289         up(&lcw_refcount_sem);
290
291         /* Keep this working in case we enable them by default */
292         if (lcw->lcw_state == LC_WATCHDOG_ENABLED) {
293                 do_gettimeofday(&lcw->lcw_last_touched);
294                 add_timer(&lcw->lcw_timer);
295         }
296
297         RETURN(lcw);
298 }
299 EXPORT_SYMBOL(lc_watchdog_add);
300
301 static long
302 timeval_sub(struct timeval *large, struct timeval *small)
303 {
304         return (large->tv_sec - small->tv_sec) * 1000000 +
305                 (large->tv_usec - small->tv_usec);
306 }
307
308 static void lcw_update_time(struct lc_watchdog *lcw, const char *message)
309 {
310         struct timeval newtime;
311         unsigned long timediff;
312
313         do_gettimeofday(&newtime);
314         if (lcw->lcw_state == LC_WATCHDOG_EXPIRED) {
315                 timediff = timeval_sub(&newtime, &lcw->lcw_last_touched);
316                 CWARN("Expired watchdog for pid %d %s after %lu.%.4lus\n",
317                       lcw->lcw_pid,
318                       message,
319                       timediff / 1000000,
320                       (timediff % 1000000) / 100);
321         }
322         lcw->lcw_last_touched = newtime;
323 }
324
325 void lc_watchdog_touch(struct lc_watchdog *lcw)
326 {
327         unsigned long flags;
328         ENTRY;
329         LASSERT(lcw != NULL);
330
331         spin_lock_irqsave(&lcw_pending_timers_lock, flags);
332         if (!list_empty(&lcw->lcw_list))
333                 list_del_init(&lcw->lcw_list);
334         spin_unlock_irqrestore(&lcw_pending_timers_lock, flags);
335
336         lcw_update_time(lcw, "touched");
337         lcw->lcw_state = LC_WATCHDOG_ENABLED;
338
339         mod_timer(&lcw->lcw_timer, jiffies + lcw->lcw_time);
340
341         EXIT;
342 }
343 EXPORT_SYMBOL(lc_watchdog_touch);
344
345 void lc_watchdog_disable(struct lc_watchdog *lcw)
346 {
347         unsigned long flags;
348         ENTRY;
349         LASSERT(lcw != NULL);
350
351         spin_lock_irqsave(&lcw_pending_timers_lock, flags);
352         if (!list_empty(&lcw->lcw_list))
353                 list_del_init(&lcw->lcw_list);
354         spin_unlock_irqrestore(&lcw_pending_timers_lock, flags);
355
356         lcw_update_time(lcw, "disabled");
357         lcw->lcw_state = LC_WATCHDOG_DISABLED;
358
359         EXIT;
360 }
361 EXPORT_SYMBOL(lc_watchdog_disable);
362
363 void lc_watchdog_delete(struct lc_watchdog *lcw)
364 {
365         unsigned long flags;
366         ENTRY;
367         LASSERT(lcw != NULL);
368
369         del_timer(&lcw->lcw_timer);
370
371         lcw_update_time(lcw, "deleted");
372
373         spin_lock_irqsave(&lcw_pending_timers_lock, flags);
374         if (!list_empty(&lcw->lcw_list))
375                 list_del_init(&lcw->lcw_list);
376         spin_unlock_irqrestore(&lcw_pending_timers_lock, flags);
377
378         down(&lcw_refcount_sem);
379         if (--lcw_refcount == 0)
380                 lcw_dispatch_stop();
381         up(&lcw_refcount_sem);
382
383         PORTAL_FREE(lcw, sizeof(*lcw));
384
385         EXIT;
386 }
387 EXPORT_SYMBOL(lc_watchdog_delete);
388
389 /*
390  * Provided watchdog handlers
391  */
392
393 extern void portals_debug_dumplog_internal(void *arg);
394
395 void lc_watchdog_dumplog(struct lc_watchdog *lcw,
396                          struct task_struct *tsk,
397                          void               *data)
398 {
399         tsk = tsk ? tsk : current;
400         portals_debug_dumplog_internal((void *)(long)tsk->pid);
401 }
402 EXPORT_SYMBOL(lc_watchdog_dumplog);