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