diff options
Diffstat (limited to 'fs/afs/volume.c')
-rw-r--r-- | fs/afs/volume.c | 290 |
1 files changed, 83 insertions, 207 deletions
diff --git a/fs/afs/volume.c b/fs/afs/volume.c index 768c6dbd323..dd160cada45 100644 --- a/fs/afs/volume.c +++ b/fs/afs/volume.c @@ -1,6 +1,6 @@ -/* volume.c: AFS volume management +/* AFS volume management * - * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. + * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) * * This program is free software; you can redistribute it and/or @@ -15,35 +15,10 @@ #include <linux/slab.h> #include <linux/fs.h> #include <linux/pagemap.h> -#include "volume.h" -#include "vnode.h" -#include "cell.h" -#include "cache.h" -#include "cmservice.h" -#include "fsclient.h" -#include "vlclient.h" #include "internal.h" -#ifdef __KDEBUG static const char *afs_voltypes[] = { "R/W", "R/O", "BAK" }; -#endif - -#ifdef AFS_CACHING_SUPPORT -static cachefs_match_val_t afs_volume_cache_match(void *target, - const void *entry); -static void afs_volume_cache_update(void *source, void *entry); - -struct cachefs_index_def afs_volume_cache_index_def = { - .name = "volume", - .data_size = sizeof(struct afs_cache_vhash), - .keys[0] = { CACHEFS_INDEX_KEYS_BIN, 1 }, - .keys[1] = { CACHEFS_INDEX_KEYS_BIN, 1 }, - .match = afs_volume_cache_match, - .update = afs_volume_cache_update, -}; -#endif -/*****************************************************************************/ /* * lookup a volume by name * - this can be one of the following: @@ -66,118 +41,52 @@ struct cachefs_index_def afs_volume_cache_index_def = { * - Rule 3: If parent volume is R/W, then only mount R/W volume unless * explicitly told otherwise */ -int afs_volume_lookup(const char *name, struct afs_cell *cell, int rwpath, - struct afs_volume **_volume) +struct afs_volume *afs_volume_lookup(struct afs_mount_params *params) { struct afs_vlocation *vlocation = NULL; struct afs_volume *volume = NULL; - afs_voltype_t type; - const char *cellname, *volname, *suffix; + struct afs_server *server = NULL; char srvtmask; - int force, ret, loop, cellnamesz, volnamesz; - - _enter("%s,,%d,", name, rwpath); - - if (!name || (name[0] != '%' && name[0] != '#') || !name[1]) { - printk("kAFS: unparsable volume name\n"); - return -EINVAL; - } - - /* determine the type of volume we're looking for */ - force = 0; - type = AFSVL_ROVOL; - - if (rwpath || name[0] == '%') { - type = AFSVL_RWVOL; - force = 1; - } - - suffix = strrchr(name, '.'); - if (suffix) { - if (strcmp(suffix, ".readonly") == 0) { - type = AFSVL_ROVOL; - force = 1; - } - else if (strcmp(suffix, ".backup") == 0) { - type = AFSVL_BACKVOL; - force = 1; - } - else if (suffix[1] == 0) { - } - else { - suffix = NULL; - } - } + int ret, loop; - /* split the cell and volume names */ - name++; - volname = strchr(name, ':'); - if (volname) { - cellname = name; - cellnamesz = volname - name; - volname++; - } - else { - volname = name; - cellname = NULL; - cellnamesz = 0; - } - - volnamesz = suffix ? suffix - volname : strlen(volname); - - _debug("CELL:%*.*s [%p] VOLUME:%*.*s SUFFIX:%s TYPE:%d%s", - cellnamesz, cellnamesz, cellname ?: "", cell, - volnamesz, volnamesz, volname, suffix ?: "-", - type, - force ? " FORCE" : ""); - - /* lookup the cell record */ - if (cellname || !cell) { - ret = afs_cell_lookup(cellname, cellnamesz, &cell); - if (ret<0) { - printk("kAFS: unable to lookup cell '%s'\n", - cellname ?: ""); - goto error; - } - } - else { - afs_get_cell(cell); - } + _enter("{%*.*s,%d}", + params->volnamesz, params->volnamesz, params->volname, params->rwpath); /* lookup the volume location record */ - ret = afs_vlocation_lookup(cell, volname, volnamesz, &vlocation); - if (ret < 0) + vlocation = afs_vlocation_lookup(params->cell, params->key, + params->volname, params->volnamesz); + if (IS_ERR(vlocation)) { + ret = PTR_ERR(vlocation); + vlocation = NULL; goto error; + } /* make the final decision on the type we want */ ret = -ENOMEDIUM; - if (force && !(vlocation->vldb.vidmask & (1 << type))) + if (params->force && !(vlocation->vldb.vidmask & (1 << params->type))) goto error; srvtmask = 0; for (loop = 0; loop < vlocation->vldb.nservers; loop++) srvtmask |= vlocation->vldb.srvtmask[loop]; - if (force) { - if (!(srvtmask & (1 << type))) + if (params->force) { + if (!(srvtmask & (1 << params->type))) goto error; - } - else if (srvtmask & AFS_VOL_VTM_RO) { - type = AFSVL_ROVOL; - } - else if (srvtmask & AFS_VOL_VTM_RW) { - type = AFSVL_RWVOL; - } - else { + } else if (srvtmask & AFS_VOL_VTM_RO) { + params->type = AFSVL_ROVOL; + } else if (srvtmask & AFS_VOL_VTM_RW) { + params->type = AFSVL_RWVOL; + } else { goto error; } - down_write(&cell->vl_sem); + down_write(¶ms->cell->vl_sem); /* is the volume already active? */ - if (vlocation->vols[type]) { + if (vlocation->vols[params->type]) { /* yes - re-use it */ - volume = vlocation->vols[type]; + volume = vlocation->vols[params->type]; afs_get_volume(volume); goto success; } @@ -191,23 +100,24 @@ int afs_volume_lookup(const char *name, struct afs_cell *cell, int rwpath, goto error_up; atomic_set(&volume->usage, 1); - volume->type = type; - volume->type_force = force; - volume->cell = cell; - volume->vid = vlocation->vldb.vid[type]; + volume->type = params->type; + volume->type_force = params->force; + volume->cell = params->cell; + volume->vid = vlocation->vldb.vid[params->type]; init_rwsem(&volume->server_sem); /* look up all the applicable server records */ for (loop = 0; loop < 8; loop++) { if (vlocation->vldb.srvtmask[loop] & (1 << volume->type)) { - ret = afs_server_lookup( - volume->cell, - &vlocation->vldb.servers[loop], - &volume->servers[volume->nservers]); - if (ret < 0) + server = afs_lookup_server( + volume->cell, &vlocation->vldb.servers[loop]); + if (IS_ERR(server)) { + ret = PTR_ERR(server); goto error_discard; + } + volume->servers[volume->nservers] = server; volume->nservers++; } } @@ -223,35 +133,34 @@ int afs_volume_lookup(const char *name, struct afs_cell *cell, int rwpath, afs_get_vlocation(vlocation); volume->vlocation = vlocation; - vlocation->vols[type] = volume; + vlocation->vols[volume->type] = volume; - success: +success: _debug("kAFS selected %s volume %08x", afs_voltypes[volume->type], volume->vid); - *_volume = volume; - ret = 0; + up_write(¶ms->cell->vl_sem); + afs_put_vlocation(vlocation); + _leave(" = %p", volume); + return volume; /* clean up */ - error_up: - up_write(&cell->vl_sem); - error: +error_up: + up_write(¶ms->cell->vl_sem); +error: afs_put_vlocation(vlocation); - afs_put_cell(cell); - - _leave(" = %d (%p)", ret, volume); - return ret; + _leave(" = %d", ret); + return ERR_PTR(ret); - error_discard: - up_write(&cell->vl_sem); +error_discard: + up_write(¶ms->cell->vl_sem); for (loop = volume->nservers - 1; loop >= 0; loop--) afs_put_server(volume->servers[loop]); kfree(volume); goto error; -} /* end afs_volume_lookup() */ +} -/*****************************************************************************/ /* * destroy a volume record */ @@ -265,10 +174,9 @@ void afs_put_volume(struct afs_volume *volume) _enter("%p", volume); - vlocation = volume->vlocation; + ASSERTCMP(atomic_read(&volume->usage), >, 0); - /* sanity check */ - BUG_ON(atomic_read(&volume->usage) <= 0); + vlocation = volume->vlocation; /* to prevent a race, the decrement and the dequeue must be effectively * atomic */ @@ -296,21 +204,27 @@ void afs_put_volume(struct afs_volume *volume) kfree(volume); _leave(" [destroyed]"); -} /* end afs_put_volume() */ +} -/*****************************************************************************/ /* * pick a server to use to try accessing this volume * - returns with an elevated usage count on the server chosen */ -int afs_volume_pick_fileserver(struct afs_volume *volume, - struct afs_server **_server) +struct afs_server *afs_volume_pick_fileserver(struct afs_vnode *vnode) { + struct afs_volume *volume = vnode->volume; struct afs_server *server; int ret, state, loop; _enter("%s", volume->vlocation->vldb.name); + /* stick with the server we're already using if we can */ + if (vnode->server && vnode->server->fs_state == 0) { + afs_get_server(vnode->server); + _leave(" = %p [current]", vnode->server); + return vnode->server; + } + down_read(&volume->server_sem); /* handle the no-server case */ @@ -318,7 +232,7 @@ int afs_volume_pick_fileserver(struct afs_volume *volume, ret = volume->rjservers ? -ENOMEDIUM : -ESTALE; up_read(&volume->server_sem); _leave(" = %d [no servers]", ret); - return ret; + return ERR_PTR(ret); } /* 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, server = volume->servers[loop]; state = server->fs_state; + _debug("consider %d [%d]", loop, state); + switch (state) { /* found an apparently healthy server */ case 0: afs_get_server(server); up_read(&volume->server_sem); - *_server = server; - _leave(" = 0 (picked %08x)", - ntohl(server->addr.s_addr)); - return 0; + _leave(" = %p (picked %08x)", + server, ntohl(server->addr.s_addr)); + return server; case -ENETUNREACH: if (ret == 0) @@ -372,20 +287,21 @@ int afs_volume_pick_fileserver(struct afs_volume *volume, */ up_read(&volume->server_sem); _leave(" = %d", ret); - return ret; -} /* end afs_volume_pick_fileserver() */ + return ERR_PTR(ret); +} -/*****************************************************************************/ /* * release a server after use * - releases the ref on the server struct that was acquired by picking * - records result of using a particular server to access a volume * - return 0 to try again, 1 if okay or to issue error + * - the caller must release the server struct if result was 0 */ -int afs_volume_release_fileserver(struct afs_volume *volume, +int afs_volume_release_fileserver(struct afs_vnode *vnode, struct afs_server *server, int result) { + struct afs_volume *volume = vnode->volume; unsigned loop; _enter("%s,%08x,%d", @@ -396,14 +312,16 @@ int afs_volume_release_fileserver(struct afs_volume *volume, /* success */ case 0: server->fs_act_jif = jiffies; - break; + server->fs_state = 0; + _leave(""); + return 1; /* the fileserver denied all knowledge of the volume */ case -ENOMEDIUM: server->fs_act_jif = jiffies; down_write(&volume->server_sem); - /* first, find where the server is in the active list (if it + /* firstly, find where the server is in the active list (if it * is) */ for (loop = 0; loop < volume->nservers; loop++) if (volume->servers[loop] == server) @@ -441,6 +359,7 @@ int afs_volume_release_fileserver(struct afs_volume *volume, case -ENETUNREACH: case -EHOSTUNREACH: case -ECONNREFUSED: + case -ETIME: case -ETIMEDOUT: case -EREMOTEIO: /* mark the server as dead @@ -460,60 +379,17 @@ int afs_volume_release_fileserver(struct afs_volume *volume, server->fs_act_jif = jiffies; case -ENOMEM: case -ENONET: - break; + /* tell the caller to accept the result */ + afs_put_server(server); + _leave(" [local failure]"); + return 1; } - /* tell the caller to accept the result */ - afs_put_server(server); - _leave(""); - return 1; - /* tell the caller to loop around and try the next server */ - try_next_server_upw: +try_next_server_upw: up_write(&volume->server_sem); - try_next_server: +try_next_server: afs_put_server(server); _leave(" [try next server]"); return 0; - -} /* end afs_volume_release_fileserver() */ - -/*****************************************************************************/ -/* - * match a volume hash record stored in the cache - */ -#ifdef AFS_CACHING_SUPPORT -static cachefs_match_val_t afs_volume_cache_match(void *target, - const void *entry) -{ - const struct afs_cache_vhash *vhash = entry; - struct afs_volume *volume = target; - - _enter("{%u},{%u}", volume->type, vhash->vtype); - - if (volume->type == vhash->vtype) { - _leave(" = SUCCESS"); - return CACHEFS_MATCH_SUCCESS; - } - - _leave(" = FAILED"); - return CACHEFS_MATCH_FAILED; -} /* end afs_volume_cache_match() */ -#endif - -/*****************************************************************************/ -/* - * update a volume hash record stored in the cache - */ -#ifdef AFS_CACHING_SUPPORT -static void afs_volume_cache_update(void *source, void *entry) -{ - struct afs_cache_vhash *vhash = entry; - struct afs_volume *volume = source; - - _enter(""); - - vhash->vtype = volume->type; - -} /* end afs_volume_cache_update() */ -#endif +} |