1 /* cell.c: AFS cell and server record management
3 * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
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.
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>
20 #include "transport.h"
22 #include "kafstimod.h"
26 DECLARE_RWSEM(afs_proc_cells_sem
);
27 LIST_HEAD(afs_proc_cells
);
29 static struct list_head afs_cells
= LIST_HEAD_INIT(afs_cells
);
30 static rwlock_t afs_cells_lock
= RW_LOCK_UNLOCKED
;
31 static DECLARE_RWSEM(afs_cells_sem
); /* add/remove serialisation */
32 static struct afs_cell
*afs_cell_root
;
34 #ifdef AFS_CACHING_SUPPORT
35 static cachefs_match_val_t
afs_cell_cache_match(void *target
,
37 static void afs_cell_cache_update(void *source
, void *entry
);
39 struct cachefs_index_def afs_cache_cell_index_def
= {
41 .data_size
= sizeof(struct afs_cache_cell
),
42 .keys
[0] = { CACHEFS_INDEX_KEYS_ASCIIZ
, 64 },
43 .match
= afs_cell_cache_match
,
44 .update
= afs_cell_cache_update
,
48 /*****************************************************************************/
50 * create a cell record
51 * - "name" is the name of the cell
52 * - "vllist" is a colon separated list of IP addresses in "a.b.c.d" format
54 int afs_cell_create(const char *name
, char *vllist
, struct afs_cell
**_cell
)
56 struct afs_cell
*cell
;
62 BUG_ON(!name
); /* TODO: want to look up "this cell" in the cache */
64 /* allocate and initialise a cell record */
65 cell
= kmalloc(sizeof(struct afs_cell
) + strlen(name
) + 1, GFP_KERNEL
);
71 down_write(&afs_cells_sem
);
73 memset(cell
, 0, sizeof(struct afs_cell
));
74 atomic_set(&cell
->usage
, 0);
76 INIT_LIST_HEAD(&cell
->link
);
78 rwlock_init(&cell
->sv_lock
);
79 INIT_LIST_HEAD(&cell
->sv_list
);
80 INIT_LIST_HEAD(&cell
->sv_graveyard
);
81 spin_lock_init(&cell
->sv_gylock
);
83 init_rwsem(&cell
->vl_sem
);
84 INIT_LIST_HEAD(&cell
->vl_list
);
85 INIT_LIST_HEAD(&cell
->vl_graveyard
);
86 spin_lock_init(&cell
->vl_gylock
);
88 strcpy(cell
->name
,name
);
90 /* fill in the VL server list from the rest of the string */
95 next
= strchr(vllist
, ':');
99 if (sscanf(vllist
, "%u.%u.%u.%u", &a
, &b
, &c
, &d
) != 4)
102 if (a
> 255 || b
> 255 || c
> 255 || d
> 255)
105 cell
->vl_addrs
[cell
->vl_naddrs
++].s_addr
=
106 htonl((a
<< 24) | (b
<< 16) | (c
<< 8) | d
);
108 if (cell
->vl_naddrs
>= AFS_CELL_MAX_ADDRS
)
111 } while(vllist
= next
, vllist
);
113 /* add a proc dir for this cell */
114 ret
= afs_proc_cell_setup(cell
);
118 #ifdef AFS_CACHING_SUPPORT
119 /* put it up for caching */
120 cachefs_acquire_cookie(afs_cache_netfs
.primary_index
,
121 &afs_vlocation_cache_index_def
,
126 /* add to the cell lists */
127 write_lock(&afs_cells_lock
);
128 list_add_tail(&cell
->link
, &afs_cells
);
129 write_unlock(&afs_cells_lock
);
131 down_write(&afs_proc_cells_sem
);
132 list_add_tail(&cell
->proc_link
, &afs_proc_cells
);
133 up_write(&afs_proc_cells_sem
);
136 up_write(&afs_cells_sem
);
138 _leave(" = 0 (%p)", cell
);
142 printk(KERN_ERR
"kAFS: bad VL server IP address: '%s'\n", vllist
);
144 up_write(&afs_cells_sem
);
146 _leave(" = %d", ret
);
148 } /* end afs_cell_create() */
150 /*****************************************************************************/
152 * initialise the cell database from module parameters
154 int afs_cell_init(char *rootcell
)
156 struct afs_cell
*old_root
, *new_root
;
163 /* module is loaded with no parameters, or built statically.
164 * - in the future we might initialize cell DB here.
166 _leave(" = 0 (but no root)");
170 cp
= strchr(rootcell
, ':');
172 printk(KERN_ERR
"kAFS: no VL server IP addresses specified\n");
173 _leave(" = %d (no colon)", -EINVAL
);
177 /* allocate a cell record for the root cell */
179 ret
= afs_cell_create(rootcell
, cp
, &new_root
);
181 _leave(" = %d", ret
);
185 /* as afs_put_cell() takes locks by itself, we have to do
186 * a little gymnastics to be race-free.
188 afs_get_cell(new_root
);
190 write_lock(&afs_cells_lock
);
191 while (afs_cell_root
) {
192 old_root
= afs_cell_root
;
193 afs_cell_root
= NULL
;
194 write_unlock(&afs_cells_lock
);
195 afs_put_cell(old_root
);
196 write_lock(&afs_cells_lock
);
198 afs_cell_root
= new_root
;
199 write_unlock(&afs_cells_lock
);
201 _leave(" = %d", ret
);
204 } /* end afs_cell_init() */
206 /*****************************************************************************/
208 * lookup a cell record
210 int afs_cell_lookup(const char *name
, unsigned namesz
, struct afs_cell
**_cell
)
212 struct afs_cell
*cell
;
215 _enter("\"%*.*s\",", namesz
, namesz
, name
? name
: "");
220 /* if the cell was named, look for it in the cell record list */
223 read_lock(&afs_cells_lock
);
225 list_for_each_entry(cell
, &afs_cells
, link
) {
226 if (strncmp(cell
->name
, name
, namesz
) == 0) {
234 read_unlock(&afs_cells_lock
);
240 read_lock(&afs_cells_lock
);
242 cell
= afs_cell_root
;
244 /* this should not happen unless user tries to mount
245 * when root cell is not set. Return an impossibly
246 * bizzare errno to alert the user. Things like
247 * ENOENT might be "more appropriate" but they happen
257 read_unlock(&afs_cells_lock
);
261 _leave(" = %d (%p)", ret
, cell
);
264 } /* end afs_cell_lookup() */
266 /*****************************************************************************/
268 * try and get a cell record
270 struct afs_cell
*afs_get_cell_maybe(struct afs_cell
**_cell
)
272 struct afs_cell
*cell
;
274 write_lock(&afs_cells_lock
);
277 if (cell
&& !list_empty(&cell
->link
))
282 write_unlock(&afs_cells_lock
);
285 } /* end afs_get_cell_maybe() */
287 /*****************************************************************************/
289 * destroy a cell record
291 void afs_put_cell(struct afs_cell
*cell
)
296 _enter("%p{%d,%s}", cell
, atomic_read(&cell
->usage
), cell
->name
);
299 BUG_ON(atomic_read(&cell
->usage
) <= 0);
301 /* to prevent a race, the decrement and the dequeue must be effectively
303 write_lock(&afs_cells_lock
);
305 if (likely(!atomic_dec_and_test(&cell
->usage
))) {
306 write_unlock(&afs_cells_lock
);
311 write_unlock(&afs_cells_lock
);
313 BUG_ON(!list_empty(&cell
->sv_list
));
314 BUG_ON(!list_empty(&cell
->sv_graveyard
));
315 BUG_ON(!list_empty(&cell
->vl_list
));
316 BUG_ON(!list_empty(&cell
->vl_graveyard
));
319 } /* end afs_put_cell() */
321 /*****************************************************************************/
323 * destroy a cell record
325 static void afs_cell_destroy(struct afs_cell
*cell
)
327 _enter("%p{%d,%s}", cell
, atomic_read(&cell
->usage
), cell
->name
);
329 /* to prevent a race, the decrement and the dequeue must be effectively
331 write_lock(&afs_cells_lock
);
334 BUG_ON(atomic_read(&cell
->usage
) != 0);
336 list_del_init(&cell
->link
);
338 write_unlock(&afs_cells_lock
);
340 down_write(&afs_cells_sem
);
342 afs_proc_cell_remove(cell
);
344 down_write(&afs_proc_cells_sem
);
345 list_del_init(&cell
->proc_link
);
346 up_write(&afs_proc_cells_sem
);
348 #ifdef AFS_CACHING_SUPPORT
349 cachefs_relinquish_cookie(cell
->cache
, 0);
352 up_write(&afs_cells_sem
);
354 BUG_ON(!list_empty(&cell
->sv_list
));
355 BUG_ON(!list_empty(&cell
->sv_graveyard
));
356 BUG_ON(!list_empty(&cell
->vl_list
));
357 BUG_ON(!list_empty(&cell
->vl_graveyard
));
359 /* finish cleaning up the cell */
362 _leave(" [destroyed]");
363 } /* end afs_cell_destroy() */
365 /*****************************************************************************/
367 * lookup the server record corresponding to an Rx RPC peer
369 int afs_server_find_by_peer(const struct rxrpc_peer
*peer
,
370 struct afs_server
**_server
)
372 struct afs_server
*server
;
373 struct afs_cell
*cell
;
375 _enter("%p{a=%08x},", peer
, ntohl(peer
->addr
.s_addr
));
377 /* search the cell list */
378 read_lock(&afs_cells_lock
);
380 list_for_each_entry(cell
, &afs_cells
, link
) {
382 _debug("? cell %s",cell
->name
);
384 write_lock(&cell
->sv_lock
);
386 /* check the active list */
387 list_for_each_entry(server
, &cell
->sv_list
, link
) {
388 _debug("?? server %08x", ntohl(server
->addr
.s_addr
));
390 if (memcmp(&server
->addr
, &peer
->addr
,
391 sizeof(struct in_addr
)) == 0)
395 /* check the inactive list */
396 spin_lock(&cell
->sv_gylock
);
397 list_for_each_entry(server
, &cell
->sv_graveyard
, link
) {
398 _debug("?? dead server %08x",
399 ntohl(server
->addr
.s_addr
));
401 if (memcmp(&server
->addr
, &peer
->addr
,
402 sizeof(struct in_addr
)) == 0)
403 goto found_dead_server
;
405 spin_unlock(&cell
->sv_gylock
);
407 write_unlock(&cell
->sv_lock
);
409 read_unlock(&afs_cells_lock
);
411 _leave(" = -ENOENT");
414 /* we found it in the graveyard - resurrect it */
416 list_del(&server
->link
);
417 list_add_tail(&server
->link
, &cell
->sv_list
);
418 afs_get_server(server
);
419 afs_kafstimod_del_timer(&server
->timeout
);
420 spin_unlock(&cell
->sv_gylock
);
423 /* we found it - increment its ref count and return it */
425 afs_get_server(server
);
428 write_unlock(&cell
->sv_lock
);
429 read_unlock(&afs_cells_lock
);
432 _leave(" = 0 (s=%p c=%p)", server
, cell
);
435 } /* end afs_server_find_by_peer() */
437 /*****************************************************************************/
439 * purge in-memory cell database on module unload or afs_init() failure
440 * - the timeout daemon is stopped before calling this
442 void afs_cell_purge(void)
444 struct afs_vlocation
*vlocation
;
445 struct afs_cell
*cell
;
449 afs_put_cell(afs_cell_root
);
451 while (!list_empty(&afs_cells
)) {
454 /* remove the next cell from the front of the list */
455 write_lock(&afs_cells_lock
);
457 if (!list_empty(&afs_cells
)) {
458 cell
= list_entry(afs_cells
.next
,
459 struct afs_cell
, link
);
460 list_del_init(&cell
->link
);
463 write_unlock(&afs_cells_lock
);
466 _debug("PURGING CELL %s (%d)",
467 cell
->name
, atomic_read(&cell
->usage
));
469 BUG_ON(!list_empty(&cell
->sv_list
));
470 BUG_ON(!list_empty(&cell
->vl_list
));
472 /* purge the cell's VL graveyard list */
473 _debug(" - clearing VL graveyard");
475 spin_lock(&cell
->vl_gylock
);
477 while (!list_empty(&cell
->vl_graveyard
)) {
478 vlocation
= list_entry(cell
->vl_graveyard
.next
,
479 struct afs_vlocation
,
481 list_del_init(&vlocation
->link
);
483 afs_kafstimod_del_timer(&vlocation
->timeout
);
485 spin_unlock(&cell
->vl_gylock
);
487 afs_vlocation_do_timeout(vlocation
);
488 /* TODO: race if move to use krxtimod instead
491 spin_lock(&cell
->vl_gylock
);
494 spin_unlock(&cell
->vl_gylock
);
496 /* purge the cell's server graveyard list */
497 _debug(" - clearing server graveyard");
499 spin_lock(&cell
->sv_gylock
);
501 while (!list_empty(&cell
->sv_graveyard
)) {
502 struct afs_server
*server
;
504 server
= list_entry(cell
->sv_graveyard
.next
,
505 struct afs_server
, link
);
506 list_del_init(&server
->link
);
508 afs_kafstimod_del_timer(&server
->timeout
);
510 spin_unlock(&cell
->sv_gylock
);
512 afs_server_do_timeout(server
);
514 spin_lock(&cell
->sv_gylock
);
517 spin_unlock(&cell
->sv_gylock
);
519 /* now the cell should be left with no references */
520 afs_cell_destroy(cell
);
525 } /* end afs_cell_purge() */
527 /*****************************************************************************/
529 * match a cell record obtained from the cache
531 #ifdef AFS_CACHING_SUPPORT
532 static cachefs_match_val_t
afs_cell_cache_match(void *target
,
535 const struct afs_cache_cell
*ccell
= entry
;
536 struct afs_cell
*cell
= target
;
538 _enter("{%s},{%s}", ccell
->name
, cell
->name
);
540 if (strncmp(ccell
->name
, cell
->name
, sizeof(ccell
->name
)) == 0) {
541 _leave(" = SUCCESS");
542 return CACHEFS_MATCH_SUCCESS
;
546 return CACHEFS_MATCH_FAILED
;
547 } /* end afs_cell_cache_match() */
550 /*****************************************************************************/
552 * update a cell record in the cache
554 #ifdef AFS_CACHING_SUPPORT
555 static void afs_cell_cache_update(void *source
, void *entry
)
557 struct afs_cache_cell
*ccell
= entry
;
558 struct afs_cell
*cell
= source
;
560 _enter("%p,%p", source
, entry
);
562 strncpy(ccell
->name
, cell
->name
, sizeof(ccell
->name
));
564 memcpy(ccell
->vl_servers
,
566 min(sizeof(ccell
->vl_servers
), sizeof(cell
->vl_addrs
)));
568 } /* end afs_cell_cache_update() */