Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6
[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_move_tail(&op->link,
140                                               &kafsasyncd_async_busyq);
141                         }
142
143                         spin_unlock(&kafsasyncd_async_lock);
144
145                         _debug("@@@ Operation %p {%p}\n",
146                                op, op ? op->ops : NULL);
147
148                         if (op)
149                                 op->ops->attend(op);
150
151                         _debug("@@@ End Asynchronous Operation");
152                 }
153
154         } while(!die);
155
156         /* need to kill all outstanding asynchronous operations before
157          * exiting */
158         kafsasyncd_task = NULL;
159         spin_lock(&kafsasyncd_async_lock);
160
161         /* fold the busy and attention queues together */
162         list_splice_init(&kafsasyncd_async_busyq,
163                          &kafsasyncd_async_attnq);
164
165         /* dequeue kafsasyncd from all their wait queues */
166         list_for_each_entry(op, &kafsasyncd_async_attnq, link) {
167                 op->call->app_attn_func = kafsasyncd_null_call_attn_func;
168                 op->call->app_error_func = kafsasyncd_null_call_error_func;
169                 remove_wait_queue(&op->call->waitq, &op->waiter);
170         }
171
172         spin_unlock(&kafsasyncd_async_lock);
173
174         /* abort all the operations */
175         while (!list_empty(&kafsasyncd_async_attnq)) {
176                 op = list_entry(kafsasyncd_async_attnq.next, struct afs_async_op, link);
177                 list_del_init(&op->link);
178
179                 rxrpc_call_abort(op->call, -EIO);
180                 rxrpc_put_call(op->call);
181                 op->call = NULL;
182
183                 op->ops->discard(op);
184         }
185
186         /* and that's all */
187         _leave("");
188         complete_and_exit(&kafsasyncd_dead, 0);
189
190 } /* end kafsasyncd() */
191
192 /*****************************************************************************/
193 /*
194  * begin an operation
195  * - place operation on busy queue
196  */
197 void afs_kafsasyncd_begin_op(struct afs_async_op *op)
198 {
199         _enter("");
200
201         spin_lock(&kafsasyncd_async_lock);
202
203         init_waitqueue_entry(&op->waiter, kafsasyncd_task);
204         add_wait_queue(&op->call->waitq, &op->waiter);
205
206         list_move_tail(&op->link, &kafsasyncd_async_busyq);
207
208         spin_unlock(&kafsasyncd_async_lock);
209
210         _leave("");
211 } /* end afs_kafsasyncd_begin_op() */
212
213 /*****************************************************************************/
214 /*
215  * request attention for an operation
216  * - move to attention queue
217  */
218 void afs_kafsasyncd_attend_op(struct afs_async_op *op)
219 {
220         _enter("");
221
222         spin_lock(&kafsasyncd_async_lock);
223
224         list_move_tail(&op->link, &kafsasyncd_async_attnq);
225
226         spin_unlock(&kafsasyncd_async_lock);
227
228         wake_up(&kafsasyncd_sleepq);
229
230         _leave("");
231 } /* end afs_kafsasyncd_attend_op() */
232
233 /*****************************************************************************/
234 /*
235  * terminate an operation
236  * - remove from either queue
237  */
238 void afs_kafsasyncd_terminate_op(struct afs_async_op *op)
239 {
240         _enter("");
241
242         spin_lock(&kafsasyncd_async_lock);
243
244         if (!list_empty(&op->link)) {
245                 list_del_init(&op->link);
246                 remove_wait_queue(&op->call->waitq, &op->waiter);
247         }
248
249         spin_unlock(&kafsasyncd_async_lock);
250
251         wake_up(&kafsasyncd_sleepq);
252
253         _leave("");
254 } /* end afs_kafsasyncd_terminate_op() */