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.c290
1 files changed, 83 insertions, 207 deletions
diff --git a/fs/afs/volume.c b/fs/afs/volume.c
index 768c6dbd323a..dd160cada45d 100644
--- a/fs/afs/volume.c
+++ b/fs/afs/volume.c
@@ -1,6 +1,6 @@
1/* volume.c: 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,35 +15,10 @@
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/*****************************************************************************/
47/* 22/*
48 * lookup a volume by name 23 * lookup a volume by name
49 * - this can be one of the following: 24 * - this can be one of the following:
@@ -66,118 +41,52 @@ struct cachefs_index_def afs_volume_cache_index_def = {
66 * - 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
67 * explicitly told otherwise 42 * explicitly told otherwise
68 */ 43 */
69int afs_volume_lookup(const char *name, struct afs_cell *cell, int rwpath, 44struct afs_volume *afs_volume_lookup(struct afs_mount_params *params)
70 struct afs_volume **_volume)
71{ 45{
72 struct afs_vlocation *vlocation = NULL; 46 struct afs_vlocation *vlocation = NULL;
73 struct afs_volume *volume = NULL; 47 struct afs_volume *volume = NULL;
74 afs_voltype_t type; 48 struct afs_server *server = NULL;
75 const char *cellname, *volname, *suffix;
76 char srvtmask; 49 char srvtmask;
77 int force, ret, loop, cellnamesz, volnamesz; 50 int ret, loop;
78
79 _enter("%s,,%d,", name, rwpath);
80
81 if (!name || (name[0] != '%' && name[0] != '#') || !name[1]) {
82 printk("kAFS: unparsable volume name\n");
83 return -EINVAL;
84 }
85
86 /* determine the type of volume we're looking for */
87 force = 0;
88 type = AFSVL_ROVOL;
89
90 if (rwpath || name[0] == '%') {
91 type = AFSVL_RWVOL;
92 force = 1;
93 }
94
95 suffix = strrchr(name, '.');
96 if (suffix) {
97 if (strcmp(suffix, ".readonly") == 0) {
98 type = AFSVL_ROVOL;
99 force = 1;
100 }
101 else if (strcmp(suffix, ".backup") == 0) {
102 type = AFSVL_BACKVOL;
103 force = 1;
104 }
105 else if (suffix[1] == 0) {
106 }
107 else {
108 suffix = NULL;
109 }
110 }
111 51
112 /* split the cell and volume names */ 52 _enter("{%*.*s,%d}",
113 name++; 53 params->volnamesz, params->volnamesz, params->volname, params->rwpath);
114 volname = strchr(name, ':');
115 if (volname) {
116 cellname = name;
117 cellnamesz = volname - name;
118 volname++;
119 }
120 else {
121 volname = name;
122 cellname = NULL;
123 cellnamesz = 0;
124 }
125
126 volnamesz = suffix ? suffix - volname : strlen(volname);
127
128 _debug("CELL:%*.*s [%p] VOLUME:%*.*s SUFFIX:%s TYPE:%d%s",
129 cellnamesz, cellnamesz, cellname ?: "", cell,
130 volnamesz, volnamesz, volname, suffix ?: "-",
131 type,
132 force ? " FORCE" : "");
133
134 /* lookup the cell record */
135 if (cellname || !cell) {
136 ret = afs_cell_lookup(cellname, cellnamesz, &cell);
137 if (ret<0) {
138 printk("kAFS: unable to lookup cell '%s'\n",
139 cellname ?: "");
140 goto error;
141 }
142 }
143 else {
144 afs_get_cell(cell);
145 }
146 54
147 /* lookup the volume location record */ 55 /* lookup the volume location record */
148 ret = afs_vlocation_lookup(cell, volname, volnamesz, &vlocation); 56 vlocation = afs_vlocation_lookup(params->cell, params->key,
149 if (ret < 0) 57 params->volname, params->volnamesz);
58 if (IS_ERR(vlocation)) {
59 ret = PTR_ERR(vlocation);
60 vlocation = NULL;
150 goto error; 61 goto error;
62 }
151 63
152 /* make the final decision on the type we want */ 64 /* make the final decision on the type we want */
153 ret = -ENOMEDIUM; 65 ret = -ENOMEDIUM;
154 if (force && !(vlocation->vldb.vidmask & (1 << type))) 66 if (params->force && !(vlocation->vldb.vidmask & (1 << params->type)))
155 goto error; 67 goto error;
156 68
157 srvtmask = 0; 69 srvtmask = 0;
158 for (loop = 0; loop < vlocation->vldb.nservers; loop++) 70 for (loop = 0; loop < vlocation->vldb.nservers; loop++)
159 srvtmask |= vlocation->vldb.srvtmask[loop]; 71 srvtmask |= vlocation->vldb.srvtmask[loop];
160 72
161 if (force) { 73 if (params->force) {
162 if (!(srvtmask & (1 << type))) 74 if (!(srvtmask & (1 << params->type)))
163 goto error; 75 goto error;
164 } 76 } else if (srvtmask & AFS_VOL_VTM_RO) {
165 else if (srvtmask & AFS_VOL_VTM_RO) { 77 params->type = AFSVL_ROVOL;
166 type = AFSVL_ROVOL; 78 } else if (srvtmask & AFS_VOL_VTM_RW) {
167 } 79 params->type = AFSVL_RWVOL;
168 else if (srvtmask & AFS_VOL_VTM_RW) { 80 } else {
169 type = AFSVL_RWVOL;
170 }
171 else {
172 goto error; 81 goto error;
173 } 82 }
174 83
175 down_write(&cell->vl_sem); 84 down_write(&params->cell->vl_sem);
176 85
177 /* is the volume already active? */ 86 /* is the volume already active? */
178 if (vlocation->vols[type]) { 87 if (vlocation->vols[params->type]) {
179 /* yes - re-use it */ 88 /* yes - re-use it */
180 volume = vlocation->vols[type]; 89 volume = vlocation->vols[params->type];
181 afs_get_volume(volume); 90 afs_get_volume(volume);
182 goto success; 91 goto success;
183 } 92 }
@@ -191,23 +100,24 @@ int afs_volume_lookup(const char *name, struct afs_cell *cell, int rwpath,
191 goto error_up; 100 goto error_up;
192 101
193 atomic_set(&volume->usage, 1); 102 atomic_set(&volume->usage, 1);
194 volume->type = type; 103 volume->type = params->type;
195 volume->type_force = force; 104 volume->type_force = params->force;
196 volume->cell = cell; 105 volume->cell = params->cell;
197 volume->vid = vlocation->vldb.vid[type]; 106 volume->vid = vlocation->vldb.vid[params->type];
198 107
199 init_rwsem(&volume->server_sem); 108 init_rwsem(&volume->server_sem);
200 109
201 /* look up all the applicable server records */ 110 /* look up all the applicable server records */
202 for (loop = 0; loop < 8; loop++) { 111 for (loop = 0; loop < 8; loop++) {
203 if (vlocation->vldb.srvtmask[loop] & (1 << volume->type)) { 112 if (vlocation->vldb.srvtmask[loop] & (1 << volume->type)) {
204 ret = afs_server_lookup( 113 server = afs_lookup_server(
205 volume->cell, 114 volume->cell, &vlocation->vldb.servers[loop]);
206 &vlocation->vldb.servers[loop], 115 if (IS_ERR(server)) {
207 &volume->servers[volume->nservers]); 116 ret = PTR_ERR(server);
208 if (ret < 0)
209 goto error_discard; 117 goto error_discard;
118 }
210 119
120 volume->servers[volume->nservers] = server;
211 volume->nservers++; 121 volume->nservers++;
212 } 122 }
213 } 123 }
@@ -223,35 +133,34 @@ int afs_volume_lookup(const char *name, struct afs_cell *cell, int rwpath,
223 afs_get_vlocation(vlocation); 133 afs_get_vlocation(vlocation);
224 volume->vlocation = vlocation; 134 volume->vlocation = vlocation;
225 135
226 vlocation->vols[type] = volume; 136 vlocation->vols[volume->type] = volume;
227 137
228 success: 138success:
229 _debug("kAFS selected %s volume %08x", 139 _debug("kAFS selected %s volume %08x",
230 afs_voltypes[volume->type], volume->vid); 140 afs_voltypes[volume->type], volume->vid);
231 *_volume = volume; 141 up_write(&params->cell->vl_sem);
232 ret = 0; 142 afs_put_vlocation(vlocation);
143 _leave(" = %p", volume);
144 return volume;
233 145
234 /* clean up */ 146 /* clean up */
235 error_up: 147error_up:
236 up_write(&cell->vl_sem); 148 up_write(&params->cell->vl_sem);
237 error: 149error:
238 afs_put_vlocation(vlocation); 150 afs_put_vlocation(vlocation);
239 afs_put_cell(cell); 151 _leave(" = %d", ret);
240 152 return ERR_PTR(ret);
241 _leave(" = %d (%p)", ret, volume);
242 return ret;
243 153
244 error_discard: 154error_discard:
245 up_write(&cell->vl_sem); 155 up_write(&params->cell->vl_sem);
246 156
247 for (loop = volume->nservers - 1; loop >= 0; loop--) 157 for (loop = volume->nservers - 1; loop >= 0; loop--)
248 afs_put_server(volume->servers[loop]); 158 afs_put_server(volume->servers[loop]);
249 159
250 kfree(volume); 160 kfree(volume);
251 goto error; 161 goto error;
252} /* end afs_volume_lookup() */ 162}
253 163
254/*****************************************************************************/
255/* 164/*
256 * destroy a volume record 165 * destroy a volume record
257 */ 166 */
@@ -265,10 +174,9 @@ void afs_put_volume(struct afs_volume *volume)
265 174
266 _enter("%p", volume); 175 _enter("%p", volume);
267 176
268 vlocation = volume->vlocation; 177 ASSERTCMP(atomic_read(&volume->usage), >, 0);
269 178
270 /* sanity check */ 179 vlocation = volume->vlocation;
271 BUG_ON(atomic_read(&volume->usage) <= 0);
272 180
273 /* to prevent a race, the decrement and the dequeue must be effectively 181 /* to prevent a race, the decrement and the dequeue must be effectively
274 * atomic */ 182 * atomic */
@@ -296,21 +204,27 @@ void afs_put_volume(struct afs_volume *volume)
296 kfree(volume); 204 kfree(volume);
297 205
298 _leave(" [destroyed]"); 206 _leave(" [destroyed]");
299} /* end afs_put_volume() */ 207}
300 208
301/*****************************************************************************/
302/* 209/*
303 * pick a server to use to try accessing this volume 210 * pick a server to use to try accessing this volume
304 * - returns with an elevated usage count on the server chosen 211 * - returns with an elevated usage count on the server chosen
305 */ 212 */
306int afs_volume_pick_fileserver(struct afs_volume *volume, 213struct afs_server *afs_volume_pick_fileserver(struct afs_vnode *vnode)
307 struct afs_server **_server)
308{ 214{
215 struct afs_volume *volume = vnode->volume;
309 struct afs_server *server; 216 struct afs_server *server;
310 int ret, state, loop; 217 int ret, state, loop;
311 218
312 _enter("%s", volume->vlocation->vldb.name); 219 _enter("%s", volume->vlocation->vldb.name);
313 220
221 /* stick with the server we're already using if we can */
222 if (vnode->server && vnode->server->fs_state == 0) {
223 afs_get_server(vnode->server);
224 _leave(" = %p [current]", vnode->server);
225 return vnode->server;
226 }
227
314 down_read(&volume->server_sem); 228 down_read(&volume->server_sem);
315 229
316 /* handle the no-server case */ 230 /* handle the no-server case */
@@ -318,7 +232,7 @@ int afs_volume_pick_fileserver(struct afs_volume *volume,
318 ret = volume->rjservers ? -ENOMEDIUM : -ESTALE; 232 ret = volume->rjservers ? -ENOMEDIUM : -ESTALE;
319 up_read(&volume->server_sem); 233 up_read(&volume->server_sem);
320 _leave(" = %d [no servers]", ret); 234 _leave(" = %d [no servers]", ret);
321 return ret; 235 return ERR_PTR(ret);
322 } 236 }
323 237
324 /* basically, just search the list for the first live server and use 238 /* basically, just search the list for the first live server and use
@@ -328,15 +242,16 @@ int afs_volume_pick_fileserver(struct afs_volume *volume,
328 server = volume->servers[loop]; 242 server = volume->servers[loop];
329 state = server->fs_state; 243 state = server->fs_state;
330 244
245 _debug("consider %d [%d]", loop, state);
246
331 switch (state) { 247 switch (state) {
332 /* found an apparently healthy server */ 248 /* found an apparently healthy server */
333 case 0: 249 case 0:
334 afs_get_server(server); 250 afs_get_server(server);
335 up_read(&volume->server_sem); 251 up_read(&volume->server_sem);
336 *_server = server; 252 _leave(" = %p (picked %08x)",
337 _leave(" = 0 (picked %08x)", 253 server, ntohl(server->addr.s_addr));
338 ntohl(server->addr.s_addr)); 254 return server;
339 return 0;
340 255
341 case -ENETUNREACH: 256 case -ENETUNREACH:
342 if (ret == 0) 257 if (ret == 0)
@@ -372,20 +287,21 @@ int afs_volume_pick_fileserver(struct afs_volume *volume,
372 */ 287 */
373 up_read(&volume->server_sem); 288 up_read(&volume->server_sem);
374 _leave(" = %d", ret); 289 _leave(" = %d", ret);
375 return ret; 290 return ERR_PTR(ret);
376} /* end afs_volume_pick_fileserver() */ 291}
377 292
378/*****************************************************************************/
379/* 293/*
380 * release a server after use 294 * release a server after use
381 * - releases the ref on the server struct that was acquired by picking 295 * - releases the ref on the server struct that was acquired by picking
382 * - records result of using a particular server to access a volume 296 * - records result of using a particular server to access a volume
383 * - return 0 to try again, 1 if okay or to issue error 297 * - return 0 to try again, 1 if okay or to issue error
298 * - the caller must release the server struct if result was 0
384 */ 299 */
385int afs_volume_release_fileserver(struct afs_volume *volume, 300int afs_volume_release_fileserver(struct afs_vnode *vnode,
386 struct afs_server *server, 301 struct afs_server *server,
387 int result) 302 int result)
388{ 303{
304 struct afs_volume *volume = vnode->volume;
389 unsigned loop; 305 unsigned loop;
390 306
391 _enter("%s,%08x,%d", 307 _enter("%s,%08x,%d",
@@ -396,14 +312,16 @@ int afs_volume_release_fileserver(struct afs_volume *volume,
396 /* success */ 312 /* success */
397 case 0: 313 case 0:
398 server->fs_act_jif = jiffies; 314 server->fs_act_jif = jiffies;
399 break; 315 server->fs_state = 0;
316 _leave("");
317 return 1;
400 318
401 /* the fileserver denied all knowledge of the volume */ 319 /* the fileserver denied all knowledge of the volume */
402 case -ENOMEDIUM: 320 case -ENOMEDIUM:
403 server->fs_act_jif = jiffies; 321 server->fs_act_jif = jiffies;
404 down_write(&volume->server_sem); 322 down_write(&volume->server_sem);
405 323
406 /* first, find where the server is in the active list (if it 324 /* firstly, find where the server is in the active list (if it
407 * is) */ 325 * is) */
408 for (loop = 0; loop < volume->nservers; loop++) 326 for (loop = 0; loop < volume->nservers; loop++)
409 if (volume->servers[loop] == server) 327 if (volume->servers[loop] == server)
@@ -441,6 +359,7 @@ int afs_volume_release_fileserver(struct afs_volume *volume,
441 case -ENETUNREACH: 359 case -ENETUNREACH:
442 case -EHOSTUNREACH: 360 case -EHOSTUNREACH:
443 case -ECONNREFUSED: 361 case -ECONNREFUSED:
362 case -ETIME:
444 case -ETIMEDOUT: 363 case -ETIMEDOUT:
445 case -EREMOTEIO: 364 case -EREMOTEIO:
446 /* mark the server as dead 365 /* mark the server as dead
@@ -460,60 +379,17 @@ int afs_volume_release_fileserver(struct afs_volume *volume,
460 server->fs_act_jif = jiffies; 379 server->fs_act_jif = jiffies;
461 case -ENOMEM: 380 case -ENOMEM:
462 case -ENONET: 381 case -ENONET:
463 break; 382 /* tell the caller to accept the result */
383 afs_put_server(server);
384 _leave(" [local failure]");
385 return 1;
464 } 386 }
465 387
466 /* tell the caller to accept the result */
467 afs_put_server(server);
468 _leave("");
469 return 1;
470
471 /* tell the caller to loop around and try the next server */ 388 /* tell the caller to loop around and try the next server */
472 try_next_server_upw: 389try_next_server_upw:
473 up_write(&volume->server_sem); 390 up_write(&volume->server_sem);
474 try_next_server: 391try_next_server:
475 afs_put_server(server); 392 afs_put_server(server);
476 _leave(" [try next server]"); 393 _leave(" [try next server]");
477 return 0; 394 return 0;
478 395}
479} /* end afs_volume_release_fileserver() */
480
481/*****************************************************************************/
482/*
483 * match a volume hash record stored in the cache
484 */
485#ifdef AFS_CACHING_SUPPORT
486static cachefs_match_val_t afs_volume_cache_match(void *target,
487 const void *entry)
488{
489 const struct afs_cache_vhash *vhash = entry;
490 struct afs_volume *volume = target;
491
492 _enter("{%u},{%u}", volume->type, vhash->vtype);
493
494 if (volume->type == vhash->vtype) {
495 _leave(" = SUCCESS");
496 return CACHEFS_MATCH_SUCCESS;
497 }
498
499 _leave(" = FAILED");
500 return CACHEFS_MATCH_FAILED;
501} /* end afs_volume_cache_match() */
502#endif
503
504/*****************************************************************************/
505/*
506 * update a volume hash record stored in the cache
507 */
508#ifdef AFS_CACHING_SUPPORT
509static void afs_volume_cache_update(void *source, void *entry)
510{
511 struct afs_cache_vhash *vhash = entry;
512 struct afs_volume *volume = source;
513
514 _enter("");
515
516 vhash->vtype = volume->type;
517
518} /* end afs_volume_cache_update() */
519#endif