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