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 DEFINE_RWLOCK(afs_cells_lock);
31 static DECLARE_RWSEM(afs_cells_sem); /* add/remove serialisation */
32 static struct afs_cell *afs_cell_root;
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,
43 static struct fscache_cookie_def afs_cell_cache_index_def = {
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,
52 /*****************************************************************************/
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
58 int afs_cell_create(const char *name, char *vllist, struct afs_cell **_cell)
60 struct afs_cell *cell;
66 BUG_ON(!name); /* TODO: want to look up "this cell" in the cache */
68 /* allocate and initialise a cell record */
69 cell = kmalloc(sizeof(struct afs_cell) + strlen(name) + 1, GFP_KERNEL);
75 down_write(&afs_cells_sem);
77 memset(cell, 0, sizeof(struct afs_cell));
78 atomic_set(&cell->usage, 0);
80 INIT_LIST_HEAD(&cell->link);
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);
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);
92 strcpy(cell->name,name);
94 /* fill in the VL server list from the rest of the string */
99 next = strchr(vllist, ':');
103 if (sscanf(vllist, "%u.%u.%u.%u", &a, &b, &c, &d) != 4)
106 if (a > 255 || b > 255 || c > 255 || d > 255)
109 cell->vl_addrs[cell->vl_naddrs++].s_addr =
110 htonl((a << 24) | (b << 16) | (c << 8) | d);
112 if (cell->vl_naddrs >= AFS_CELL_MAX_ADDRS)
115 } while(vllist = next, vllist);
117 /* add a proc dir for this cell */
118 ret = afs_proc_cell_setup(cell);
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,
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);
134 down_write(&afs_proc_cells_sem);
135 list_add_tail(&cell->proc_link, &afs_proc_cells);
136 up_write(&afs_proc_cells_sem);
139 up_write(&afs_cells_sem);
141 _leave(" = 0 (%p)", cell);
145 printk(KERN_ERR "kAFS: bad VL server IP address: '%s'\n", vllist);
147 up_write(&afs_cells_sem);
149 _leave(" = %d", ret);
151 } /* end afs_cell_create() */
153 /*****************************************************************************/
155 * initialise the cell database from module parameters
157 int afs_cell_init(char *rootcell)
159 struct afs_cell *old_root, *new_root;
166 /* module is loaded with no parameters, or built statically.
167 * - in the future we might initialize cell DB here.
169 _leave(" = 0 (but no root)");
173 cp = strchr(rootcell, ':');
175 printk(KERN_ERR "kAFS: no VL server IP addresses specified\n");
176 _leave(" = %d (no colon)", -EINVAL);
180 /* allocate a cell record for the root cell */
182 ret = afs_cell_create(rootcell, cp, &new_root);
184 _leave(" = %d", ret);
188 /* as afs_put_cell() takes locks by itself, we have to do
189 * a little gymnastics to be race-free.
191 afs_get_cell(new_root);
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);
201 afs_cell_root = new_root;
202 write_unlock(&afs_cells_lock);
204 _leave(" = %d", ret);
207 } /* end afs_cell_init() */
209 /*****************************************************************************/
211 * lookup a cell record
213 int afs_cell_lookup(const char *name, unsigned namesz, struct afs_cell **_cell)
215 struct afs_cell *cell;
218 _enter("\"%*.*s\",", namesz, namesz, name ? name : "");
223 /* if the cell was named, look for it in the cell record list */
226 read_lock(&afs_cells_lock);
228 list_for_each_entry(cell, &afs_cells, link) {
229 if (strncmp(cell->name, name, namesz) == 0) {
237 read_unlock(&afs_cells_lock);
243 read_lock(&afs_cells_lock);
245 cell = afs_cell_root;
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
260 read_unlock(&afs_cells_lock);
264 _leave(" = %d (%p)", ret, cell);
267 } /* end afs_cell_lookup() */
269 /*****************************************************************************/
271 * try and get a cell record
273 struct afs_cell *afs_get_cell_maybe(struct afs_cell **_cell)
275 struct afs_cell *cell;
277 write_lock(&afs_cells_lock);
280 if (cell && !list_empty(&cell->link))
285 write_unlock(&afs_cells_lock);
288 } /* end afs_get_cell_maybe() */
290 /*****************************************************************************/
292 * destroy a cell record
294 void afs_put_cell(struct afs_cell *cell)
299 _enter("%p{%d,%s}", cell, atomic_read(&cell->usage), cell->name);
302 BUG_ON(atomic_read(&cell->usage) <= 0);
304 /* to prevent a race, the decrement and the dequeue must be effectively
306 write_lock(&afs_cells_lock);
308 if (likely(!atomic_dec_and_test(&cell->usage))) {
309 write_unlock(&afs_cells_lock);
314 write_unlock(&afs_cells_lock);
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));
322 } /* end afs_put_cell() */
324 /*****************************************************************************/
326 * destroy a cell record
328 static void afs_cell_destroy(struct afs_cell *cell)
330 _enter("%p{%d,%s}", cell, atomic_read(&cell->usage), cell->name);
332 /* to prevent a race, the decrement and the dequeue must be effectively
334 write_lock(&afs_cells_lock);
337 BUG_ON(atomic_read(&cell->usage) != 0);
339 list_del_init(&cell->link);
341 write_unlock(&afs_cells_lock);
343 down_write(&afs_cells_sem);
345 afs_proc_cell_remove(cell);
347 down_write(&afs_proc_cells_sem);
348 list_del_init(&cell->proc_link);
349 up_write(&afs_proc_cells_sem);
351 #ifdef CONFIG_AFS_FSCACHE
352 fscache_relinquish_cookie(cell->cache, 0);
355 up_write(&afs_cells_sem);
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));
362 /* finish cleaning up the cell */
365 _leave(" [destroyed]");
366 } /* end afs_cell_destroy() */
368 /*****************************************************************************/
370 * lookup the server record corresponding to an Rx RPC peer
372 int afs_server_find_by_peer(const struct rxrpc_peer *peer,
373 struct afs_server **_server)
375 struct afs_server *server;
376 struct afs_cell *cell;
378 _enter("%p{a=%08x},", peer, ntohl(peer->addr.s_addr));
380 /* search the cell list */
381 read_lock(&afs_cells_lock);
383 list_for_each_entry(cell, &afs_cells, link) {
385 _debug("? cell %s",cell->name);
387 write_lock(&cell->sv_lock);
389 /* check the active list */
390 list_for_each_entry(server, &cell->sv_list, link) {
391 _debug("?? server %08x", ntohl(server->addr.s_addr));
393 if (memcmp(&server->addr, &peer->addr,
394 sizeof(struct in_addr)) == 0)
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));
404 if (memcmp(&server->addr, &peer->addr,
405 sizeof(struct in_addr)) == 0)
406 goto found_dead_server;
408 spin_unlock(&cell->sv_gylock);
410 write_unlock(&cell->sv_lock);
412 read_unlock(&afs_cells_lock);
414 _leave(" = -ENOENT");
417 /* we found it in the graveyard - resurrect it */
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);
425 /* we found it - increment its ref count and return it */
427 afs_get_server(server);
430 write_unlock(&cell->sv_lock);
431 read_unlock(&afs_cells_lock);
434 _leave(" = 0 (s=%p c=%p)", server, cell);
437 } /* end afs_server_find_by_peer() */
439 /*****************************************************************************/
441 * purge in-memory cell database on module unload or afs_init() failure
442 * - the timeout daemon is stopped before calling this
444 void afs_cell_purge(void)
446 struct afs_vlocation *vlocation;
447 struct afs_cell *cell;
451 afs_put_cell(afs_cell_root);
453 while (!list_empty(&afs_cells)) {
456 /* remove the next cell from the front of the list */
457 write_lock(&afs_cells_lock);
459 if (!list_empty(&afs_cells)) {
460 cell = list_entry(afs_cells.next,
461 struct afs_cell, link);
462 list_del_init(&cell->link);
465 write_unlock(&afs_cells_lock);
468 _debug("PURGING CELL %s (%d)",
469 cell->name, atomic_read(&cell->usage));
471 BUG_ON(!list_empty(&cell->sv_list));
472 BUG_ON(!list_empty(&cell->vl_list));
474 /* purge the cell's VL graveyard list */
475 _debug(" - clearing VL graveyard");
477 spin_lock(&cell->vl_gylock);
479 while (!list_empty(&cell->vl_graveyard)) {
480 vlocation = list_entry(cell->vl_graveyard.next,
481 struct afs_vlocation,
483 list_del_init(&vlocation->link);
485 afs_kafstimod_del_timer(&vlocation->timeout);
487 spin_unlock(&cell->vl_gylock);
489 afs_vlocation_do_timeout(vlocation);
490 /* TODO: race if move to use krxtimod instead
493 spin_lock(&cell->vl_gylock);
496 spin_unlock(&cell->vl_gylock);
498 /* purge the cell's server graveyard list */
499 _debug(" - clearing server graveyard");
501 spin_lock(&cell->sv_gylock);
503 while (!list_empty(&cell->sv_graveyard)) {
504 struct afs_server *server;
506 server = list_entry(cell->sv_graveyard.next,
507 struct afs_server, link);
508 list_del_init(&server->link);
510 afs_kafstimod_del_timer(&server->timeout);
512 spin_unlock(&cell->sv_gylock);
514 afs_server_do_timeout(server);
516 spin_lock(&cell->sv_gylock);
519 spin_unlock(&cell->sv_gylock);
521 /* now the cell should be left with no references */
522 afs_cell_destroy(cell);
527 } /* end afs_cell_purge() */
529 /*****************************************************************************/
531 * set the key for the index entry
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)
537 const struct afs_cell *cell = cookie_netfs_data;
540 _enter("%p,%p,%u", cell, buffer, bufmax);
542 klen = strlen(cell->name);
546 memcpy(buffer, cell->name, klen);
549 } /* end afs_cell_cache_get_key() */
552 /*****************************************************************************/
554 * provide new auxilliary cache data
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)
560 const struct afs_cell *cell = cookie_netfs_data;
563 _enter("%p,%p,%u", cell, buffer, bufmax);
565 dlen = cell->vl_naddrs * sizeof(cell->vl_addrs[0]);
566 dlen = min(dlen, bufmax);
567 dlen &= ~(sizeof(cell->vl_addrs[0]) - 1);
569 memcpy(buffer, cell->vl_addrs, dlen);
573 } /* end afs_cell_cache_get_aux() */
576 /*****************************************************************************/
578 * check that the auxilliary data indicates that the entry is still valid
580 #ifdef CONFIG_AFS_FSCACHE
581 static fscache_checkaux_t afs_cell_cache_check_aux(void *cookie_netfs_data,
586 return FSCACHE_CHECKAUX_OKAY;
588 } /* end afs_cell_cache_check_aux() */