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