vlocation.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 955 行 · 第 1/2 页

C
955
字号
/* 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*1000static 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 spinlock_t afs_vlocation_update_lock = SPIN_LOCK_UNLOCKED; /* lock guarding update queue */#ifdef AFS_CACHING_SUPPORTstatic 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){	struct afs_server *server = NULL;	struct afs_cell *cell = vlocation->cell;	int count, ret;	_enter("%s,%x,%d,", cell->name, volid, voltype);	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_id(server, volid, voltype, 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_id() *//*****************************************************************************//* * lookup volume location * - caller must have cell->vol_sem write-locked * - iterate through the VL servers in a cell until one of them admits knowing *   about the volume in question * - lookup in the local cache if not able to find on the VL server * - insert/update in the local cache if did get a VL response */int afs_vlocation_lookup(struct afs_cell *cell,			 const char *name,			 unsigned namesz,			 struct afs_vlocation **_vlocation){	struct afs_cache_vlocation vldb;	struct afs_vlocation *vlocation;	afs_voltype_t voltype;	afs_volid_t vid;	int active = 0, ret;	_enter("{%s},%*.*s,%u,", cell->name, namesz, namesz, name, namesz);	if (namesz > sizeof(vlocation->vldb.name)) {		_leave(" = -ENAMETOOLONG");		return -ENAMETOOLONG;	}	/* search the cell's active list first */	list_for_each_entry(vlocation, &cell->vl_list, link) {		if (namesz < sizeof(vlocation->vldb.name) &&		    vlocation->vldb.name[namesz] != '\0')			continue;		if (memcmp(vlocation->vldb.name, name, namesz) == 0)			goto found_in_memory;	}	/* search the cell's graveyard list second */	spin_lock(&cell->vl_gylock);	list_for_each_entry(vlocation, &cell->vl_graveyard, link) {		if (namesz < sizeof(vlocation->vldb.name) &&		    vlocation->vldb.name[namesz] != '\0')			continue;		if (memcmp(vlocation->vldb.name, name, namesz) == 0)			goto found_in_graveyard;	}	spin_unlock(&cell->vl_gylock);	/* not in the cell's in-memory lists - create a new record */	vlocation = kmalloc(sizeof(struct afs_vlocation), GFP_KERNEL);	if (!vlocation)		return -ENOMEM;	memset(vlocation, 0, sizeof(struct afs_vlocation));	atomic_set(&vlocation->usage, 1);	INIT_LIST_HEAD(&vlocation->link);	rwlock_init(&vlocation->lock);	memcpy(vlocation->vldb.name, name, namesz);	afs_timer_init(&vlocation->timeout, &afs_vlocation_timer_ops);	afs_timer_init(&vlocation->upd_timer, &afs_vlocation_update_timer_ops);	afs_async_op_init(&vlocation->upd_op, &afs_vlocation_update_op_ops);	afs_get_cell(cell);	vlocation->cell = cell;	list_add_tail(&vlocation->link, &cell->vl_list);#ifdef AFS_CACHING_SUPPORT	/* we want to store it in the cache, plus it might already be	 * encached */	cachefs_acquire_cookie(cell->cache,			       &afs_volume_cache_index_def,			       vlocation,			       &vlocation->cache);	if (vlocation->valid)		goto found_in_cache;#endif	/* try to look up an unknown volume in the cell VL databases by name */	ret = afs_vlocation_access_vl_by_name(vlocation, name, namesz, &vldb);	if (ret < 0) {		printk("kAFS: failed to locate '%*.*s' in cell '%s'\n",		       namesz, namesz, name, cell->name);		goto error;	}	goto found_on_vlserver; found_in_graveyard:	/* found in the graveyard - resurrect */	_debug("found in graveyard");	atomic_inc(&vlocation->usage);	list_del(&vlocation->link);	list_add_tail(&vlocation->link, &cell->vl_list);	spin_unlock(&cell->vl_gylock);	afs_kafstimod_del_timer(&vlocation->timeout);	goto active; found_in_memory:	/* found in memory - check to see if it's active */	_debug("found in memory");	atomic_inc(&vlocation->usage); active:	active = 1;#ifdef AFS_CACHING_SUPPORT found_in_cache:#endif	/* try to look up a cached volume in the cell VL databases by ID */	_debug("found in cache");	_debug("Locally Cached: %s %02x { %08x(%x) %08x(%x) %08x(%x) }",	       vlocation->vldb.name,	       vlocation->vldb.vidmask,	       ntohl(vlocation->vldb.servers[0].s_addr),	       vlocation->vldb.srvtmask[0],	       ntohl(vlocation->vldb.servers[1].s_addr),	       vlocation->vldb.srvtmask[1],	       ntohl(vlocation->vldb.servers[2].s_addr),	       vlocation->vldb.srvtmask[2]	       );	_debug("Vids: %08x %08x %08x",	       vlocation->vldb.vid[0],	       vlocation->vldb.vid[1],	       vlocation->vldb.vid[2]);	if (vlocation->vldb.vidmask & AFS_VOL_VTM_RW) {		vid = vlocation->vldb.vid[0];		voltype = AFSVL_RWVOL;	}	else if (vlocation->vldb.vidmask & AFS_VOL_VTM_RO) {		vid = vlocation->vldb.vid[1];		voltype = AFSVL_ROVOL;	}	else if (vlocation->vldb.vidmask & AFS_VOL_VTM_BAK) {		vid = vlocation->vldb.vid[2];		voltype = AFSVL_BACKVOL;	}	else {		BUG();		vid = 0;		voltype = 0;	}	ret = afs_vlocation_access_vl_by_id(vlocation, vid, voltype, &vldb);	switch (ret) {		/* net error */	default:		printk("kAFS: failed to volume '%*.*s' (%x) up in '%s': %d\n",		       namesz, namesz, name, vid, cell->name, ret);		goto error;		/* pulled from local cache into memory */	case 0:		goto found_on_vlserver;		/* uh oh... looks like the volume got deleted */	case -ENOMEDIUM:		printk("kAFS: volume '%*.*s' (%x) does not exist '%s'\n",		       namesz, namesz, name, vid, cell->name);		/* TODO: make existing record unavailable */		goto error;	} found_on_vlserver:	_debug("Done VL Lookup: %*.*s %02x { %08x(%x) %08x(%x) %08x(%x) }",	       namesz, namesz, name,	       vldb.vidmask,	       ntohl(vldb.servers[0].s_addr), vldb.srvtmask[0],	       ntohl(vldb.servers[1].s_addr), vldb.srvtmask[1],	       ntohl(vldb.servers[2].s_addr), vldb.srvtmask[2]	       );	_debug("Vids: %08x %08x %08x", vldb.vid[0], vldb.vid[1], vldb.vid[2]);	if ((namesz < sizeof(vlocation->vldb.name) &&	     vlocation->vldb.name[namesz] != '\0') ||	    memcmp(vldb.name, name, namesz) != 0)		printk("kAFS: name of volume '%*.*s' changed to '%s' on server\n",		       namesz, namesz, name, vldb.name);	memcpy(&vlocation->vldb, &vldb, sizeof(vlocation->vldb));	afs_kafstimod_add_timer(&vlocation->upd_timer, 10 * HZ);#ifdef AFS_CACHING_SUPPORT	/* update volume entry in local cache */	cachefs_update_cookie(vlocation->cache);#endif	*_vlocation = vlocation;	_leave(" = 0 (%p)",vlocation);	return 0; error:	if (vlocation) {		if (active) {			__afs_put_vlocation(vlocation);		}		else {			list_del(&vlocation->link);#ifdef AFS_CACHING_SUPPORT			cachefs_relinquish_cookie(vlocation->cache, 0);#endif			afs_put_cell(vlocation->cell);			kfree(vlocation);		}	}	_leave(" = %d", ret);	return ret;} /* end afs_vlocation_lookup() *//*****************************************************************************//* * finish using a volume location record * - caller must have cell->vol_sem write-locked */static void __afs_put_vlocation(struct afs_vlocation *vlocation){	struct afs_cell *cell;	if (!vlocation)		return;	_enter("%s", vlocation->vldb.name);	cell = vlocation->cell;	/* sanity check */	BUG_ON(atomic_read(&vlocation->usage) <= 0);	spin_lock(&cell->vl_gylock);	if (likely(!atomic_dec_and_test(&vlocation->usage))) {		spin_unlock(&cell->vl_gylock);		_leave("");		return;	}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?