Merge branch 'for_paulus' of master.kernel.org:/pub/scm/linux/kernel/git/galak/powerpc
[pandora-kernel.git] / fs / afs / server.c
1 /* server.c: AFS server record management
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/sched.h>
13 #include <linux/slab.h>
14 #include <rxrpc/peer.h>
15 #include <rxrpc/connection.h>
16 #include "volume.h"
17 #include "cell.h"
18 #include "server.h"
19 #include "transport.h"
20 #include "vlclient.h"
21 #include "kafstimod.h"
22 #include "internal.h"
23
24 DEFINE_SPINLOCK(afs_server_peer_lock);
25
26 #define FS_SERVICE_ID           1       /* AFS Volume Location Service ID */
27 #define VL_SERVICE_ID           52      /* AFS Volume Location Service ID */
28
29 static void __afs_server_timeout(struct afs_timer *timer)
30 {
31         struct afs_server *server =
32                 list_entry(timer, struct afs_server, timeout);
33
34         _debug("SERVER TIMEOUT [%p{u=%d}]",
35                server, atomic_read(&server->usage));
36
37         afs_server_do_timeout(server);
38 }
39
40 static const struct afs_timer_ops afs_server_timer_ops = {
41         .timed_out      = __afs_server_timeout,
42 };
43
44 /*****************************************************************************/
45 /*
46  * lookup a server record in a cell
47  * - TODO: search the cell's server list
48  */
49 int afs_server_lookup(struct afs_cell *cell, const struct in_addr *addr,
50                       struct afs_server **_server)
51 {
52         struct afs_server *server, *active, *zombie;
53         int loop;
54
55         _enter("%p,%08x,", cell, ntohl(addr->s_addr));
56
57         /* allocate and initialise a server record */
58         server = kmalloc(sizeof(struct afs_server), GFP_KERNEL);
59         if (!server) {
60                 _leave(" = -ENOMEM");
61                 return -ENOMEM;
62         }
63
64         memset(server, 0, sizeof(struct afs_server));
65         atomic_set(&server->usage, 1);
66
67         INIT_LIST_HEAD(&server->link);
68         init_rwsem(&server->sem);
69         INIT_LIST_HEAD(&server->fs_callq);
70         spin_lock_init(&server->fs_lock);
71         INIT_LIST_HEAD(&server->cb_promises);
72         spin_lock_init(&server->cb_lock);
73
74         for (loop = 0; loop < AFS_SERVER_CONN_LIST_SIZE; loop++)
75                 server->fs_conn_cnt[loop] = 4;
76
77         memcpy(&server->addr, addr, sizeof(struct in_addr));
78         server->addr.s_addr = addr->s_addr;
79
80         afs_timer_init(&server->timeout, &afs_server_timer_ops);
81
82         /* add to the cell */
83         write_lock(&cell->sv_lock);
84
85         /* check the active list */
86         list_for_each_entry(active, &cell->sv_list, link) {
87                 if (active->addr.s_addr == addr->s_addr)
88                         goto use_active_server;
89         }
90
91         /* check the inactive list */
92         spin_lock(&cell->sv_gylock);
93         list_for_each_entry(zombie, &cell->sv_graveyard, link) {
94                 if (zombie->addr.s_addr == addr->s_addr)
95                         goto resurrect_server;
96         }
97         spin_unlock(&cell->sv_gylock);
98
99         afs_get_cell(cell);
100         server->cell = cell;
101         list_add_tail(&server->link, &cell->sv_list);
102
103         write_unlock(&cell->sv_lock);
104
105         *_server = server;
106         _leave(" = 0 (%p)", server);
107         return 0;
108
109         /* found a matching active server */
110  use_active_server:
111         _debug("active server");
112         afs_get_server(active);
113         write_unlock(&cell->sv_lock);
114
115         kfree(server);
116
117         *_server = active;
118         _leave(" = 0 (%p)", active);
119         return 0;
120
121         /* found a matching server in the graveyard, so resurrect it and
122          * dispose of the new record */
123  resurrect_server:
124         _debug("resurrecting server");
125
126         list_move_tail(&zombie->link, &cell->sv_list);
127         afs_get_server(zombie);
128         afs_kafstimod_del_timer(&zombie->timeout);
129         spin_unlock(&cell->sv_gylock);
130         write_unlock(&cell->sv_lock);
131
132         kfree(server);
133
134         *_server = zombie;
135         _leave(" = 0 (%p)", zombie);
136         return 0;
137
138 } /* end afs_server_lookup() */
139
140 /*****************************************************************************/
141 /*
142  * destroy a server record
143  * - removes from the cell list
144  */
145 void afs_put_server(struct afs_server *server)
146 {
147         struct afs_cell *cell;
148
149         if (!server)
150                 return;
151
152         _enter("%p", server);
153
154         cell = server->cell;
155
156         /* sanity check */
157         BUG_ON(atomic_read(&server->usage) <= 0);
158
159         /* to prevent a race, the decrement and the dequeue must be effectively
160          * atomic */
161         write_lock(&cell->sv_lock);
162
163         if (likely(!atomic_dec_and_test(&server->usage))) {
164                 write_unlock(&cell->sv_lock);
165                 _leave("");
166                 return;
167         }
168
169         spin_lock(&cell->sv_gylock);
170         list_move_tail(&server->link, &cell->sv_graveyard);
171
172         /* time out in 10 secs */
173         afs_kafstimod_add_timer(&server->timeout, 10 * HZ);
174
175         spin_unlock(&cell->sv_gylock);
176         write_unlock(&cell->sv_lock);
177
178         _leave(" [killed]");
179 } /* end afs_put_server() */
180
181 /*****************************************************************************/
182 /*
183  * timeout server record
184  * - removes from the cell's graveyard if the usage count is zero
185  */
186 void afs_server_do_timeout(struct afs_server *server)
187 {
188         struct rxrpc_peer *peer;
189         struct afs_cell *cell;
190         int loop;
191
192         _enter("%p", server);
193
194         cell = server->cell;
195
196         BUG_ON(atomic_read(&server->usage) < 0);
197
198         /* remove from graveyard if still dead */
199         spin_lock(&cell->vl_gylock);
200         if (atomic_read(&server->usage) == 0)
201                 list_del_init(&server->link);
202         else
203                 server = NULL;
204         spin_unlock(&cell->vl_gylock);
205
206         if (!server) {
207                 _leave("");
208                 return; /* resurrected */
209         }
210
211         /* we can now destroy it properly */
212         afs_put_cell(cell);
213
214         /* uncross-point the structs under a global lock */
215         spin_lock(&afs_server_peer_lock);
216         peer = server->peer;
217         if (peer) {
218                 server->peer = NULL;
219                 peer->user = NULL;
220         }
221         spin_unlock(&afs_server_peer_lock);
222
223         /* finish cleaning up the server */
224         for (loop = AFS_SERVER_CONN_LIST_SIZE - 1; loop >= 0; loop--)
225                 if (server->fs_conn[loop])
226                         rxrpc_put_connection(server->fs_conn[loop]);
227
228         if (server->vlserver)
229                 rxrpc_put_connection(server->vlserver);
230
231         kfree(server);
232
233         _leave(" [destroyed]");
234 } /* end afs_server_do_timeout() */
235
236 /*****************************************************************************/
237 /*
238  * get a callslot on a connection to the fileserver on the specified server
239  */
240 int afs_server_request_callslot(struct afs_server *server,
241                                 struct afs_server_callslot *callslot)
242 {
243         struct afs_server_callslot *pcallslot;
244         struct rxrpc_connection *conn;
245         int nconn, ret;
246
247         _enter("%p,",server);
248
249         INIT_LIST_HEAD(&callslot->link);
250         callslot->task = current;
251         callslot->conn = NULL;
252         callslot->nconn = -1;
253         callslot->ready = 0;
254
255         ret = 0;
256         conn = NULL;
257
258         /* get hold of a callslot first */
259         spin_lock(&server->fs_lock);
260
261         /* resurrect the server if it's death timeout has expired */
262         if (server->fs_state) {
263                 if (time_before(jiffies, server->fs_dead_jif)) {
264                         ret = server->fs_state;
265                         spin_unlock(&server->fs_lock);
266                         _leave(" = %d [still dead]", ret);
267                         return ret;
268                 }
269
270                 server->fs_state = 0;
271         }
272
273         /* try and find a connection that has spare callslots */
274         for (nconn = 0; nconn < AFS_SERVER_CONN_LIST_SIZE; nconn++) {
275                 if (server->fs_conn_cnt[nconn] > 0) {
276                         server->fs_conn_cnt[nconn]--;
277                         spin_unlock(&server->fs_lock);
278                         callslot->nconn = nconn;
279                         goto obtained_slot;
280                 }
281         }
282
283         /* none were available - wait interruptibly for one to become
284          * available */
285         set_current_state(TASK_INTERRUPTIBLE);
286         list_add_tail(&callslot->link, &server->fs_callq);
287         spin_unlock(&server->fs_lock);
288
289         while (!callslot->ready && !signal_pending(current)) {
290                 schedule();
291                 set_current_state(TASK_INTERRUPTIBLE);
292         }
293
294         set_current_state(TASK_RUNNING);
295
296         /* even if we were interrupted we may still be queued */
297         if (!callslot->ready) {
298                 spin_lock(&server->fs_lock);
299                 list_del_init(&callslot->link);
300                 spin_unlock(&server->fs_lock);
301         }
302
303         nconn = callslot->nconn;
304
305         /* if interrupted, we must release any slot we also got before
306          * returning an error */
307         if (signal_pending(current)) {
308                 ret = -EINTR;
309                 goto error_release;
310         }
311
312         /* if we were woken up with an error, then pass that error back to the
313          * called */
314         if (nconn < 0) {
315                 _leave(" = %d", callslot->errno);
316                 return callslot->errno;
317         }
318
319         /* were we given a connection directly? */
320         if (callslot->conn) {
321                 /* yes - use it */
322                 _leave(" = 0 (nc=%d)", nconn);
323                 return 0;
324         }
325
326         /* got a callslot, but no connection */
327  obtained_slot:
328
329         /* need to get hold of the RxRPC connection */
330         down_write(&server->sem);
331
332         /* quick check to see if there's an outstanding error */
333         ret = server->fs_state;
334         if (ret)
335                 goto error_release_upw;
336
337         if (server->fs_conn[nconn]) {
338                 /* reuse an existing connection */
339                 rxrpc_get_connection(server->fs_conn[nconn]);
340                 callslot->conn = server->fs_conn[nconn];
341         }
342         else {
343                 /* create a new connection */
344                 ret = rxrpc_create_connection(afs_transport,
345                                               htons(7000),
346                                               server->addr.s_addr,
347                                               FS_SERVICE_ID,
348                                               NULL,
349                                               &server->fs_conn[nconn]);
350
351                 if (ret < 0)
352                         goto error_release_upw;
353
354                 callslot->conn = server->fs_conn[0];
355                 rxrpc_get_connection(callslot->conn);
356         }
357
358         up_write(&server->sem);
359
360         _leave(" = 0");
361         return 0;
362
363         /* handle an error occurring */
364  error_release_upw:
365         up_write(&server->sem);
366
367  error_release:
368         /* either release the callslot or pass it along to another deserving
369          * task */
370         spin_lock(&server->fs_lock);
371
372         if (nconn < 0) {
373                 /* no callslot allocated */
374         }
375         else if (list_empty(&server->fs_callq)) {
376                 /* no one waiting */
377                 server->fs_conn_cnt[nconn]++;
378                 spin_unlock(&server->fs_lock);
379         }
380         else {
381                 /* someone's waiting - dequeue them and wake them up */
382                 pcallslot = list_entry(server->fs_callq.next,
383                                        struct afs_server_callslot, link);
384                 list_del_init(&pcallslot->link);
385
386                 pcallslot->errno = server->fs_state;
387                 if (!pcallslot->errno) {
388                         /* pass them out callslot details */
389                         callslot->conn = xchg(&pcallslot->conn,
390                                               callslot->conn);
391                         pcallslot->nconn = nconn;
392                         callslot->nconn = nconn = -1;
393                 }
394                 pcallslot->ready = 1;
395                 wake_up_process(pcallslot->task);
396                 spin_unlock(&server->fs_lock);
397         }
398
399         rxrpc_put_connection(callslot->conn);
400         callslot->conn = NULL;
401
402         _leave(" = %d", ret);
403         return ret;
404
405 } /* end afs_server_request_callslot() */
406
407 /*****************************************************************************/
408 /*
409  * release a callslot back to the server
410  * - transfers the RxRPC connection to the next pending callslot if possible
411  */
412 void afs_server_release_callslot(struct afs_server *server,
413                                  struct afs_server_callslot *callslot)
414 {
415         struct afs_server_callslot *pcallslot;
416
417         _enter("{ad=%08x,cnt=%u},{%d}",
418                ntohl(server->addr.s_addr),
419                server->fs_conn_cnt[callslot->nconn],
420                callslot->nconn);
421
422         BUG_ON(callslot->nconn < 0);
423
424         spin_lock(&server->fs_lock);
425
426         if (list_empty(&server->fs_callq)) {
427                 /* no one waiting */
428                 server->fs_conn_cnt[callslot->nconn]++;
429                 spin_unlock(&server->fs_lock);
430         }
431         else {
432                 /* someone's waiting - dequeue them and wake them up */
433                 pcallslot = list_entry(server->fs_callq.next,
434                                        struct afs_server_callslot, link);
435                 list_del_init(&pcallslot->link);
436
437                 pcallslot->errno = server->fs_state;
438                 if (!pcallslot->errno) {
439                         /* pass them out callslot details */
440                         callslot->conn = xchg(&pcallslot->conn, callslot->conn);
441                         pcallslot->nconn = callslot->nconn;
442                         callslot->nconn = -1;
443                 }
444
445                 pcallslot->ready = 1;
446                 wake_up_process(pcallslot->task);
447                 spin_unlock(&server->fs_lock);
448         }
449
450         rxrpc_put_connection(callslot->conn);
451
452         _leave("");
453 } /* end afs_server_release_callslot() */
454
455 /*****************************************************************************/
456 /*
457  * get a handle to a connection to the vlserver (volume location) on the
458  * specified server
459  */
460 int afs_server_get_vlconn(struct afs_server *server,
461                           struct rxrpc_connection **_conn)
462 {
463         struct rxrpc_connection *conn;
464         int ret;
465
466         _enter("%p,", server);
467
468         ret = 0;
469         conn = NULL;
470         down_read(&server->sem);
471
472         if (server->vlserver) {
473                 /* reuse an existing connection */
474                 rxrpc_get_connection(server->vlserver);
475                 conn = server->vlserver;
476                 up_read(&server->sem);
477         }
478         else {
479                 /* create a new connection */
480                 up_read(&server->sem);
481                 down_write(&server->sem);
482                 if (!server->vlserver) {
483                         ret = rxrpc_create_connection(afs_transport,
484                                                       htons(7003),
485                                                       server->addr.s_addr,
486                                                       VL_SERVICE_ID,
487                                                       NULL,
488                                                       &server->vlserver);
489                 }
490                 if (ret == 0) {
491                         rxrpc_get_connection(server->vlserver);
492                         conn = server->vlserver;
493                 }
494                 up_write(&server->sem);
495         }
496
497         *_conn = conn;
498         _leave(" = %d", ret);
499         return ret;
500 } /* end afs_server_get_vlconn() */