/* vlocation.c: volume location management
*
* Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/pagemap.h>
#include "volume.h"
#include "cell.h"
#include "cmservice.h"
#include "fsclient.h"
#include "vlclient.h"
#include "kafstimod.h"
#include <rxrpc/connection.h>
#include "internal.h"
#define AFS_VLDB_TIMEOUT HZ*1000
static void afs_vlocation_update_timer(struct afs_timer *timer);
static void afs_vlocation_update_attend(struct afs_async_op *op);
static void afs_vlocation_update_discard(struct afs_async_op *op);
static void __afs_put_vlocation(struct afs_vlocation *vlocation);
static void __afs_vlocation_timeout(struct afs_timer *timer)
{
struct afs_vlocation *vlocation =
list_entry(timer, struct afs_vlocation, timeout);
_debug("VL TIMEOUT [%s{u=%d}]",
vlocation->vldb.name, atomic_read(&vlocation->usage));
afs_vlocation_do_timeout(vlocation);
}
static const struct afs_timer_ops afs_vlocation_timer_ops = {
.timed_out = __afs_vlocation_timeout,
};
static const struct afs_timer_ops afs_vlocation_update_timer_ops = {
.timed_out = afs_vlocation_update_timer,
};
static const struct afs_async_op_ops afs_vlocation_update_op_ops = {
.attend = afs_vlocation_update_attend,
.discard = afs_vlocation_update_discard,
};
static LIST_HEAD(afs_vlocation_update_pendq); /* queue of VLs awaiting update */
static struct afs_vlocation *afs_vlocation_update; /* VL currently being updated */
static DEFINE_SPINLOCK(afs_vlocation_update_lock); /* lock guarding update queue */
#ifdef AFS_CACHING_SUPPORT
static cachefs_match_val_t afs_vlocation_cache_match(void *target,
const void *entry);
static void afs_vlocation_cache_update(void *source, void *entry);
struct cachefs_index_def afs_vlocation_cache_index_def = {
.name = "vldb",
.data_size = sizeof(struct afs_cache_vlocation),
.keys[0] = { CACHEFS_INDEX_KEYS_ASCIIZ, 64 },
.match = afs_vlocation_cache_match,
.update = afs_vlocation_cache_update,
};
#endif
/*****************************************************************************/
/*
* iterate through the VL servers in a cell until one of them admits knowing
* about the volume in question
* - caller must have cell->vl_sem write-locked
*/
static int afs_vlocation_access_vl_by_name(struct afs_vlocation *vlocation,
const char *name,
unsigned namesz,
struct afs_cache_vlocation *vldb)
{
struct afs_server *server = NULL;
struct afs_cell *cell = vlocation->cell;
int count, ret;
_enter("%s,%*.*s,%u", cell->name, namesz, namesz, name, namesz);
ret = -ENOMEDIUM;
for (count = cell->vl_naddrs; count > 0; count--) {
_debug("CellServ[%hu]: %08x",
cell->vl_curr_svix,
cell->vl_addrs[cell->vl_curr_svix].s_addr);
/* try and create a server */
ret = afs_server_lookup(cell,
&cell->vl_addrs[cell->vl_curr_svix],
&server);
switch (ret) {
case 0:
break;
case -ENOMEM:
case -ENONET:
goto out;
default:
goto rotate;
}
/* attempt to access the VL server */
ret = afs_rxvl_get_entry_by_name(server, name, namesz, vldb);
switch (ret) {
case 0:
afs_put_server(server);
goto out;
case -ENOMEM:
case -ENONET:
case -ENETUNREACH:
case -EHOSTUNREACH:
case -ECONNREFUSED:
down_write(&server->sem);
if (server->vlserver) {
rxrpc_put_connection(server->vlserver);
server->vlserver = NULL;
}
up_write(&server->sem);
afs_put_server(server);
if (ret == -ENOMEM || ret == -ENONET)
goto out;
goto rotate;
case -ENOMEDIUM:
afs_put_server(server);
goto out;
default:
afs_put_server(server);
ret = -ENOMEDIUM;
goto rotate;
}
/* rotate the server records upon lookup failure */
rotate:
cell->vl_curr_svix++;
cell->vl_curr_svix %= cell->vl_naddrs;
}
out:
_leave(" = %d", ret);
return ret;
} /* end afs_vlocation_access_vl_by_name() */
/*****************************************************************************/
/*
* iterate through the VL servers in a cell until one of them admits knowing
* about the volume in question
* - caller must have cell->vl_sem write-locked
*/
static int afs_vlocation_access_vl_by_id(struct afs_vlocation *vlocation,
afs_volid_t volid,
afs_voltype_t voltype,
struct afs_cache_vlocation *vldb)
{