Merge master.kernel.org:/home/rmk/linux-2.6-arm
[linux-2.6] / fs / afs / kafsasyncd.c
1 /* kafsasyncd.c: AFS asynchronous operation 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  * The AFS async daemon is used to the following:
13  * - probe "dead" servers to see whether they've come back to life yet.
14  * - probe "live" servers that we haven't talked to for a while to see if they are better
15  *   candidates for serving than what we're currently using
16  * - poll volume location servers to keep up to date volume location lists
17  */
18
19 #include <linux/module.h>
20 #include <linux/init.h>
21 #include <linux/sched.h>
22 #include <linux/completion.h>
23 #include "cell.h"
24 #include "server.h"
25 #include "volume.h"
26 #include "kafsasyncd.h"
27 #include "kafstimod.h"
28 #include <rxrpc/call.h>
29 #include <asm/errno.h>
30 #include "internal.h"
31
32 static DECLARE_COMPLETION(kafsasyncd_alive);
33 static DECLARE_COMPLETION(kafsasyncd_dead);
34 static DECLARE_WAIT_QUEUE_HEAD(kafsasyncd_sleepq);
35 static struct task_struct *kafsasyncd_task;
36 static int kafsasyncd_die;
37
38 static int kafsasyncd(void *arg);
39
40 static LIST_HEAD(kafsasyncd_async_attnq);
41 static LIST_HEAD(kafsasyncd_async_busyq);
42 static DEFINE_SPINLOCK(kafsasyncd_async_lock);
43
44 static void kafsasyncd_null_call_attn_func(struct rxrpc_call *call)
45 {
46 }
47
48 static void kafsasyncd_null_call_error_func(struct rxrpc_call *call)
49 {
50 }
51
52 /*****************************************************************************/
53 /*
54  * start the async daemon
55  */
56 int afs_kafsasyncd_start(void)
57 {
58         int ret;
59
60         ret = kernel_thread(kafsasyncd, NULL, 0);
61         if (ret < 0)
62                 return ret;
63
64         wait_for_completion(&kafsasyncd_alive);
65
66         return ret;
67 } /* end afs_kafsasyncd_start() */
68
69 /*****************************************************************************/
70 /*
71  * stop the async daemon
72  */
73 void afs_kafsasyncd_stop(void)
74 {
75         /* get rid of my daemon */
76         kafsasyncd_die = 1;
77         wake_up(&kafsasyncd_sleepq);
78         wait_for_completion(&kafsasyncd_dead);
79
80 } /* end afs_kafsasyncd_stop() */
81
82 /*****************************************************************************/
83 /*
84  * probing daemon
85  */
86 static int kafsasyncd(void *arg)
87 {
88         struct afs_async_op *op;
89         int die;
90
91         DECLARE_WAITQUEUE(myself, current);
92
93         kafsasyncd_task = current;
94
95         printk("kAFS: Started kafsasyncd %d\n", current->pid);
96
97         daemonize("kafsasyncd");
98
99         complete(&kafsasyncd_alive);
100
101         /* loop around looking for things to attend to */
102         do {
103                 set_current_state(TASK_INTERRUPTIBLE);
104                 add_wait_queue(&kafsasyncd_sleepq, &myself);
105
106                 for (;;) {
107                         if (!list_empty(&kafsasyncd_async_attnq) ||
108                             signal_pending(current) ||
109                             kafsasyncd_die)
110                                 break;
111
112                         schedule();
113                         set_current_state(TASK_INTERRUPTIBLE);
114                 }
115
116                 remove_wait_queue(&kafsasyncd_sleepq, &myself);
117                 set_current_state(TASK_RUNNING);
118
119                 try_to_freeze();
120
121                 /* discard pending signals */
122                 afs_discard_my_signals();
123
124                 die = kafsasyncd_die;
125
126                 /* deal with the next asynchronous operation requiring
127                  * attention */
128                 if (!list_empty(&kafsasyncd_async_attnq)) {
129                         struct afs_async_op *op;
130
131                         _debug("@@@ Begin Asynchronous Operation");
132
133                         op = NULL;
134                         spin_lock(&kafsasyncd_async_lock);
135
136                         if (!list_empty(&kafsasyncd_async_attnq)) {
137                                 op = list_entry(kafsasyncd_async_attnq.next,
138                                                 struct afs_async_op, link);
139                                 list_del(&op->link);
140                                 list_add_tail(&op->link,
141                                               &kafsasyncd_async_busyq);
142                         }
143
144                         spin_unlock(&kafsasyncd_async_lock);
145
146                         _debug("@@@ Operation %p {%p}\n",
147                                op, op ? op->ops : NULL);
148
149                         if (op)
150                                 op->ops->attend(op);
151
152                         _debug("@@@ End Asynchronous Operation");
153                 }
154
155         } while(!die);
156
157         /* need to kill all outstanding asynchronous operations before
158          * exiting */
159         kafsasyncd_task = NULL;
160         spin_lock(&kafsasyncd_async_lock);
161
162         /* fold the busy and attention queues together */
163         list_splice_init(&kafsasyncd_async_busyq,
164                          &kafsasyncd_async_attnq);
165
166         /* dequeue kafsasyncd from all their wait queues */
167         list_for_each_entry(op, &kafsasyncd_async_attnq, link) {
168                 op->call->app_attn_func = kafsasyncd_null_call_attn_func;
169                 op->call->app_error_func = kafsasyncd_null_call_error_func;
170                 remove_wait_queue(&op->call->waitq, &op->waiter);
171         }
172
173         spin_unlock(&kafsasyncd_async_lock);
174
175         /* abort all the operations */
176         while (!list_empty(&kafsasyncd_async_attnq)) {
177                 op = list_entry(kafsasyncd_async_attnq.next, struct afs_async_op, link);
178                 list_del_init(&op->link);
179
180                 rxrpc_call_abort(op->call, -EIO);
181                 rxrpc_put_call(op->call);
182                 op->call = NULL;
183
184                 op->ops->discard(op);
185         }
186
187         /* and that's all */
188         _leave("");
189         complete_and_exit(&kafsasyncd_dead, 0);
190
191 } /* end kafsasyncd() */
192
193 /*****************************************************************************/
194 /*
195  * begin an operation
196  * - place operation on busy queue
197  */
198 void afs_kafsasyncd_begin_op(struct afs_async_op *op)
199 {
200         _enter("");
201
202         spin_lock(&kafsasyncd_async_lock);
203
204         init_waitqueue_entry(&op->waiter, kafsasyncd_task);
205         add_wait_queue(&op->call->waitq, &op->waiter);
206
207         list_del(&op->link);
208         list_add_tail(&op->link, &kafsasyncd_async_busyq);
209
210         spin_unlock(&kafsasyncd_async_lock);
211
212         _leave("");
213 } /* end afs_kafsasyncd_begin_op() */
214
215 /*****************************************************************************/
216 /*
217  * request attention for an operation
218  * - move to attention queue
219  */
220 void afs_kafsasyncd_attend_op(struct afs_async_op *op)
221 {
222         _enter("");
223
224         spin_lock(&kafsasyncd_async_lock);
225
226         list_del(&op->link);
227         list_add_tail(&op->link, &kafsasyncd_async_attnq);
228
229         spin_unlock(&kafsasyncd_async_lock);
230
231         wake_up(&kafsasyncd_sleepq);
232
233         _leave("");
234 } /* end afs_kafsasyncd_attend_op() */
235
236 /*****************************************************************************/
237 /*
238  * terminate an operation
239  * - remove from either queue
240  */
241 void afs_kafsasyncd_terminate_op(struct afs_async_op *op)
242 {
243         _enter("");
244
245         spin_lock(&kafsasyncd_async_lock);
246
247         if (!list_empty(&op->link)) {
248                 list_del_init(&op->link);
249                 remove_wait_queue(&op->call->waitq, &op->waiter);
250         }
251
252         spin_unlock(&kafsasyncd_async_lock);
253
254         wake_up(&kafsasyncd_sleepq);
255
256         _leave("");
257 } /* end afs_kafsasyncd_terminate_op() */