⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vlocation.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* AFS volume location management * * 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 * 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/sched.h>#include "internal.h"static unsigned afs_vlocation_timeout = 10;	/* volume location timeout in seconds */static unsigned afs_vlocation_update_timeout = 10 * 60;static void afs_vlocation_reaper(struct work_struct *);static void afs_vlocation_updater(struct work_struct *);static LIST_HEAD(afs_vlocation_updates);static LIST_HEAD(afs_vlocation_graveyard);static DEFINE_SPINLOCK(afs_vlocation_updates_lock);static DEFINE_SPINLOCK(afs_vlocation_graveyard_lock);static DECLARE_DELAYED_WORK(afs_vlocation_reap, afs_vlocation_reaper);static DECLARE_DELAYED_WORK(afs_vlocation_update, afs_vlocation_updater);static struct workqueue_struct *afs_vlocation_update_worker;/* * iterate through the VL servers in a cell until one of them admits knowing * about the volume in question */static int afs_vlocation_access_vl_by_name(struct afs_vlocation *vl,					   struct key *key,					   struct afs_cache_vlocation *vldb){	struct afs_cell *cell = vl->cell;	struct in_addr addr;	int count, ret;	_enter("%s,%s", cell->name, vl->vldb.name);	down_write(&vl->cell->vl_sem);	ret = -ENOMEDIUM;	for (count = cell->vl_naddrs; count > 0; count--) {		addr = cell->vl_addrs[cell->vl_curr_svix];		_debug("CellServ[%hu]: %08x", cell->vl_curr_svix, addr.s_addr);		/* attempt to access the VL server */		ret = afs_vl_get_entry_by_name(&addr, key, vl->vldb.name, vldb,					       &afs_sync_call);		switch (ret) {		case 0:			goto out;		case -ENOMEM:		case -ENONET:		case -ENETUNREACH:		case -EHOSTUNREACH:		case -ECONNREFUSED:			if (ret == -ENOMEM || ret == -ENONET)				goto out;			goto rotate;		case -ENOMEDIUM:			goto out;		default:			ret = -EIO;			goto rotate;		}		/* rotate the server records upon lookup failure */	rotate:		cell->vl_curr_svix++;		cell->vl_curr_svix %= cell->vl_naddrs;	}out:	up_write(&vl->cell->vl_sem);	_leave(" = %d", ret);	return ret;}/* * iterate through the VL servers in a cell until one of them admits knowing * about the volume in question */static int afs_vlocation_access_vl_by_id(struct afs_vlocation *vl,					 struct key *key,					 afs_volid_t volid,					 afs_voltype_t voltype,					 struct afs_cache_vlocation *vldb){	struct afs_cell *cell = vl->cell;	struct in_addr addr;	int count, ret;	_enter("%s,%x,%d,", cell->name, volid, voltype);	down_write(&vl->cell->vl_sem);	ret = -ENOMEDIUM;	for (count = cell->vl_naddrs; count > 0; count--) {		addr = cell->vl_addrs[cell->vl_curr_svix];		_debug("CellServ[%hu]: %08x", cell->vl_curr_svix, addr.s_addr);		/* attempt to access the VL server */		ret = afs_vl_get_entry_by_id(&addr, key, volid, voltype, vldb,					     &afs_sync_call);		switch (ret) {		case 0:			goto out;		case -ENOMEM:		case -ENONET:		case -ENETUNREACH:		case -EHOSTUNREACH:		case -ECONNREFUSED:			if (ret == -ENOMEM || ret == -ENONET)				goto out;			goto rotate;		case -EBUSY:			vl->upd_busy_cnt++;			if (vl->upd_busy_cnt <= 3) {				if (vl->upd_busy_cnt > 1) {					/* second+ BUSY - sleep a little bit */					set_current_state(TASK_UNINTERRUPTIBLE);					schedule_timeout(1);					__set_current_state(TASK_RUNNING);				}				continue;			}			break;		case -ENOMEDIUM:			vl->upd_rej_cnt++;			goto rotate;		default:			ret = -EIO;			goto rotate;		}		/* rotate the server records upon lookup failure */	rotate:		cell->vl_curr_svix++;		cell->vl_curr_svix %= cell->vl_naddrs;		vl->upd_busy_cnt = 0;	}out:	if (ret < 0 && vl->upd_rej_cnt > 0) {		printk(KERN_NOTICE "kAFS:"		       " Active volume no longer valid '%s'\n",		       vl->vldb.name);		vl->valid = 0;		ret = -ENOMEDIUM;	}	up_write(&vl->cell->vl_sem);	_leave(" = %d", ret);	return ret;}/* * allocate a volume location record */static struct afs_vlocation *afs_vlocation_alloc(struct afs_cell *cell,						 const char *name,						 size_t namesz){	struct afs_vlocation *vl;	vl = kzalloc(sizeof(struct afs_vlocation), GFP_KERNEL);	if (vl) {		vl->cell = cell;		vl->state = AFS_VL_NEW;		atomic_set(&vl->usage, 1);		INIT_LIST_HEAD(&vl->link);		INIT_LIST_HEAD(&vl->grave);		INIT_LIST_HEAD(&vl->update);		init_waitqueue_head(&vl->waitq);		spin_lock_init(&vl->lock);		memcpy(vl->vldb.name, name, namesz);	}	_leave(" = %p", vl);	return vl;}/* * update record if we found it in the cache */static int afs_vlocation_update_record(struct afs_vlocation *vl,				       struct key *key,				       struct afs_cache_vlocation *vldb){	afs_voltype_t voltype;	afs_volid_t vid;	int ret;	/* try to look up a cached volume in the cell VL databases by ID */	_debug("Locally Cached: %s %02x { %08x(%x) %08x(%x) %08x(%x) }",	       vl->vldb.name,	       vl->vldb.vidmask,	       ntohl(vl->vldb.servers[0].s_addr),	       vl->vldb.srvtmask[0],	       ntohl(vl->vldb.servers[1].s_addr),	       vl->vldb.srvtmask[1],	       ntohl(vl->vldb.servers[2].s_addr),	       vl->vldb.srvtmask[2]);	_debug("Vids: %08x %08x %08x",	       vl->vldb.vid[0],	       vl->vldb.vid[1],	       vl->vldb.vid[2]);	if (vl->vldb.vidmask & AFS_VOL_VTM_RW) {		vid = vl->vldb.vid[0];		voltype = AFSVL_RWVOL;	} else if (vl->vldb.vidmask & AFS_VOL_VTM_RO) {		vid = vl->vldb.vid[1];		voltype = AFSVL_ROVOL;	} else if (vl->vldb.vidmask & AFS_VOL_VTM_BAK) {		vid = vl->vldb.vid[2];		voltype = AFSVL_BACKVOL;	} else {		BUG();		vid = 0;		voltype = 0;	}	/* contact the server to make sure the volume is still available	 * - TODO: need to handle disconnected operation here	 */	ret = afs_vlocation_access_vl_by_id(vl, key, vid, voltype, vldb);	switch (ret) {		/* net error */	default:		printk(KERN_WARNING "kAFS:"		       " failed to update volume '%s' (%x) up in '%s': %d\n",		       vl->vldb.name, vid, vl->cell->name, ret);		_leave(" = %d", ret);		return ret;		/* pulled from local cache into memory */	case 0:		_leave(" = 0");		return 0;		/* uh oh... looks like the volume got deleted */	case -ENOMEDIUM:		printk(KERN_ERR "kAFS:"		       " volume '%s' (%x) does not exist '%s'\n",		       vl->vldb.name, vid, vl->cell->name);		/* TODO: make existing record unavailable */		_leave(" = %d", ret);		return ret;	}}/* * apply the update to a VL record */static void afs_vlocation_apply_update(struct afs_vlocation *vl,				       struct afs_cache_vlocation *vldb){	_debug("Done VL Lookup: %s %02x { %08x(%x) %08x(%x) %08x(%x) }",	       vldb->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 (strcmp(vldb->name, vl->vldb.name) != 0)		printk(KERN_NOTICE "kAFS:"		       " name of volume '%s' changed to '%s' on server\n",		       vl->vldb.name, vldb->name);	vl->vldb = *vldb;#ifdef AFS_CACHING_SUPPORT	/* update volume entry in local cache */	cachefs_update_cookie(vl->cache);#endif}/* * fill in a volume location record, consulting the cache and the VL server * both */static int afs_vlocation_fill_in_record(struct afs_vlocation *vl,					struct key *key){	struct afs_cache_vlocation vldb;	int ret;	_enter("");	ASSERTCMP(vl->valid, ==, 0);	memset(&vldb, 0, sizeof(vldb));	/* see if we have an in-cache copy (will set vl->valid if there is) */#ifdef AFS_CACHING_SUPPORT	cachefs_acquire_cookie(cell->cache,			       &afs_volume_cache_index_def,			       vlocation,			       &vl->cache);#endif	if (vl->valid) {		/* try to update a known volume in the cell VL databases by		 * ID as the name may have changed */		_debug("found in cache");		ret = afs_vlocation_update_record(vl, key, &vldb);	} else {		/* try to look up an unknown volume in the cell VL databases by		 * name */		ret = afs_vlocation_access_vl_by_name(vl, key, &vldb);		if (ret < 0) {			printk("kAFS: failed to locate '%s' in cell '%s'\n",			       vl->vldb.name, vl->cell->name);			return ret;		}	}	afs_vlocation_apply_update(vl, &vldb);	_leave(" = 0");	return 0;}/* * queue a vlocation record for updates */static void afs_vlocation_queue_for_updates(struct afs_vlocation *vl){	struct afs_vlocation *xvl;	/* wait at least 10 minutes before updating... */	vl->update_at = get_seconds() + afs_vlocation_update_timeout;	spin_lock(&afs_vlocation_updates_lock);	if (!list_empty(&afs_vlocation_updates)) {		/* ... but wait at least 1 second more than the newest record		 * already queued so that we don't spam the VL server suddenly		 * with lots of requests		 */		xvl = list_entry(afs_vlocation_updates.prev,				 struct afs_vlocation, update);		if (vl->update_at <= xvl->update_at)			vl->update_at = xvl->update_at + 1;	} else {		queue_delayed_work(afs_vlocation_update_worker,				   &afs_vlocation_update,				   afs_vlocation_update_timeout * HZ);	}	list_add_tail(&vl->update, &afs_vlocation_updates);

⌨️ 快捷键说明

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