]> bbs.cooldavid.org Git - net-next-2.6.git/blame - fs/afs/volume.c
[AF_RXRPC]: Add an interface to the AF_RXRPC module for the AFS filesystem to use
[net-next-2.6.git] / fs / afs / volume.c
CommitLineData
ec26815a 1/* AFS volume management
1da177e4
LT
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/kernel.h>
13#include <linux/module.h>
14#include <linux/init.h>
15#include <linux/slab.h>
16#include <linux/fs.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"
26
27#ifdef __KDEBUG
28static 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
1da177e4
LT
46/*
47 * lookup a volume by name
48 * - this can be one of the following:
49 * "%[cell:]volume[.]" R/W volume
50 * "#[cell:]volume[.]" R/O or R/W volume (rwparent=0),
51 * or R/W (rwparent=1) volume
52 * "%[cell:]volume.readonly" R/O volume
53 * "#[cell:]volume.readonly" R/O volume
54 * "%[cell:]volume.backup" Backup volume
55 * "#[cell:]volume.backup" Backup volume
56 *
57 * The cell name is optional, and defaults to the current cell.
58 *
59 * See "The Rules of Mount Point Traversal" in Chapter 5 of the AFS SysAdmin
60 * Guide
61 * - Rule 1: Explicit type suffix forces access of that type or nothing
62 * (no suffix, then use Rule 2 & 3)
63 * - Rule 2: If parent volume is R/O, then mount R/O volume by preference, R/W
64 * if not available
65 * - Rule 3: If parent volume is R/W, then only mount R/W volume unless
66 * explicitly told otherwise
67 */
68int afs_volume_lookup(const char *name, struct afs_cell *cell, int rwpath,
69 struct afs_volume **_volume)
70{
71 struct afs_vlocation *vlocation = NULL;
72 struct afs_volume *volume = NULL;
73 afs_voltype_t type;
74 const char *cellname, *volname, *suffix;
75 char srvtmask;
76 int force, ret, loop, cellnamesz, volnamesz;
77
78 _enter("%s,,%d,", name, rwpath);
79
80 if (!name || (name[0] != '%' && name[0] != '#') || !name[1]) {
81 printk("kAFS: unparsable volume name\n");
82 return -EINVAL;
83 }
84
85 /* determine the type of volume we're looking for */
86 force = 0;
87 type = AFSVL_ROVOL;
88
89 if (rwpath || name[0] == '%') {
90 type = AFSVL_RWVOL;
91 force = 1;
92 }
93
94 suffix = strrchr(name, '.');
95 if (suffix) {
96 if (strcmp(suffix, ".readonly") == 0) {
97 type = AFSVL_ROVOL;
98 force = 1;
ec26815a 99 } else if (strcmp(suffix, ".backup") == 0) {
1da177e4
LT
100 type = AFSVL_BACKVOL;
101 force = 1;
ec26815a
DH
102 } else if (suffix[1] == 0) {
103 } else {
1da177e4
LT
104 suffix = NULL;
105 }
106 }
107
108 /* split the cell and volume names */
109 name++;
110 volname = strchr(name, ':');
111 if (volname) {
112 cellname = name;
113 cellnamesz = volname - name;
114 volname++;
ec26815a 115 } else {
1da177e4
LT
116 volname = name;
117 cellname = NULL;
118 cellnamesz = 0;
119 }
120
121 volnamesz = suffix ? suffix - volname : strlen(volname);
122
123 _debug("CELL:%*.*s [%p] VOLUME:%*.*s SUFFIX:%s TYPE:%d%s",
124 cellnamesz, cellnamesz, cellname ?: "", cell,
125 volnamesz, volnamesz, volname, suffix ?: "-",
126 type,
127 force ? " FORCE" : "");
128
129 /* lookup the cell record */
130 if (cellname || !cell) {
131 ret = afs_cell_lookup(cellname, cellnamesz, &cell);
132 if (ret<0) {
133 printk("kAFS: unable to lookup cell '%s'\n",
134 cellname ?: "");
135 goto error;
136 }
ec26815a 137 } else {
1da177e4
LT
138 afs_get_cell(cell);
139 }
140
141 /* lookup the volume location record */
142 ret = afs_vlocation_lookup(cell, volname, volnamesz, &vlocation);
143 if (ret < 0)
144 goto error;
145
146 /* make the final decision on the type we want */
147 ret = -ENOMEDIUM;
148 if (force && !(vlocation->vldb.vidmask & (1 << type)))
149 goto error;
150
151 srvtmask = 0;
152 for (loop = 0; loop < vlocation->vldb.nservers; loop++)
153 srvtmask |= vlocation->vldb.srvtmask[loop];
154
155 if (force) {
156 if (!(srvtmask & (1 << type)))
157 goto error;
ec26815a 158 } else if (srvtmask & AFS_VOL_VTM_RO) {
1da177e4 159 type = AFSVL_ROVOL;
ec26815a 160 } else if (srvtmask & AFS_VOL_VTM_RW) {
1da177e4 161 type = AFSVL_RWVOL;
ec26815a 162 } else {
1da177e4
LT
163 goto error;
164 }
165
166 down_write(&cell->vl_sem);
167
168 /* is the volume already active? */
169 if (vlocation->vols[type]) {
170 /* yes - re-use it */
171 volume = vlocation->vols[type];
172 afs_get_volume(volume);
173 goto success;
174 }
175
176 /* create a new volume record */
177 _debug("creating new volume record");
178
179 ret = -ENOMEM;
f8314dc6 180 volume = kzalloc(sizeof(struct afs_volume), GFP_KERNEL);
1da177e4
LT
181 if (!volume)
182 goto error_up;
183
1da177e4
LT
184 atomic_set(&volume->usage, 1);
185 volume->type = type;
186 volume->type_force = force;
187 volume->cell = cell;
188 volume->vid = vlocation->vldb.vid[type];
189
190 init_rwsem(&volume->server_sem);
191
192 /* look up all the applicable server records */
193 for (loop = 0; loop < 8; loop++) {
194 if (vlocation->vldb.srvtmask[loop] & (1 << volume->type)) {
195 ret = afs_server_lookup(
196 volume->cell,
197 &vlocation->vldb.servers[loop],
198 &volume->servers[volume->nservers]);
199 if (ret < 0)
200 goto error_discard;
201
202 volume->nservers++;
203 }
204 }
205
206 /* attach the cache and volume location */
207#ifdef AFS_CACHING_SUPPORT
208 cachefs_acquire_cookie(vlocation->cache,
209 &afs_vnode_cache_index_def,
210 volume,
211 &volume->cache);
212#endif
213
214 afs_get_vlocation(vlocation);
215 volume->vlocation = vlocation;
216
217 vlocation->vols[type] = volume;
218
ec26815a 219success:
1da177e4
LT
220 _debug("kAFS selected %s volume %08x",
221 afs_voltypes[volume->type], volume->vid);
222 *_volume = volume;
223 ret = 0;
224
225 /* clean up */
ec26815a 226error_up:
1da177e4 227 up_write(&cell->vl_sem);
ec26815a 228error:
1da177e4
LT
229 afs_put_vlocation(vlocation);
230 afs_put_cell(cell);
231
232 _leave(" = %d (%p)", ret, volume);
233 return ret;
234
ec26815a 235error_discard:
1da177e4
LT
236 up_write(&cell->vl_sem);
237
238 for (loop = volume->nservers - 1; loop >= 0; loop--)
239 afs_put_server(volume->servers[loop]);
240
241 kfree(volume);
242 goto error;
ec26815a 243}
1da177e4 244
1da177e4
LT
245/*
246 * destroy a volume record
247 */
248void afs_put_volume(struct afs_volume *volume)
249{
250 struct afs_vlocation *vlocation;
251 int loop;
252
253 if (!volume)
254 return;
255
256 _enter("%p", volume);
257
258 vlocation = volume->vlocation;
259
260 /* sanity check */
261 BUG_ON(atomic_read(&volume->usage) <= 0);
262
263 /* to prevent a race, the decrement and the dequeue must be effectively
264 * atomic */
265 down_write(&vlocation->cell->vl_sem);
266
267 if (likely(!atomic_dec_and_test(&volume->usage))) {
268 up_write(&vlocation->cell->vl_sem);
269 _leave("");
270 return;
271 }
272
273 vlocation->vols[volume->type] = NULL;
274
275 up_write(&vlocation->cell->vl_sem);
276
277 /* finish cleaning up the volume */
278#ifdef AFS_CACHING_SUPPORT
279 cachefs_relinquish_cookie(volume->cache, 0);
280#endif
281 afs_put_vlocation(vlocation);
282
283 for (loop = volume->nservers - 1; loop >= 0; loop--)
284 afs_put_server(volume->servers[loop]);
285
286 kfree(volume);
287
288 _leave(" [destroyed]");
ec26815a 289}
1da177e4 290
1da177e4
LT
291/*
292 * pick a server to use to try accessing this volume
293 * - returns with an elevated usage count on the server chosen
294 */
295int afs_volume_pick_fileserver(struct afs_volume *volume,
296 struct afs_server **_server)
297{
298 struct afs_server *server;
299 int ret, state, loop;
300
301 _enter("%s", volume->vlocation->vldb.name);
302
303 down_read(&volume->server_sem);
304
305 /* handle the no-server case */
306 if (volume->nservers == 0) {
307 ret = volume->rjservers ? -ENOMEDIUM : -ESTALE;
308 up_read(&volume->server_sem);
309 _leave(" = %d [no servers]", ret);
310 return ret;
311 }
312
313 /* basically, just search the list for the first live server and use
314 * that */
315 ret = 0;
316 for (loop = 0; loop < volume->nservers; loop++) {
317 server = volume->servers[loop];
318 state = server->fs_state;
319
320 switch (state) {
321 /* found an apparently healthy server */
322 case 0:
323 afs_get_server(server);
324 up_read(&volume->server_sem);
325 *_server = server;
326 _leave(" = 0 (picked %08x)",
327 ntohl(server->addr.s_addr));
328 return 0;
329
330 case -ENETUNREACH:
331 if (ret == 0)
332 ret = state;
333 break;
334
335 case -EHOSTUNREACH:
336 if (ret == 0 ||
337 ret == -ENETUNREACH)
338 ret = state;
339 break;
340
341 case -ECONNREFUSED:
342 if (ret == 0 ||
343 ret == -ENETUNREACH ||
344 ret == -EHOSTUNREACH)
345 ret = state;
346 break;
347
348 default:
349 case -EREMOTEIO:
350 if (ret == 0 ||
351 ret == -ENETUNREACH ||
352 ret == -EHOSTUNREACH ||
353 ret == -ECONNREFUSED)
354 ret = state;
355 break;
356 }
357 }
358
359 /* no available servers
360 * - TODO: handle the no active servers case better
361 */
362 up_read(&volume->server_sem);
363 _leave(" = %d", ret);
364 return ret;
ec26815a 365}
1da177e4 366
1da177e4
LT
367/*
368 * release a server after use
369 * - releases the ref on the server struct that was acquired by picking
370 * - records result of using a particular server to access a volume
371 * - return 0 to try again, 1 if okay or to issue error
372 */
373int afs_volume_release_fileserver(struct afs_volume *volume,
374 struct afs_server *server,
375 int result)
376{
377 unsigned loop;
378
379 _enter("%s,%08x,%d",
380 volume->vlocation->vldb.name, ntohl(server->addr.s_addr),
381 result);
382
383 switch (result) {
384 /* success */
385 case 0:
386 server->fs_act_jif = jiffies;
387 break;
388
389 /* the fileserver denied all knowledge of the volume */
390 case -ENOMEDIUM:
391 server->fs_act_jif = jiffies;
392 down_write(&volume->server_sem);
393
394 /* first, find where the server is in the active list (if it
395 * is) */
396 for (loop = 0; loop < volume->nservers; loop++)
397 if (volume->servers[loop] == server)
398 goto present;
399
400 /* no longer there - may have been discarded by another op */
401 goto try_next_server_upw;
402
403 present:
404 volume->nservers--;
405 memmove(&volume->servers[loop],
406 &volume->servers[loop + 1],
407 sizeof(volume->servers[loop]) *
408 (volume->nservers - loop));
409 volume->servers[volume->nservers] = NULL;
410 afs_put_server(server);
411 volume->rjservers++;
412
413 if (volume->nservers > 0)
414 /* another server might acknowledge its existence */
415 goto try_next_server_upw;
416
417 /* handle the case where all the fileservers have rejected the
418 * volume
419 * - TODO: try asking the fileservers for volume information
420 * - TODO: contact the VL server again to see if the volume is
421 * no longer registered
422 */
423 up_write(&volume->server_sem);
424 afs_put_server(server);
425 _leave(" [completely rejected]");
426 return 1;
427
428 /* problem reaching the server */
429 case -ENETUNREACH:
430 case -EHOSTUNREACH:
431 case -ECONNREFUSED:
432 case -ETIMEDOUT:
433 case -EREMOTEIO:
434 /* mark the server as dead
435 * TODO: vary dead timeout depending on error
436 */
437 spin_lock(&server->fs_lock);
438 if (!server->fs_state) {
439 server->fs_dead_jif = jiffies + HZ * 10;
440 server->fs_state = result;
441 printk("kAFS: SERVER DEAD state=%d\n", result);
442 }
443 spin_unlock(&server->fs_lock);
444 goto try_next_server;
445
446 /* miscellaneous error */
447 default:
448 server->fs_act_jif = jiffies;
449 case -ENOMEM:
450 case -ENONET:
451 break;
452 }
453
454 /* tell the caller to accept the result */
455 afs_put_server(server);
456 _leave("");
457 return 1;
458
459 /* tell the caller to loop around and try the next server */
ec26815a 460try_next_server_upw:
1da177e4 461 up_write(&volume->server_sem);
ec26815a 462try_next_server:
1da177e4
LT
463 afs_put_server(server);
464 _leave(" [try next server]");
465 return 0;
ec26815a 466}
1da177e4 467
1da177e4
LT
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;
ec26815a 487}
1da177e4
LT
488#endif
489
1da177e4
LT
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;
ec26815a 502}
1da177e4 503#endif