blob: 22afaae1a4ce53417d3e52900817d25245f99395 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* 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
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
44/*****************************************************************************/
45/*
46 * lookup a server record in a cell
47 * - TODO: search the cell's server list
48 */
49int 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
Akinobu Mitaf1166292006-06-26 00:24:46 -0700126 list_move_tail(&zombie->link, &cell->sv_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 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 */
145void 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);
Akinobu Mitaf1166292006-06-26 00:24:46 -0700170 list_move_tail(&server->link, &cell->sv_graveyard);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171
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 */
186void 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 */
240int 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 */
412void 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 */
460int 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() */