fs/afs/: possible cleanups
[linux-2.6.git] / fs / afs / cell.c
1 /* 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 <linux/key.h>
15 #include <linux/ctype.h>
16 #include <linux/sched.h>
17 #include <keys/rxrpc-type.h>
18 #include "internal.h"
19
20 DECLARE_RWSEM(afs_proc_cells_sem);
21 LIST_HEAD(afs_proc_cells);
22
23 static struct list_head afs_cells = LIST_HEAD_INIT(afs_cells);
24 static DEFINE_RWLOCK(afs_cells_lock);
25 static DECLARE_RWSEM(afs_cells_sem); /* add/remove serialisation */
26 static DECLARE_WAIT_QUEUE_HEAD(afs_cells_freeable_wq);
27 static struct afs_cell *afs_cell_root;
28
29 /*
30  * allocate a cell record and fill in its name, VL server address list and
31  * allocate an anonymous key
32  */
33 static struct afs_cell *afs_cell_alloc(const char *name, char *vllist)
34 {
35         struct afs_cell *cell;
36         size_t namelen;
37         char keyname[4 + AFS_MAXCELLNAME + 1], *cp, *dp, *next;
38         int ret;
39
40         _enter("%s,%s", name, vllist);
41
42         BUG_ON(!name); /* TODO: want to look up "this cell" in the cache */
43
44         namelen = strlen(name);
45         if (namelen > AFS_MAXCELLNAME)
46                 return ERR_PTR(-ENAMETOOLONG);
47
48         /* allocate and initialise a cell record */
49         cell = kzalloc(sizeof(struct afs_cell) + namelen + 1, GFP_KERNEL);
50         if (!cell) {
51                 _leave(" = -ENOMEM");
52                 return ERR_PTR(-ENOMEM);
53         }
54
55         memcpy(cell->name, name, namelen);
56         cell->name[namelen] = 0;
57
58         atomic_set(&cell->usage, 1);
59         INIT_LIST_HEAD(&cell->link);
60         rwlock_init(&cell->servers_lock);
61         INIT_LIST_HEAD(&cell->servers);
62         init_rwsem(&cell->vl_sem);
63         INIT_LIST_HEAD(&cell->vl_list);
64         spin_lock_init(&cell->vl_lock);
65
66         /* fill in the VL server list from the rest of the string */
67         do {
68                 unsigned a, b, c, d;
69
70                 next = strchr(vllist, ':');
71                 if (next)
72                         *next++ = 0;
73
74                 if (sscanf(vllist, "%u.%u.%u.%u", &a, &b, &c, &d) != 4)
75                         goto bad_address;
76
77                 if (a > 255 || b > 255 || c > 255 || d > 255)
78                         goto bad_address;
79
80                 cell->vl_addrs[cell->vl_naddrs++].s_addr =
81                         htonl((a << 24) | (b << 16) | (c << 8) | d);
82
83         } while (cell->vl_naddrs < AFS_CELL_MAX_ADDRS && (vllist = next));
84
85         /* create a key to represent an anonymous user */
86         memcpy(keyname, "afs@", 4);
87         dp = keyname + 4;
88         cp = cell->name;
89         do {
90                 *dp++ = toupper(*cp);
91         } while (*cp++);
92         cell->anonymous_key = key_alloc(&key_type_rxrpc, keyname, 0, 0, current,
93                                         KEY_POS_SEARCH, KEY_ALLOC_NOT_IN_QUOTA);
94         if (IS_ERR(cell->anonymous_key)) {
95                 _debug("no key");
96                 ret = PTR_ERR(cell->anonymous_key);
97                 goto error;
98         }
99
100         ret = key_instantiate_and_link(cell->anonymous_key, NULL, 0,
101                                        NULL, NULL);
102         if (ret < 0) {
103                 _debug("instantiate failed");
104                 goto error;
105         }
106
107         _debug("anon key %p{%x}",
108                cell->anonymous_key, key_serial(cell->anonymous_key));
109
110         _leave(" = %p", cell);
111         return cell;
112
113 bad_address:
114         printk(KERN_ERR "kAFS: bad VL server IP address\n");
115         ret = -EINVAL;
116 error:
117         key_put(cell->anonymous_key);
118         kfree(cell);
119         _leave(" = %d", ret);
120         return ERR_PTR(ret);
121 }
122
123 /*
124  * create a cell record
125  * - "name" is the name of the cell
126  * - "vllist" is a colon separated list of IP addresses in "a.b.c.d" format
127  */
128 struct afs_cell *afs_cell_create(const char *name, char *vllist)
129 {
130         struct afs_cell *cell;
131         int ret;
132
133         _enter("%s,%s", name, vllist);
134
135         cell = afs_cell_alloc(name, vllist);
136         if (IS_ERR(cell)) {
137                 _leave(" = %ld", PTR_ERR(cell));
138                 return cell;
139         }
140
141         down_write(&afs_cells_sem);
142
143         /* add a proc directory for this cell */
144         ret = afs_proc_cell_setup(cell);
145         if (ret < 0)
146                 goto error;
147
148 #ifdef AFS_CACHING_SUPPORT
149         /* put it up for caching */
150         cachefs_acquire_cookie(afs_cache_netfs.primary_index,
151                                &afs_vlocation_cache_index_def,
152                                cell,
153                                &cell->cache);
154 #endif
155
156         /* add to the cell lists */
157         write_lock(&afs_cells_lock);
158         list_add_tail(&cell->link, &afs_cells);
159         write_unlock(&afs_cells_lock);
160
161         down_write(&afs_proc_cells_sem);
162         list_add_tail(&cell->proc_link, &afs_proc_cells);
163         up_write(&afs_proc_cells_sem);
164         up_write(&afs_cells_sem);
165
166         _leave(" = %p", cell);
167         return cell;
168
169 error:
170         up_write(&afs_cells_sem);
171         key_put(cell->anonymous_key);
172         kfree(cell);
173         _leave(" = %d", ret);
174         return ERR_PTR(ret);
175 }
176
177 /*
178  * set the root cell information
179  * - can be called with a module parameter string
180  * - can be called from a write to /proc/fs/afs/rootcell
181  */
182 int afs_cell_init(char *rootcell)
183 {
184         struct afs_cell *old_root, *new_root;
185         char *cp;
186
187         _enter("");
188
189         if (!rootcell) {
190                 /* module is loaded with no parameters, or built statically.
191                  * - in the future we might initialize cell DB here.
192                  */
193                 _leave(" = 0 [no root]");
194                 return 0;
195         }
196
197         cp = strchr(rootcell, ':');
198         if (!cp) {
199                 printk(KERN_ERR "kAFS: no VL server IP addresses specified\n");
200                 _leave(" = -EINVAL");
201                 return -EINVAL;
202         }
203
204         /* allocate a cell record for the root cell */
205         *cp++ = 0;
206         new_root = afs_cell_create(rootcell, cp);
207         if (IS_ERR(new_root)) {
208                 _leave(" = %ld", PTR_ERR(new_root));
209                 return PTR_ERR(new_root);
210         }
211
212         /* install the new cell */
213         write_lock(&afs_cells_lock);
214         old_root = afs_cell_root;
215         afs_cell_root = new_root;
216         write_unlock(&afs_cells_lock);
217         afs_put_cell(old_root);
218
219         _leave(" = 0");
220         return 0;
221 }
222
223 /*
224  * lookup a cell record
225  */
226 struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz)
227 {
228         struct afs_cell *cell;
229
230         _enter("\"%*.*s\",", namesz, namesz, name ? name : "");
231
232         down_read(&afs_cells_sem);
233         read_lock(&afs_cells_lock);
234
235         if (name) {
236                 /* if the cell was named, look for it in the cell record list */
237                 list_for_each_entry(cell, &afs_cells, link) {
238                         if (strncmp(cell->name, name, namesz) == 0) {
239                                 afs_get_cell(cell);
240                                 goto found;
241                         }
242                 }
243                 cell = ERR_PTR(-ENOENT);
244         found:
245                 ;
246         } else {
247                 cell = afs_cell_root;
248                 if (!cell) {
249                         /* this should not happen unless user tries to mount
250                          * when root cell is not set. Return an impossibly
251                          * bizzare errno to alert the user. Things like
252                          * ENOENT might be "more appropriate" but they happen
253                          * for other reasons.
254                          */
255                         cell = ERR_PTR(-EDESTADDRREQ);
256                 } else {
257                         afs_get_cell(cell);
258                 }
259
260         }
261
262         read_unlock(&afs_cells_lock);
263         up_read(&afs_cells_sem);
264         _leave(" = %p", cell);
265         return cell;
266 }
267
268 #if 0
269 /*
270  * try and get a cell record
271  */
272 struct afs_cell *afs_get_cell_maybe(struct afs_cell *cell)
273 {
274         write_lock(&afs_cells_lock);
275
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         return cell;
283 }
284 #endif  /*  0  */
285
286 /*
287  * destroy a cell record
288  */
289 void afs_put_cell(struct afs_cell *cell)
290 {
291         if (!cell)
292                 return;
293
294         _enter("%p{%d,%s}", cell, atomic_read(&cell->usage), cell->name);
295
296         ASSERTCMP(atomic_read(&cell->usage), >, 0);
297
298         /* to prevent a race, the decrement and the dequeue must be effectively
299          * atomic */
300         write_lock(&afs_cells_lock);
301
302         if (likely(!atomic_dec_and_test(&cell->usage))) {
303                 write_unlock(&afs_cells_lock);
304                 _leave("");
305                 return;
306         }
307
308         ASSERT(list_empty(&cell->servers));
309         ASSERT(list_empty(&cell->vl_list));
310
311         write_unlock(&afs_cells_lock);
312
313         wake_up(&afs_cells_freeable_wq);
314
315         _leave(" [unused]");
316 }
317
318 /*
319  * destroy a cell record
320  * - must be called with the afs_cells_sem write-locked
321  * - cell->link should have been broken by the caller
322  */
323 static void afs_cell_destroy(struct afs_cell *cell)
324 {
325         _enter("%p{%d,%s}", cell, atomic_read(&cell->usage), cell->name);
326
327         ASSERTCMP(atomic_read(&cell->usage), >=, 0);
328         ASSERT(list_empty(&cell->link));
329
330         /* wait for everyone to stop using the cell */
331         if (atomic_read(&cell->usage) > 0) {
332                 DECLARE_WAITQUEUE(myself, current);
333
334                 _debug("wait for cell %s", cell->name);
335                 set_current_state(TASK_UNINTERRUPTIBLE);
336                 add_wait_queue(&afs_cells_freeable_wq, &myself);
337
338                 while (atomic_read(&cell->usage) > 0) {
339                         schedule();
340                         set_current_state(TASK_UNINTERRUPTIBLE);
341                 }
342
343                 remove_wait_queue(&afs_cells_freeable_wq, &myself);
344                 set_current_state(TASK_RUNNING);
345         }
346
347         _debug("cell dead");
348         ASSERTCMP(atomic_read(&cell->usage), ==, 0);
349         ASSERT(list_empty(&cell->servers));
350         ASSERT(list_empty(&cell->vl_list));
351
352         afs_proc_cell_remove(cell);
353
354         down_write(&afs_proc_cells_sem);
355         list_del_init(&cell->proc_link);
356         up_write(&afs_proc_cells_sem);
357
358 #ifdef AFS_CACHING_SUPPORT
359         cachefs_relinquish_cookie(cell->cache, 0);
360 #endif
361
362         key_put(cell->anonymous_key);
363         kfree(cell);
364
365         _leave(" [destroyed]");
366 }
367
368 /*
369  * purge in-memory cell database on module unload or afs_init() failure
370  * - the timeout daemon is stopped before calling this
371  */
372 void afs_cell_purge(void)
373 {
374         struct afs_cell *cell;
375
376         _enter("");
377
378         afs_put_cell(afs_cell_root);
379
380         down_write(&afs_cells_sem);
381
382         while (!list_empty(&afs_cells)) {
383                 cell = NULL;
384
385                 /* remove the next cell from the front of the list */
386                 write_lock(&afs_cells_lock);
387
388                 if (!list_empty(&afs_cells)) {
389                         cell = list_entry(afs_cells.next,
390                                           struct afs_cell, link);
391                         list_del_init(&cell->link);
392                 }
393
394                 write_unlock(&afs_cells_lock);
395
396                 if (cell) {
397                         _debug("PURGING CELL %s (%d)",
398                                cell->name, atomic_read(&cell->usage));
399
400                         /* now the cell should be left with no references */
401                         afs_cell_destroy(cell);
402                 }
403         }
404
405         up_write(&afs_cells_sem);
406         _leave("");
407 }