[PATCH] knfsd: lockd: fix refount on nsm
[linux-2.6] / fs / afs / kafstimod.c
1 /* kafstimod.c: AFS timeout daemon
2  *
3  * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
4  * Written by David Howells (dhowells@redhat.com)
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version
9  * 2 of the License, or (at your option) any later version.
10  */
11
12 #include <linux/module.h>
13 #include <linux/init.h>
14 #include <linux/sched.h>
15 #include <linux/completion.h>
16 #include "cell.h"
17 #include "volume.h"
18 #include "kafstimod.h"
19 #include <asm/errno.h>
20 #include "internal.h"
21
22 static DECLARE_COMPLETION(kafstimod_alive);
23 static DECLARE_COMPLETION(kafstimod_dead);
24 static DECLARE_WAIT_QUEUE_HEAD(kafstimod_sleepq);
25 static int kafstimod_die;
26
27 static LIST_HEAD(kafstimod_list);
28 static DEFINE_SPINLOCK(kafstimod_lock);
29
30 static int kafstimod(void *arg);
31
32 /*****************************************************************************/
33 /*
34  * start the timeout daemon
35  */
36 int afs_kafstimod_start(void)
37 {
38         int ret;
39
40         ret = kernel_thread(kafstimod, NULL, 0);
41         if (ret < 0)
42                 return ret;
43
44         wait_for_completion(&kafstimod_alive);
45
46         return ret;
47 } /* end afs_kafstimod_start() */
48
49 /*****************************************************************************/
50 /*
51  * stop the timeout daemon
52  */
53 void afs_kafstimod_stop(void)
54 {
55         /* get rid of my daemon */
56         kafstimod_die = 1;
57         wake_up(&kafstimod_sleepq);
58         wait_for_completion(&kafstimod_dead);
59
60 } /* end afs_kafstimod_stop() */
61
62 /*****************************************************************************/
63 /*
64  * timeout processing daemon
65  */
66 static int kafstimod(void *arg)
67 {
68         struct afs_timer *timer;
69
70         DECLARE_WAITQUEUE(myself, current);
71
72         printk("kAFS: Started kafstimod %d\n", current->pid);
73
74         daemonize("kafstimod");
75
76         complete(&kafstimod_alive);
77
78         /* loop around looking for things to attend to */
79  loop:
80         set_current_state(TASK_INTERRUPTIBLE);
81         add_wait_queue(&kafstimod_sleepq, &myself);
82
83         for (;;) {
84                 unsigned long jif;
85                 signed long timeout;
86
87                 /* deal with the server being asked to die */
88                 if (kafstimod_die) {
89                         remove_wait_queue(&kafstimod_sleepq, &myself);
90                         _leave("");
91                         complete_and_exit(&kafstimod_dead, 0);
92                 }
93
94                 try_to_freeze();
95
96                 /* discard pending signals */
97                 afs_discard_my_signals();
98
99                 /* work out the time to elapse before the next event */
100                 spin_lock(&kafstimod_lock);
101                 if (list_empty(&kafstimod_list)) {
102                         timeout = MAX_SCHEDULE_TIMEOUT;
103                 }
104                 else {
105                         timer = list_entry(kafstimod_list.next,
106                                            struct afs_timer, link);
107                         timeout = timer->timo_jif;
108                         jif = jiffies;
109
110                         if (time_before_eq((unsigned long) timeout, jif))
111                                 goto immediate;
112
113                         else {
114                                 timeout = (long) timeout - (long) jiffies;
115                         }
116                 }
117                 spin_unlock(&kafstimod_lock);
118
119                 schedule_timeout(timeout);
120
121                 set_current_state(TASK_INTERRUPTIBLE);
122         }
123
124         /* the thing on the front of the queue needs processing
125          * - we come here with the lock held and timer pointing to the expired
126          *   entry
127          */
128  immediate:
129         remove_wait_queue(&kafstimod_sleepq, &myself);
130         set_current_state(TASK_RUNNING);
131
132         _debug("@@@ Begin Timeout of %p", timer);
133
134         /* dequeue the timer */
135         list_del_init(&timer->link);
136         spin_unlock(&kafstimod_lock);
137
138         /* call the timeout function */
139         timer->ops->timed_out(timer);
140
141         _debug("@@@ End Timeout");
142         goto loop;
143
144 } /* end kafstimod() */
145
146 /*****************************************************************************/
147 /*
148  * (re-)queue a timer
149  */
150 void afs_kafstimod_add_timer(struct afs_timer *timer, unsigned long timeout)
151 {
152         struct afs_timer *ptimer;
153         struct list_head *_p;
154
155         _enter("%p,%lu", timer, timeout);
156
157         spin_lock(&kafstimod_lock);
158
159         list_del(&timer->link);
160
161         /* the timer was deferred or reset - put it back in the queue at the
162          * right place */
163         timer->timo_jif = jiffies + timeout;
164
165         list_for_each(_p, &kafstimod_list) {
166                 ptimer = list_entry(_p, struct afs_timer, link);
167                 if (time_before(timer->timo_jif, ptimer->timo_jif))
168                         break;
169         }
170
171         list_add_tail(&timer->link, _p); /* insert before stopping point */
172
173         spin_unlock(&kafstimod_lock);
174
175         wake_up(&kafstimod_sleepq);
176
177         _leave("");
178 } /* end afs_kafstimod_add_timer() */
179
180 /*****************************************************************************/
181 /*
182  * dequeue a timer
183  * - returns 0 if the timer was deleted or -ENOENT if it wasn't queued
184  */
185 int afs_kafstimod_del_timer(struct afs_timer *timer)
186 {
187         int ret = 0;
188
189         _enter("%p", timer);
190
191         spin_lock(&kafstimod_lock);
192
193         if (list_empty(&timer->link))
194                 ret = -ENOENT;
195         else
196                 list_del_init(&timer->link);
197
198         spin_unlock(&kafstimod_lock);
199
200         wake_up(&kafstimod_sleepq);
201
202         _leave(" = %d", ret);
203         return ret;
204 } /* end afs_kafstimod_del_timer() */