]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - fs/afs/kafstimod.c
[AF_RXRPC]: Add an interface to the AF_RXRPC module for the AFS filesystem to use
[linux-2.6-omap-h63xx.git] / fs / afs / kafstimod.c
1 /* 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 <linux/freezer.h>
17 #include "cell.h"
18 #include "volume.h"
19 #include "kafstimod.h"
20 #include <asm/errno.h>
21 #include "internal.h"
22
23 static DECLARE_COMPLETION(kafstimod_alive);
24 static DECLARE_COMPLETION(kafstimod_dead);
25 static DECLARE_WAIT_QUEUE_HEAD(kafstimod_sleepq);
26 static int kafstimod_die;
27
28 static LIST_HEAD(kafstimod_list);
29 static DEFINE_SPINLOCK(kafstimod_lock);
30
31 static int kafstimod(void *arg);
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 }
48
49 /*
50  * stop the timeout daemon
51  */
52 void afs_kafstimod_stop(void)
53 {
54         /* get rid of my daemon */
55         kafstimod_die = 1;
56         wake_up(&kafstimod_sleepq);
57         wait_for_completion(&kafstimod_dead);
58 }
59
60 /*
61  * timeout processing daemon
62  */
63 static int kafstimod(void *arg)
64 {
65         struct afs_timer *timer;
66
67         DECLARE_WAITQUEUE(myself, current);
68
69         printk("kAFS: Started kafstimod %d\n", current->pid);
70
71         daemonize("kafstimod");
72
73         complete(&kafstimod_alive);
74
75         /* loop around looking for things to attend to */
76 loop:
77         set_current_state(TASK_INTERRUPTIBLE);
78         add_wait_queue(&kafstimod_sleepq, &myself);
79
80         for (;;) {
81                 unsigned long jif;
82                 signed long timeout;
83
84                 /* deal with the server being asked to die */
85                 if (kafstimod_die) {
86                         remove_wait_queue(&kafstimod_sleepq, &myself);
87                         _leave("");
88                         complete_and_exit(&kafstimod_dead, 0);
89                 }
90
91                 try_to_freeze();
92
93                 /* discard pending signals */
94                 afs_discard_my_signals();
95
96                 /* work out the time to elapse before the next event */
97                 spin_lock(&kafstimod_lock);
98                 if (list_empty(&kafstimod_list)) {
99                         timeout = MAX_SCHEDULE_TIMEOUT;
100                 } else {
101                         timer = list_entry(kafstimod_list.next,
102                                            struct afs_timer, link);
103                         timeout = timer->timo_jif;
104                         jif = jiffies;
105
106                         if (time_before_eq((unsigned long) timeout, jif))
107                                 goto immediate;
108                         timeout = (long) timeout - (long) jiffies;
109                 }
110                 spin_unlock(&kafstimod_lock);
111
112                 schedule_timeout(timeout);
113
114                 set_current_state(TASK_INTERRUPTIBLE);
115         }
116
117         /* the thing on the front of the queue needs processing
118          * - we come here with the lock held and timer pointing to the expired
119          *   entry
120          */
121 immediate:
122         remove_wait_queue(&kafstimod_sleepq, &myself);
123         set_current_state(TASK_RUNNING);
124
125         _debug("@@@ Begin Timeout of %p", timer);
126
127         /* dequeue the timer */
128         list_del_init(&timer->link);
129         spin_unlock(&kafstimod_lock);
130
131         /* call the timeout function */
132         timer->ops->timed_out(timer);
133
134         _debug("@@@ End Timeout");
135         goto loop;
136 }
137
138 /*
139  * (re-)queue a timer
140  */
141 void afs_kafstimod_add_timer(struct afs_timer *timer, unsigned long timeout)
142 {
143         struct afs_timer *ptimer;
144         struct list_head *_p;
145
146         _enter("%p,%lu", timer, timeout);
147
148         spin_lock(&kafstimod_lock);
149
150         list_del(&timer->link);
151
152         /* the timer was deferred or reset - put it back in the queue at the
153          * right place */
154         timer->timo_jif = jiffies + timeout;
155
156         list_for_each(_p, &kafstimod_list) {
157                 ptimer = list_entry(_p, struct afs_timer, link);
158                 if (time_before(timer->timo_jif, ptimer->timo_jif))
159                         break;
160         }
161
162         list_add_tail(&timer->link, _p); /* insert before stopping point */
163
164         spin_unlock(&kafstimod_lock);
165
166         wake_up(&kafstimod_sleepq);
167
168         _leave("");
169 }
170
171 /*
172  * dequeue a timer
173  * - returns 0 if the timer was deleted or -ENOENT if it wasn't queued
174  */
175 int afs_kafstimod_del_timer(struct afs_timer *timer)
176 {
177         int ret = 0;
178
179         _enter("%p", timer);
180
181         spin_lock(&kafstimod_lock);
182
183         if (list_empty(&timer->link))
184                 ret = -ENOENT;
185         else
186                 list_del_init(&timer->link);
187
188         spin_unlock(&kafstimod_lock);
189
190         wake_up(&kafstimod_sleepq);
191
192         _leave(" = %d", ret);
193         return ret;
194 }