Merge to Fedora kernel-2.6.18-1.2224_FC5 patched with stable patch-2.6.18.1-vs2.0...
[linux-2.6.git] / fs / afs / cell.c
1 /* cell.c: AFS cell and 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/module.h>
13 #include <linux/sched.h>
14 #include <linux/slab.h>
15 #include <rxrpc/peer.h>
16 #include <rxrpc/connection.h>
17 #include "volume.h"
18 #include "cell.h"
19 #include "server.h"
20 #include "transport.h"
21 #include "vlclient.h"
22 #include "kafstimod.h"
23 #include "super.h"
24 #include "internal.h"
25
26 DECLARE_RWSEM(afs_proc_cells_sem);
27 LIST_HEAD(afs_proc_cells);
28
29 static struct list_head afs_cells = LIST_HEAD_INIT(afs_cells);
30 static DEFINE_RWLOCK(afs_cells_lock);
31 static DECLARE_RWSEM(afs_cells_sem); /* add/remove serialisation */
32 static struct afs_cell *afs_cell_root;
33
34 #ifdef CONFIG_AFS_FSCACHE
35 static uint16_t afs_cell_cache_get_key(const void *cookie_netfs_data,
36                                        void *buffer, uint16_t buflen);
37 static uint16_t afs_cell_cache_get_aux(const void *cookie_netfs_data,
38                                        void *buffer, uint16_t buflen);
39 static fscache_checkaux_t afs_cell_cache_check_aux(void *cookie_netfs_data,
40                                                    const void *buffer,
41                                                    uint16_t buflen);
42
43 static struct fscache_cookie_def afs_cell_cache_index_def = {
44         .name           = "AFS cell",
45         .type           = FSCACHE_COOKIE_TYPE_INDEX,
46         .get_key        = afs_cell_cache_get_key,
47         .get_aux        = afs_cell_cache_get_aux,
48         .check_aux      = afs_cell_cache_check_aux,
49 };
50 #endif
51
52 /*****************************************************************************/
53 /*
54  * create a cell record
55  * - "name" is the name of the cell
56  * - "vllist" is a colon separated list of IP addresses in "a.b.c.d" format
57  */
58 int afs_cell_create(const char *name, char *vllist, struct afs_cell **_cell)
59 {
60         struct afs_cell *cell;
61         char *next;
62         int ret;
63
64         _enter("%s", name);
65
66         BUG_ON(!name); /* TODO: want to look up "this cell" in the cache */
67
68         /* allocate and initialise a cell record */
69         cell = kmalloc(sizeof(struct afs_cell) + strlen(name) + 1, GFP_KERNEL);
70         if (!cell) {
71                 _leave(" = -ENOMEM");
72                 return -ENOMEM;
73         }
74
75         down_write(&afs_cells_sem);
76
77         memset(cell, 0, sizeof(struct afs_cell));
78         atomic_set(&cell->usage, 0);
79
80         INIT_LIST_HEAD(&cell->link);
81
82         rwlock_init(&cell->sv_lock);
83         INIT_LIST_HEAD(&cell->sv_list);
84         INIT_LIST_HEAD(&cell->sv_graveyard);
85         spin_lock_init(&cell->sv_gylock);
86
87         init_rwsem(&cell->vl_sem);
88         INIT_LIST_HEAD(&cell->vl_list);
89         INIT_LIST_HEAD(&cell->vl_graveyard);
90         spin_lock_init(&cell->vl_gylock);
91
92         strcpy(cell->name,name);
93
94         /* fill in the VL server list from the rest of the string */
95         ret = -EINVAL;
96         do {
97                 unsigned a, b, c, d;
98
99                 next = strchr(vllist, ':');
100                 if (next)
101                         *next++ = 0;
102
103                 if (sscanf(vllist, "%u.%u.%u.%u", &a, &b, &c, &d) != 4)
104                         goto badaddr;
105
106                 if (a > 255 || b > 255 || c > 255 || d > 255)
107                         goto badaddr;
108
109                 cell->vl_addrs[cell->vl_naddrs++].s_addr =
110                         htonl((a << 24) | (b << 16) | (c << 8) | d);
111
112                 if (cell->vl_naddrs >= AFS_CELL_MAX_ADDRS)
113                         break;
114
115         } while(vllist = next, vllist);
116
117         /* add a proc dir for this cell */
118         ret = afs_proc_cell_setup(cell);
119         if (ret < 0)
120                 goto error;
121
122 #ifdef CONFIG_AFS_FSCACHE
123         /* put it up for caching (this never returns an error) */
124         cell->cache = fscache_acquire_cookie(afs_cache_netfs.primary_index,
125                                              &afs_cell_cache_index_def,
126                                              cell);
127 #endif
128
129         /* add to the cell lists */
130         write_lock(&afs_cells_lock);
131         list_add_tail(&cell->link, &afs_cells);
132         write_unlock(&afs_cells_lock);
133
134         down_write(&afs_proc_cells_sem);
135         list_add_tail(&cell->proc_link, &afs_proc_cells);
136         up_write(&afs_proc_cells_sem);
137
138         *_cell = cell;
139         up_write(&afs_cells_sem);
140
141         _leave(" = 0 (%p)", cell);
142         return 0;
143
144  badaddr:
145         printk(KERN_ERR "kAFS: bad VL server IP address: '%s'\n", vllist);
146  error:
147         up_write(&afs_cells_sem);
148         kfree(cell);
149         _leave(" = %d", ret);
150         return ret;
151 } /* end afs_cell_create() */
152
153 /*****************************************************************************/
154 /*
155  * initialise the cell database from module parameters
156  */
157 int afs_cell_init(char *rootcell)
158 {
159         struct afs_cell *old_root, *new_root;
160         char *cp;
161         int ret;
162
163         _enter("");
164
165         if (!rootcell) {
166                 /* module is loaded with no parameters, or built statically.
167                  * - in the future we might initialize cell DB here.
168                  */
169                 _leave(" = 0 (but no root)");
170                 return 0;
171         }
172
173         cp = strchr(rootcell, ':');
174         if (!cp) {
175                 printk(KERN_ERR "kAFS: no VL server IP addresses specified\n");
176                 _leave(" = %d (no colon)", -EINVAL);
177                 return -EINVAL;
178         }
179
180         /* allocate a cell record for the root cell */
181         *cp++ = 0;
182         ret = afs_cell_create(rootcell, cp, &new_root);
183         if (ret < 0) {
184                 _leave(" = %d", ret);
185                 return ret;
186         }
187
188         /* as afs_put_cell() takes locks by itself, we have to do
189          * a little gymnastics to be race-free.
190          */
191         afs_get_cell(new_root);
192
193         write_lock(&afs_cells_lock);
194         while (afs_cell_root) {
195                 old_root = afs_cell_root;
196                 afs_cell_root = NULL;
197                 write_unlock(&afs_cells_lock);
198                 afs_put_cell(old_root);
199                 write_lock(&afs_cells_lock);
200         }
201         afs_cell_root = new_root;
202         write_unlock(&afs_cells_lock);
203
204         _leave(" = %d", ret);
205         return ret;
206
207 } /* end afs_cell_init() */
208
209 /*****************************************************************************/
210 /*
211  * lookup a cell record
212  */
213 int afs_cell_lookup(const char *name, unsigned namesz, struct afs_cell **_cell)
214 {
215         struct afs_cell *cell;
216         int ret;
217
218         _enter("\"%*.*s\",", namesz, namesz, name ? name : "");
219
220         *_cell = NULL;
221
222         if (name) {
223                 /* if the cell was named, look for it in the cell record list */
224                 ret = -ENOENT;
225                 cell = NULL;
226                 read_lock(&afs_cells_lock);
227
228                 list_for_each_entry(cell, &afs_cells, link) {
229                         if (strncmp(cell->name, name, namesz) == 0) {
230                                 afs_get_cell(cell);
231                                 goto found;
232                         }
233                 }
234                 cell = NULL;
235         found:
236
237                 read_unlock(&afs_cells_lock);
238
239                 if (cell)
240                         ret = 0;
241         }
242         else {
243                 read_lock(&afs_cells_lock);
244
245                 cell = afs_cell_root;
246                 if (!cell) {
247                         /* this should not happen unless user tries to mount
248                          * when root cell is not set. Return an impossibly
249                          * bizzare errno to alert the user. Things like
250                          * ENOENT might be "more appropriate" but they happen
251                          * for other reasons.
252                          */
253                         ret = -EDESTADDRREQ;
254                 }
255                 else {
256                         afs_get_cell(cell);
257                         ret = 0;
258                 }
259
260                 read_unlock(&afs_cells_lock);
261         }
262
263         *_cell = cell;
264         _leave(" = %d (%p)", ret, cell);
265         return ret;
266
267 } /* end afs_cell_lookup() */
268
269 /*****************************************************************************/
270 /*
271  * try and get a cell record
272  */
273 struct afs_cell *afs_get_cell_maybe(struct afs_cell **_cell)
274 {
275         struct afs_cell *cell;
276
277         write_lock(&afs_cells_lock);
278
279         cell = *_cell;
280         if (cell && !list_empty(&cell->link))
281                 afs_get_cell(cell);
282         else
283                 cell = NULL;
284
285         write_unlock(&afs_cells_lock);
286
287         return cell;
288 } /* end afs_get_cell_maybe() */
289
290 /*****************************************************************************/
291 /*
292  * destroy a cell record
293  */
294 void afs_put_cell(struct afs_cell *cell)
295 {
296         if (!cell)
297                 return;
298
299         _enter("%p{%d,%s}", cell, atomic_read(&cell->usage), cell->name);
300
301         /* sanity check */
302         BUG_ON(atomic_read(&cell->usage) <= 0);
303
304         /* to prevent a race, the decrement and the dequeue must be effectively
305          * atomic */
306         write_lock(&afs_cells_lock);
307
308         if (likely(!atomic_dec_and_test(&cell->usage))) {
309                 write_unlock(&afs_cells_lock);
310                 _leave("");
311                 return;
312         }
313
314         write_unlock(&afs_cells_lock);
315
316         BUG_ON(!list_empty(&cell->sv_list));
317         BUG_ON(!list_empty(&cell->sv_graveyard));
318         BUG_ON(!list_empty(&cell->vl_list));
319         BUG_ON(!list_empty(&cell->vl_graveyard));
320
321         _leave(" [unused]");
322 } /* end afs_put_cell() */
323
324 /*****************************************************************************/
325 /*
326  * destroy a cell record
327  */
328 static void afs_cell_destroy(struct afs_cell *cell)
329 {
330         _enter("%p{%d,%s}", cell, atomic_read(&cell->usage), cell->name);
331
332         /* to prevent a race, the decrement and the dequeue must be effectively
333          * atomic */
334         write_lock(&afs_cells_lock);
335
336         /* sanity check */
337         BUG_ON(atomic_read(&cell->usage) != 0);
338
339         list_del_init(&cell->link);
340
341         write_unlock(&afs_cells_lock);
342
343         down_write(&afs_cells_sem);
344
345         afs_proc_cell_remove(cell);
346
347         down_write(&afs_proc_cells_sem);
348         list_del_init(&cell->proc_link);
349         up_write(&afs_proc_cells_sem);
350
351 #ifdef CONFIG_AFS_FSCACHE
352         fscache_relinquish_cookie(cell->cache, 0);
353 #endif
354
355         up_write(&afs_cells_sem);
356
357         BUG_ON(!list_empty(&cell->sv_list));
358         BUG_ON(!list_empty(&cell->sv_graveyard));
359         BUG_ON(!list_empty(&cell->vl_list));
360         BUG_ON(!list_empty(&cell->vl_graveyard));
361
362         /* finish cleaning up the cell */
363         kfree(cell);
364
365         _leave(" [destroyed]");
366 } /* end afs_cell_destroy() */
367
368 /*****************************************************************************/
369 /*
370  * lookup the server record corresponding to an Rx RPC peer
371  */
372 int afs_server_find_by_peer(const struct rxrpc_peer *peer,
373                             struct afs_server **_server)
374 {
375         struct afs_server *server;
376         struct afs_cell *cell;
377
378         _enter("%p{a=%08x},", peer, ntohl(peer->addr.s_addr));
379
380         /* search the cell list */
381         read_lock(&afs_cells_lock);
382
383         list_for_each_entry(cell, &afs_cells, link) {
384
385                 _debug("? cell %s",cell->name);
386
387                 write_lock(&cell->sv_lock);
388
389                 /* check the active list */
390                 list_for_each_entry(server, &cell->sv_list, link) {
391                         _debug("?? server %08x", ntohl(server->addr.s_addr));
392
393                         if (memcmp(&server->addr, &peer->addr,
394                                    sizeof(struct in_addr)) == 0)
395                                 goto found_server;
396                 }
397
398                 /* check the inactive list */
399                 spin_lock(&cell->sv_gylock);
400                 list_for_each_entry(server, &cell->sv_graveyard, link) {
401                         _debug("?? dead server %08x",
402                                ntohl(server->addr.s_addr));
403
404                         if (memcmp(&server->addr, &peer->addr,
405                                    sizeof(struct in_addr)) == 0)
406                                 goto found_dead_server;
407                 }
408                 spin_unlock(&cell->sv_gylock);
409
410                 write_unlock(&cell->sv_lock);
411         }
412         read_unlock(&afs_cells_lock);
413
414         _leave(" = -ENOENT");
415         return -ENOENT;
416
417         /* we found it in the graveyard - resurrect it */
418  found_dead_server:
419         list_move_tail(&server->link, &cell->sv_list);
420         afs_get_server(server);
421         afs_kafstimod_del_timer(&server->timeout);
422         spin_unlock(&cell->sv_gylock);
423         goto success;
424
425         /* we found it - increment its ref count and return it */
426  found_server:
427         afs_get_server(server);
428
429  success:
430         write_unlock(&cell->sv_lock);
431         read_unlock(&afs_cells_lock);
432
433         *_server = server;
434         _leave(" = 0 (s=%p c=%p)", server, cell);
435         return 0;
436
437 } /* end afs_server_find_by_peer() */
438
439 /*****************************************************************************/
440 /*
441  * purge in-memory cell database on module unload or afs_init() failure
442  * - the timeout daemon is stopped before calling this
443  */
444 void afs_cell_purge(void)
445 {
446         struct afs_vlocation *vlocation;
447         struct afs_cell *cell;
448
449         _enter("");
450
451         afs_put_cell(afs_cell_root);
452
453         while (!list_empty(&afs_cells)) {
454                 cell = NULL;
455
456                 /* remove the next cell from the front of the list */
457                 write_lock(&afs_cells_lock);
458
459                 if (!list_empty(&afs_cells)) {
460                         cell = list_entry(afs_cells.next,
461                                           struct afs_cell, link);
462                         list_del_init(&cell->link);
463                 }
464
465                 write_unlock(&afs_cells_lock);
466
467                 if (cell) {
468                         _debug("PURGING CELL %s (%d)",
469                                cell->name, atomic_read(&cell->usage));
470
471                         BUG_ON(!list_empty(&cell->sv_list));
472                         BUG_ON(!list_empty(&cell->vl_list));
473
474                         /* purge the cell's VL graveyard list */
475                         _debug(" - clearing VL graveyard");
476
477                         spin_lock(&cell->vl_gylock);
478
479                         while (!list_empty(&cell->vl_graveyard)) {
480                                 vlocation = list_entry(cell->vl_graveyard.next,
481                                                        struct afs_vlocation,
482                                                        link);
483                                 list_del_init(&vlocation->link);
484
485                                 afs_kafstimod_del_timer(&vlocation->timeout);
486
487                                 spin_unlock(&cell->vl_gylock);
488
489                                 afs_vlocation_do_timeout(vlocation);
490                                 /* TODO: race if move to use krxtimod instead
491                                  * of kafstimod */
492
493                                 spin_lock(&cell->vl_gylock);
494                         }
495
496                         spin_unlock(&cell->vl_gylock);
497
498                         /* purge the cell's server graveyard list */
499                         _debug(" - clearing server graveyard");
500
501                         spin_lock(&cell->sv_gylock);
502
503                         while (!list_empty(&cell->sv_graveyard)) {
504                                 struct afs_server *server;
505
506                                 server = list_entry(cell->sv_graveyard.next,
507                                                     struct afs_server, link);
508                                 list_del_init(&server->link);
509
510                                 afs_kafstimod_del_timer(&server->timeout);
511
512                                 spin_unlock(&cell->sv_gylock);
513
514                                 afs_server_do_timeout(server);
515
516                                 spin_lock(&cell->sv_gylock);
517                         }
518
519                         spin_unlock(&cell->sv_gylock);
520
521                         /* now the cell should be left with no references */
522                         afs_cell_destroy(cell);
523                 }
524         }
525
526         _leave("");
527 } /* end afs_cell_purge() */
528
529 /*****************************************************************************/
530 /*
531  * set the key for the index entry
532  */
533 #ifdef CONFIG_AFS_FSCACHE
534 static uint16_t afs_cell_cache_get_key(const void *cookie_netfs_data,
535                                        void *buffer, uint16_t bufmax)
536 {
537         const struct afs_cell *cell = cookie_netfs_data;
538         uint16_t klen;
539
540         _enter("%p,%p,%u", cell, buffer, bufmax);
541
542         klen = strlen(cell->name);
543         if (klen > bufmax)
544                 return 0;
545
546         memcpy(buffer, cell->name, klen);
547         return klen;
548
549 } /* end afs_cell_cache_get_key() */
550 #endif
551
552 /*****************************************************************************/
553 /*
554  * provide new auxilliary cache data
555  */
556 #ifdef CONFIG_AFS_FSCACHE
557 static uint16_t afs_cell_cache_get_aux(const void *cookie_netfs_data,
558                                        void *buffer, uint16_t bufmax)
559 {
560         const struct afs_cell *cell = cookie_netfs_data;
561         uint16_t dlen;
562
563         _enter("%p,%p,%u", cell, buffer, bufmax);
564
565         dlen = cell->vl_naddrs * sizeof(cell->vl_addrs[0]);
566         dlen = min(dlen, bufmax);
567         dlen &= ~(sizeof(cell->vl_addrs[0]) - 1);
568
569         memcpy(buffer, cell->vl_addrs, dlen);
570
571         return dlen;
572
573 } /* end afs_cell_cache_get_aux() */
574 #endif
575
576 /*****************************************************************************/
577 /*
578  * check that the auxilliary data indicates that the entry is still valid
579  */
580 #ifdef CONFIG_AFS_FSCACHE
581 static fscache_checkaux_t afs_cell_cache_check_aux(void *cookie_netfs_data,
582                                                    const void *buffer,
583                                                    uint16_t buflen)
584 {
585         _leave(" = OKAY");
586         return FSCACHE_CHECKAUX_OKAY;
587
588 } /* end afs_cell_cache_check_aux() */
589 #endif