aboutsummaryrefslogtreecommitdiffstats
path: root/fs/afs/volume.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/afs/volume.c')
-rw-r--r--fs/afs/volume.c141
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
28static const char *afs_voltypes[] = { "R/W", "R/O", "BAK" }; 20static const char *afs_voltypes[] = { "R/W", "R/O", "BAK" };
29#endif
30
31#ifdef AFS_CACHING_SUPPORT
32static cachefs_match_val_t afs_volume_cache_match(void *target,
33 const void *entry);
34static void afs_volume_cache_update(void *source, void *entry);
35
36struct 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 */
68int afs_volume_lookup(const char *name, struct afs_cell *cell, int rwpath, 44struct 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,
219success: 201success:
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 */
226error_up: 211error_up:
@@ -228,9 +213,8 @@ error_up:
228error: 213error:
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
235error_discard: 219error_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 */
295int afs_volume_pick_fileserver(struct afs_volume *volume, 278struct 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 */
373int afs_volume_release_fileserver(struct afs_volume *volume, 364int 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
472static 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
494static 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