diff options
Diffstat (limited to 'fs/afs/volume.c')
-rw-r--r-- | fs/afs/volume.c | 141 |
1 files changed, 49 insertions, 92 deletions
diff --git a/fs/afs/volume.c b/fs/afs/volume.c index c82e1bb4f2dd..45491cfd4f4f 100644 --- a/fs/afs/volume.c +++ b/fs/afs/volume.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* AFS volume management | 1 | /* AFS volume management |
2 | * | 2 | * |
3 | * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved. |
4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
@@ -15,33 +15,9 @@ | |||
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/fs.h> | 16 | #include <linux/fs.h> |
17 | #include <linux/pagemap.h> | 17 | #include <linux/pagemap.h> |
18 | #include "volume.h" | ||
19 | #include "vnode.h" | ||
20 | #include "cell.h" | ||
21 | #include "cache.h" | ||
22 | #include "cmservice.h" | ||
23 | #include "fsclient.h" | ||
24 | #include "vlclient.h" | ||
25 | #include "internal.h" | 18 | #include "internal.h" |
26 | 19 | ||
27 | #ifdef __KDEBUG | ||
28 | static const char *afs_voltypes[] = { "R/W", "R/O", "BAK" }; | 20 | static const char *afs_voltypes[] = { "R/W", "R/O", "BAK" }; |
29 | #endif | ||
30 | |||
31 | #ifdef AFS_CACHING_SUPPORT | ||
32 | static cachefs_match_val_t afs_volume_cache_match(void *target, | ||
33 | const void *entry); | ||
34 | static void afs_volume_cache_update(void *source, void *entry); | ||
35 | |||
36 | struct cachefs_index_def afs_volume_cache_index_def = { | ||
37 | .name = "volume", | ||
38 | .data_size = sizeof(struct afs_cache_vhash), | ||
39 | .keys[0] = { CACHEFS_INDEX_KEYS_BIN, 1 }, | ||
40 | .keys[1] = { CACHEFS_INDEX_KEYS_BIN, 1 }, | ||
41 | .match = afs_volume_cache_match, | ||
42 | .update = afs_volume_cache_update, | ||
43 | }; | ||
44 | #endif | ||
45 | 21 | ||
46 | /* | 22 | /* |
47 | * lookup a volume by name | 23 | * lookup a volume by name |
@@ -65,11 +41,12 @@ struct cachefs_index_def afs_volume_cache_index_def = { | |||
65 | * - Rule 3: If parent volume is R/W, then only mount R/W volume unless | 41 | * - Rule 3: If parent volume is R/W, then only mount R/W volume unless |
66 | * explicitly told otherwise | 42 | * explicitly told otherwise |
67 | */ | 43 | */ |
68 | int afs_volume_lookup(const char *name, struct afs_cell *cell, int rwpath, | 44 | struct afs_volume *afs_volume_lookup(const char *name, struct afs_cell *cell, |
69 | struct afs_volume **_volume) | 45 | int rwpath) |
70 | { | 46 | { |
71 | struct afs_vlocation *vlocation = NULL; | 47 | struct afs_vlocation *vlocation = NULL; |
72 | struct afs_volume *volume = NULL; | 48 | struct afs_volume *volume = NULL; |
49 | struct afs_server *server = NULL; | ||
73 | afs_voltype_t type; | 50 | afs_voltype_t type; |
74 | const char *cellname, *volname, *suffix; | 51 | const char *cellname, *volname, *suffix; |
75 | char srvtmask; | 52 | char srvtmask; |
@@ -79,7 +56,7 @@ int afs_volume_lookup(const char *name, struct afs_cell *cell, int rwpath, | |||
79 | 56 | ||
80 | if (!name || (name[0] != '%' && name[0] != '#') || !name[1]) { | 57 | if (!name || (name[0] != '%' && name[0] != '#') || !name[1]) { |
81 | printk("kAFS: unparsable volume name\n"); | 58 | printk("kAFS: unparsable volume name\n"); |
82 | return -EINVAL; | 59 | return ERR_PTR(-EINVAL); |
83 | } | 60 | } |
84 | 61 | ||
85 | /* determine the type of volume we're looking for */ | 62 | /* determine the type of volume we're looking for */ |
@@ -128,8 +105,9 @@ int afs_volume_lookup(const char *name, struct afs_cell *cell, int rwpath, | |||
128 | 105 | ||
129 | /* lookup the cell record */ | 106 | /* lookup the cell record */ |
130 | if (cellname || !cell) { | 107 | if (cellname || !cell) { |
131 | ret = afs_cell_lookup(cellname, cellnamesz, &cell); | 108 | cell = afs_cell_lookup(cellname, cellnamesz); |
132 | if (ret<0) { | 109 | if (IS_ERR(cell)) { |
110 | ret = PTR_ERR(cell); | ||
133 | printk("kAFS: unable to lookup cell '%s'\n", | 111 | printk("kAFS: unable to lookup cell '%s'\n", |
134 | cellname ?: ""); | 112 | cellname ?: ""); |
135 | goto error; | 113 | goto error; |
@@ -139,9 +117,12 @@ int afs_volume_lookup(const char *name, struct afs_cell *cell, int rwpath, | |||
139 | } | 117 | } |
140 | 118 | ||
141 | /* lookup the volume location record */ | 119 | /* lookup the volume location record */ |
142 | ret = afs_vlocation_lookup(cell, volname, volnamesz, &vlocation); | 120 | vlocation = afs_vlocation_lookup(cell, volname, volnamesz); |
143 | if (ret < 0) | 121 | if (IS_ERR(vlocation)) { |
122 | ret = PTR_ERR(vlocation); | ||
123 | vlocation = NULL; | ||
144 | goto error; | 124 | goto error; |
125 | } | ||
145 | 126 | ||
146 | /* make the final decision on the type we want */ | 127 | /* make the final decision on the type we want */ |
147 | ret = -ENOMEDIUM; | 128 | ret = -ENOMEDIUM; |
@@ -192,13 +173,14 @@ int afs_volume_lookup(const char *name, struct afs_cell *cell, int rwpath, | |||
192 | /* look up all the applicable server records */ | 173 | /* look up all the applicable server records */ |
193 | for (loop = 0; loop < 8; loop++) { | 174 | for (loop = 0; loop < 8; loop++) { |
194 | if (vlocation->vldb.srvtmask[loop] & (1 << volume->type)) { | 175 | if (vlocation->vldb.srvtmask[loop] & (1 << volume->type)) { |
195 | ret = afs_server_lookup( | 176 | server = afs_lookup_server( |
196 | volume->cell, | 177 | volume->cell, &vlocation->vldb.servers[loop]); |
197 | &vlocation->vldb.servers[loop], | 178 | if (IS_ERR(server)) { |
198 | &volume->servers[volume->nservers]); | 179 | ret = PTR_ERR(server); |
199 | if (ret < 0) | ||
200 | goto error_discard; | 180 | goto error_discard; |
181 | } | ||
201 | 182 | ||
183 | volume->servers[volume->nservers] = server; | ||
202 | volume->nservers++; | 184 | volume->nservers++; |
203 | } | 185 | } |
204 | } | 186 | } |
@@ -219,8 +201,11 @@ int afs_volume_lookup(const char *name, struct afs_cell *cell, int rwpath, | |||
219 | success: | 201 | success: |
220 | _debug("kAFS selected %s volume %08x", | 202 | _debug("kAFS selected %s volume %08x", |
221 | afs_voltypes[volume->type], volume->vid); | 203 | afs_voltypes[volume->type], volume->vid); |
222 | *_volume = volume; | 204 | up_write(&cell->vl_sem); |
223 | ret = 0; | 205 | afs_put_vlocation(vlocation); |
206 | afs_put_cell(cell); | ||
207 | _leave(" = %p", volume); | ||
208 | return volume; | ||
224 | 209 | ||
225 | /* clean up */ | 210 | /* clean up */ |
226 | error_up: | 211 | error_up: |
@@ -228,9 +213,8 @@ error_up: | |||
228 | error: | 213 | error: |
229 | afs_put_vlocation(vlocation); | 214 | afs_put_vlocation(vlocation); |
230 | afs_put_cell(cell); | 215 | afs_put_cell(cell); |
231 | 216 | _leave(" = %d", ret); | |
232 | _leave(" = %d (%p)", ret, volume); | 217 | return ERR_PTR(ret); |
233 | return ret; | ||
234 | 218 | ||
235 | error_discard: | 219 | error_discard: |
236 | up_write(&cell->vl_sem); | 220 | up_write(&cell->vl_sem); |
@@ -255,10 +239,9 @@ void afs_put_volume(struct afs_volume *volume) | |||
255 | 239 | ||
256 | _enter("%p", volume); | 240 | _enter("%p", volume); |
257 | 241 | ||
258 | vlocation = volume->vlocation; | 242 | ASSERTCMP(atomic_read(&volume->usage), >, 0); |
259 | 243 | ||
260 | /* sanity check */ | 244 | vlocation = volume->vlocation; |
261 | BUG_ON(atomic_read(&volume->usage) <= 0); | ||
262 | 245 | ||
263 | /* to prevent a race, the decrement and the dequeue must be effectively | 246 | /* to prevent a race, the decrement and the dequeue must be effectively |
264 | * atomic */ | 247 | * atomic */ |
@@ -292,14 +275,21 @@ void afs_put_volume(struct afs_volume *volume) | |||
292 | * pick a server to use to try accessing this volume | 275 | * pick a server to use to try accessing this volume |
293 | * - returns with an elevated usage count on the server chosen | 276 | * - returns with an elevated usage count on the server chosen |
294 | */ | 277 | */ |
295 | int afs_volume_pick_fileserver(struct afs_volume *volume, | 278 | struct afs_server *afs_volume_pick_fileserver(struct afs_vnode *vnode) |
296 | struct afs_server **_server) | ||
297 | { | 279 | { |
280 | struct afs_volume *volume = vnode->volume; | ||
298 | struct afs_server *server; | 281 | struct afs_server *server; |
299 | int ret, state, loop; | 282 | int ret, state, loop; |
300 | 283 | ||
301 | _enter("%s", volume->vlocation->vldb.name); | 284 | _enter("%s", volume->vlocation->vldb.name); |
302 | 285 | ||
286 | /* stick with the server we're already using if we can */ | ||
287 | if (vnode->server && vnode->server->fs_state == 0) { | ||
288 | afs_get_server(vnode->server); | ||
289 | _leave(" = %p [current]", vnode->server); | ||
290 | return vnode->server; | ||
291 | } | ||
292 | |||
303 | down_read(&volume->server_sem); | 293 | down_read(&volume->server_sem); |
304 | 294 | ||
305 | /* handle the no-server case */ | 295 | /* handle the no-server case */ |
@@ -307,7 +297,7 @@ int afs_volume_pick_fileserver(struct afs_volume *volume, | |||
307 | ret = volume->rjservers ? -ENOMEDIUM : -ESTALE; | 297 | ret = volume->rjservers ? -ENOMEDIUM : -ESTALE; |
308 | up_read(&volume->server_sem); | 298 | up_read(&volume->server_sem); |
309 | _leave(" = %d [no servers]", ret); | 299 | _leave(" = %d [no servers]", ret); |
310 | return ret; | 300 | return ERR_PTR(ret); |
311 | } | 301 | } |
312 | 302 | ||
313 | /* basically, just search the list for the first live server and use | 303 | /* basically, just search the list for the first live server and use |
@@ -317,15 +307,16 @@ int afs_volume_pick_fileserver(struct afs_volume *volume, | |||
317 | server = volume->servers[loop]; | 307 | server = volume->servers[loop]; |
318 | state = server->fs_state; | 308 | state = server->fs_state; |
319 | 309 | ||
310 | _debug("consider %d [%d]", loop, state); | ||
311 | |||
320 | switch (state) { | 312 | switch (state) { |
321 | /* found an apparently healthy server */ | 313 | /* found an apparently healthy server */ |
322 | case 0: | 314 | case 0: |
323 | afs_get_server(server); | 315 | afs_get_server(server); |
324 | up_read(&volume->server_sem); | 316 | up_read(&volume->server_sem); |
325 | *_server = server; | 317 | _leave(" = %p (picked %08x)", |
326 | _leave(" = 0 (picked %08x)", | 318 | server, ntohl(server->addr.s_addr)); |
327 | ntohl(server->addr.s_addr)); | 319 | return server; |
328 | return 0; | ||
329 | 320 | ||
330 | case -ENETUNREACH: | 321 | case -ENETUNREACH: |
331 | if (ret == 0) | 322 | if (ret == 0) |
@@ -361,7 +352,7 @@ int afs_volume_pick_fileserver(struct afs_volume *volume, | |||
361 | */ | 352 | */ |
362 | up_read(&volume->server_sem); | 353 | up_read(&volume->server_sem); |
363 | _leave(" = %d", ret); | 354 | _leave(" = %d", ret); |
364 | return ret; | 355 | return ERR_PTR(ret); |
365 | } | 356 | } |
366 | 357 | ||
367 | /* | 358 | /* |
@@ -370,10 +361,11 @@ int afs_volume_pick_fileserver(struct afs_volume *volume, | |||
370 | * - records result of using a particular server to access a volume | 361 | * - records result of using a particular server to access a volume |
371 | * - return 0 to try again, 1 if okay or to issue error | 362 | * - return 0 to try again, 1 if okay or to issue error |
372 | */ | 363 | */ |
373 | int afs_volume_release_fileserver(struct afs_volume *volume, | 364 | int afs_volume_release_fileserver(struct afs_vnode *vnode, |
374 | struct afs_server *server, | 365 | struct afs_server *server, |
375 | int result) | 366 | int result) |
376 | { | 367 | { |
368 | struct afs_volume *volume = vnode->volume; | ||
377 | unsigned loop; | 369 | unsigned loop; |
378 | 370 | ||
379 | _enter("%s,%08x,%d", | 371 | _enter("%s,%08x,%d", |
@@ -384,6 +376,7 @@ int afs_volume_release_fileserver(struct afs_volume *volume, | |||
384 | /* success */ | 376 | /* success */ |
385 | case 0: | 377 | case 0: |
386 | server->fs_act_jif = jiffies; | 378 | server->fs_act_jif = jiffies; |
379 | server->fs_state = 0; | ||
387 | break; | 380 | break; |
388 | 381 | ||
389 | /* the fileserver denied all knowledge of the volume */ | 382 | /* the fileserver denied all knowledge of the volume */ |
@@ -391,7 +384,7 @@ int afs_volume_release_fileserver(struct afs_volume *volume, | |||
391 | server->fs_act_jif = jiffies; | 384 | server->fs_act_jif = jiffies; |
392 | down_write(&volume->server_sem); | 385 | down_write(&volume->server_sem); |
393 | 386 | ||
394 | /* first, find where the server is in the active list (if it | 387 | /* firstly, find where the server is in the active list (if it |
395 | * is) */ | 388 | * is) */ |
396 | for (loop = 0; loop < volume->nservers; loop++) | 389 | for (loop = 0; loop < volume->nservers; loop++) |
397 | if (volume->servers[loop] == server) | 390 | if (volume->servers[loop] == server) |
@@ -429,6 +422,7 @@ int afs_volume_release_fileserver(struct afs_volume *volume, | |||
429 | case -ENETUNREACH: | 422 | case -ENETUNREACH: |
430 | case -EHOSTUNREACH: | 423 | case -EHOSTUNREACH: |
431 | case -ECONNREFUSED: | 424 | case -ECONNREFUSED: |
425 | case -ETIME: | ||
432 | case -ETIMEDOUT: | 426 | case -ETIMEDOUT: |
433 | case -EREMOTEIO: | 427 | case -EREMOTEIO: |
434 | /* mark the server as dead | 428 | /* mark the server as dead |
@@ -464,40 +458,3 @@ try_next_server: | |||
464 | _leave(" [try next server]"); | 458 | _leave(" [try next server]"); |
465 | return 0; | 459 | return 0; |
466 | } | 460 | } |
467 | |||
468 | /* | ||
469 | * match a volume hash record stored in the cache | ||
470 | */ | ||
471 | #ifdef AFS_CACHING_SUPPORT | ||
472 | static cachefs_match_val_t afs_volume_cache_match(void *target, | ||
473 | const void *entry) | ||
474 | { | ||
475 | const struct afs_cache_vhash *vhash = entry; | ||
476 | struct afs_volume *volume = target; | ||
477 | |||
478 | _enter("{%u},{%u}", volume->type, vhash->vtype); | ||
479 | |||
480 | if (volume->type == vhash->vtype) { | ||
481 | _leave(" = SUCCESS"); | ||
482 | return CACHEFS_MATCH_SUCCESS; | ||
483 | } | ||
484 | |||
485 | _leave(" = FAILED"); | ||
486 | return CACHEFS_MATCH_FAILED; | ||
487 | } | ||
488 | #endif | ||
489 | |||
490 | /* | ||
491 | * update a volume hash record stored in the cache | ||
492 | */ | ||
493 | #ifdef AFS_CACHING_SUPPORT | ||
494 | static void afs_volume_cache_update(void *source, void *entry) | ||
495 | { | ||
496 | struct afs_cache_vhash *vhash = entry; | ||
497 | struct afs_volume *volume = source; | ||
498 | |||
499 | _enter(""); | ||
500 | |||
501 | vhash->vtype = volume->type; | ||
502 | } | ||
503 | #endif | ||