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