[AF_RXRPC]: Add an interface to the AF_RXRPC module for the AFS filesystem to use
[linux-2.6-block.git] / fs / afs / server.c
CommitLineData
ec26815a 1/* AFS server record management
1da177e4
LT
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
24DEFINE_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
29static 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
40static const struct afs_timer_ops afs_server_timer_ops = {
41 .timed_out = __afs_server_timeout,
42};
43
1da177e4
LT
44/*
45 * lookup a server record in a cell
46 * - TODO: search the cell's server list
47 */
48int 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 */
b593e48d 57 server = kzalloc(sizeof(struct afs_server), GFP_KERNEL);
1da177e4
LT
58 if (!server) {
59 _leave(" = -ENOMEM");
60 return -ENOMEM;
61 }
62
1da177e4
LT
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 */
ec26815a 108use_active_server:
1da177e4
LT
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 */
ec26815a 121resurrect_server:
1da177e4
LT
122 _debug("resurrecting server");
123
f116629d 124 list_move_tail(&zombie->link, &cell->sv_list);
1da177e4
LT
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;
ec26815a 135}
1da177e4 136
1da177e4
LT
137/*
138 * destroy a server record
139 * - removes from the cell list
140 */
141void 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);
f116629d 166 list_move_tail(&server->link, &cell->sv_graveyard);
1da177e4
LT
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]");
ec26815a 175}
1da177e4 176
1da177e4
LT
177/*
178 * timeout server record
179 * - removes from the cell's graveyard if the usage count is zero
180 */
181void 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]");
ec26815a 229}
1da177e4 230
1da177e4
LT
231/*
232 * get a callslot on a connection to the fileserver on the specified server
233 */
234int 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 */
ec26815a 321obtained_slot:
1da177e4
LT
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];
ec26815a 335 } else {
1da177e4
LT
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 */
ec26815a 357error_release_upw:
1da177e4
LT
358 up_write(&server->sem);
359
ec26815a 360error_release:
1da177e4
LT
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 */
ec26815a 367 } else if (list_empty(&server->fs_callq)) {
1da177e4
LT
368 /* no one waiting */
369 server->fs_conn_cnt[nconn]++;
370 spin_unlock(&server->fs_lock);
ec26815a 371 } else {
1da177e4
LT
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;
ec26815a 395}
1da177e4 396
1da177e4
LT
397/*
398 * release a callslot back to the server
399 * - transfers the RxRPC connection to the next pending callslot if possible
400 */
401void 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);
ec26815a 419 } else {
1da177e4
LT
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("");
ec26815a 441}
1da177e4 442
1da177e4
LT
443/*
444 * get a handle to a connection to the vlserver (volume location) on the
445 * specified server
446 */
447int 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);
ec26815a 464 } else {
1da177e4
LT
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;
ec26815a 486}