[AFS]: Clean up the AFS sources
[linux-2.6.git] / fs / afs / kafsasyncd.c
1 /* 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  * 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 }
68
69 /*
70  * stop the async daemon
71  */
72 void afs_kafsasyncd_stop(void)
73 {
74         /* get rid of my daemon */
75         kafsasyncd_die = 1;
76         wake_up(&kafsasyncd_sleepq);
77         wait_for_completion(&kafsasyncd_dead);
78 }
79
80 /*
81  * probing daemon
82  */
83 static int kafsasyncd(void *arg)
84 {
85         struct afs_async_op *op;
86         int die;
87
88         DECLARE_WAITQUEUE(myself, current);
89
90         kafsasyncd_task = current;
91
92         printk("kAFS: Started kafsasyncd %d\n", current->pid);
93
94         daemonize("kafsasyncd");
95
96         complete(&kafsasyncd_alive);
97
98         /* loop around looking for things to attend to */
99         do {
100                 set_current_state(TASK_INTERRUPTIBLE);
101                 add_wait_queue(&kafsasyncd_sleepq, &myself);
102
103                 for (;;) {
104                         if (!list_empty(&kafsasyncd_async_attnq) ||
105                             signal_pending(current) ||
106                             kafsasyncd_die)
107                                 break;
108
109                         schedule();
110                         set_current_state(TASK_INTERRUPTIBLE);
111                 }
112
113                 remove_wait_queue(&kafsasyncd_sleepq, &myself);
114                 set_current_state(TASK_RUNNING);
115
116                 try_to_freeze();
117
118                 /* discard pending signals */
119                 afs_discard_my_signals();
120
121                 die = kafsasyncd_die;
122
123                 /* deal with the next asynchronous operation requiring
124                  * attention */
125                 if (!list_empty(&kafsasyncd_async_attnq)) {
126                         struct afs_async_op *op;
127
128                         _debug("@@@ Begin Asynchronous Operation");
129
130                         op = NULL;
131                         spin_lock(&kafsasyncd_async_lock);
132
133                         if (!list_empty(&kafsasyncd_async_attnq)) {
134                                 op = list_entry(kafsasyncd_async_attnq.next,
135                                                 struct afs_async_op, link);
136                                 list_move_tail(&op->link,
137                                               &kafsasyncd_async_busyq);
138                         }
139
140                         spin_unlock(&kafsasyncd_async_lock);
141
142                         _debug("@@@ Operation %p {%p}\n",
143                                op, op ? op->ops : NULL);
144
145                         if (op)
146                                 op->ops->attend(op);
147
148                         _debug("@@@ End Asynchronous Operation");
149                 }
150
151         } while(!die);
152
153         /* need to kill all outstanding asynchronous operations before
154          * exiting */
155         kafsasyncd_task = NULL;
156         spin_lock(&kafsasyncd_async_lock);
157
158         /* fold the busy and attention queues together */
159         list_splice_init(&kafsasyncd_async_busyq,
160                          &kafsasyncd_async_attnq);
161
162         /* dequeue kafsasyncd from all their wait queues */
163         list_for_each_entry(op, &kafsasyncd_async_attnq, link) {
164                 op->call->app_attn_func = kafsasyncd_null_call_attn_func;
165                 op->call->app_error_func = kafsasyncd_null_call_error_func;
166                 remove_wait_queue(&op->call->waitq, &op->waiter);
167         }
168
169         spin_unlock(&kafsasyncd_async_lock);
170
171         /* abort all the operations */
172         while (!list_empty(&kafsasyncd_async_attnq)) {
173                 op = list_entry(kafsasyncd_async_attnq.next, struct afs_async_op, link);
174                 list_del_init(&op->link);
175
176                 rxrpc_call_abort(op->call, -EIO);
177                 rxrpc_put_call(op->call);
178                 op->call = NULL;
179
180                 op->ops->discard(op);
181         }
182
183         /* and that's all */
184         _leave("");
185         complete_and_exit(&kafsasyncd_dead, 0);
186 }
187
188 /*
189  * begin an operation
190  * - place operation on busy queue
191  */
192 void afs_kafsasyncd_begin_op(struct afs_async_op *op)
193 {
194         _enter("");
195
196         spin_lock(&kafsasyncd_async_lock);
197
198         init_waitqueue_entry(&op->waiter, kafsasyncd_task);
199         add_wait_queue(&op->call->waitq, &op->waiter);
200
201         list_move_tail(&op->link, &kafsasyncd_async_busyq);
202
203         spin_unlock(&kafsasyncd_async_lock);
204
205         _leave("");
206 }
207
208 /*
209  * request attention for an operation
210  * - move to attention queue
211  */
212 void afs_kafsasyncd_attend_op(struct afs_async_op *op)
213 {
214         _enter("");
215
216         spin_lock(&kafsasyncd_async_lock);
217
218         list_move_tail(&op->link, &kafsasyncd_async_attnq);
219
220         spin_unlock(&kafsasyncd_async_lock);
221
222         wake_up(&kafsasyncd_sleepq);
223
224         _leave("");
225 }
226
227 /*
228  * terminate an operation
229  * - remove from either queue
230  */
231 void afs_kafsasyncd_terminate_op(struct afs_async_op *op)
232 {
233         _enter("");
234
235         spin_lock(&kafsasyncd_async_lock);
236
237         if (!list_empty(&op->link)) {
238                 list_del_init(&op->link);
239                 remove_wait_queue(&op->call->waitq, &op->waiter);
240         }
241
242         spin_unlock(&kafsasyncd_async_lock);
243
244         wake_up(&kafsasyncd_sleepq);
245
246         _leave("");
247 }