Merge branch 'intx' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/misc-2.6
[pandora-kernel.git] / 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 <linux/freezer.h>
24 #include "cell.h"
25 #include "server.h"
26 #include "volume.h"
27 #include "kafsasyncd.h"
28 #include "kafstimod.h"
29 #include <rxrpc/call.h>
30 #include <asm/errno.h>
31 #include "internal.h"
32
33 static DECLARE_COMPLETION(kafsasyncd_alive);
34 static DECLARE_COMPLETION(kafsasyncd_dead);
35 static DECLARE_WAIT_QUEUE_HEAD(kafsasyncd_sleepq);
36 static struct task_struct *kafsasyncd_task;
37 static int kafsasyncd_die;
38
39 static int kafsasyncd(void *arg);
40
41 static LIST_HEAD(kafsasyncd_async_attnq);
42 static LIST_HEAD(kafsasyncd_async_busyq);
43 static DEFINE_SPINLOCK(kafsasyncd_async_lock);
44
45 static void kafsasyncd_null_call_attn_func(struct rxrpc_call *call)
46 {
47 }
48
49 static void kafsasyncd_null_call_error_func(struct rxrpc_call *call)
50 {
51 }
52
53 /*****************************************************************************/
54 /*
55  * start the async daemon
56  */
57 int afs_kafsasyncd_start(void)
58 {
59         int ret;
60
61         ret = kernel_thread(kafsasyncd, NULL, 0);
62         if (ret < 0)
63                 return ret;
64
65         wait_for_completion(&kafsasyncd_alive);
66
67         return ret;
68 } /* end afs_kafsasyncd_start() */
69
70 /*****************************************************************************/
71 /*
72  * stop the async daemon
73  */
74 void afs_kafsasyncd_stop(void)
75 {
76         /* get rid of my daemon */
77         kafsasyncd_die = 1;
78         wake_up(&kafsasyncd_sleepq);
79         wait_for_completion(&kafsasyncd_dead);
80
81 } /* end afs_kafsasyncd_stop() */
82
83 /*****************************************************************************/
84 /*
85  * probing daemon
86  */
87 static int kafsasyncd(void *arg)
88 {
89         struct afs_async_op *op;
90         int die;
91
92         DECLARE_WAITQUEUE(myself, current);
93
94         kafsasyncd_task = current;
95
96         printk("kAFS: Started kafsasyncd %d\n", current->pid);
97
98         daemonize("kafsasyncd");
99
100         complete(&kafsasyncd_alive);
101
102         /* loop around looking for things to attend to */
103         do {
104                 set_current_state(TASK_INTERRUPTIBLE);
105                 add_wait_queue(&kafsasyncd_sleepq, &myself);
106
107                 for (;;) {
108                         if (!list_empty(&kafsasyncd_async_attnq) ||
109                             signal_pending(current) ||
110                             kafsasyncd_die)
111                                 break;
112
113                         schedule();
114                         set_current_state(TASK_INTERRUPTIBLE);
115                 }
116
117                 remove_wait_queue(&kafsasyncd_sleepq, &myself);
118                 set_current_state(TASK_RUNNING);
119
120                 try_to_freeze();
121
122                 /* discard pending signals */
123                 afs_discard_my_signals();
124
125                 die = kafsasyncd_die;
126
127                 /* deal with the next asynchronous operation requiring
128                  * attention */
129                 if (!list_empty(&kafsasyncd_async_attnq)) {
130                         struct afs_async_op *op;
131
132                         _debug("@@@ Begin Asynchronous Operation");
133
134                         op = NULL;
135                         spin_lock(&kafsasyncd_async_lock);
136
137                         if (!list_empty(&kafsasyncd_async_attnq)) {
138                                 op = list_entry(kafsasyncd_async_attnq.next,
139                                                 struct afs_async_op, link);
140                                 list_move_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_move_tail(&op->link, &kafsasyncd_async_busyq);
208
209         spin_unlock(&kafsasyncd_async_lock);
210
211         _leave("");
212 } /* end afs_kafsasyncd_begin_op() */
213
214 /*****************************************************************************/
215 /*
216  * request attention for an operation
217  * - move to attention queue
218  */
219 void afs_kafsasyncd_attend_op(struct afs_async_op *op)
220 {
221         _enter("");
222
223         spin_lock(&kafsasyncd_async_lock);
224
225         list_move_tail(&op->link, &kafsasyncd_async_attnq);
226
227         spin_unlock(&kafsasyncd_async_lock);
228
229         wake_up(&kafsasyncd_sleepq);
230
231         _leave("");
232 } /* end afs_kafsasyncd_attend_op() */
233
234 /*****************************************************************************/
235 /*
236  * terminate an operation
237  * - remove from either queue
238  */
239 void afs_kafsasyncd_terminate_op(struct afs_async_op *op)
240 {
241         _enter("");
242
243         spin_lock(&kafsasyncd_async_lock);
244
245         if (!list_empty(&op->link)) {
246                 list_del_init(&op->link);
247                 remove_wait_queue(&op->call->waitq, &op->waiter);
248         }
249
250         spin_unlock(&kafsasyncd_async_lock);
251
252         wake_up(&kafsasyncd_sleepq);
253
254         _leave("");
255 } /* end afs_kafsasyncd_terminate_op() */