vlocation.c

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

C
955
字号
	/* move to graveyard queue */	list_del(&vlocation->link);	list_add_tail(&vlocation->link,&cell->vl_graveyard);	/* remove from pending timeout queue (refcounted if actually being	 * updated) */	list_del_init(&vlocation->upd_op.link);	/* time out in 10 secs */	afs_kafstimod_del_timer(&vlocation->upd_timer);	afs_kafstimod_add_timer(&vlocation->timeout, 10 * HZ);	spin_unlock(&cell->vl_gylock);	_leave(" [killed]");} /* end __afs_put_vlocation() *//*****************************************************************************//* * finish using a volume location record */void afs_put_vlocation(struct afs_vlocation *vlocation){	if (vlocation) {		struct afs_cell *cell = vlocation->cell;		down_write(&cell->vl_sem);		__afs_put_vlocation(vlocation);		up_write(&cell->vl_sem);	}} /* end afs_put_vlocation() *//*****************************************************************************//* * timeout vlocation record * - removes from the cell's graveyard if the usage count is zero */void afs_vlocation_do_timeout(struct afs_vlocation *vlocation){	struct afs_cell *cell;	_enter("%s", vlocation->vldb.name);	cell = vlocation->cell;	BUG_ON(atomic_read(&vlocation->usage) < 0);	/* remove from graveyard if still dead */	spin_lock(&cell->vl_gylock);	if (atomic_read(&vlocation->usage) == 0)		list_del_init(&vlocation->link);	else		vlocation = NULL;	spin_unlock(&cell->vl_gylock);	if (!vlocation) {		_leave("");		return; /* resurrected */	}	/* we can now destroy it properly */#ifdef AFS_CACHING_SUPPORT	cachefs_relinquish_cookie(vlocation->cache, 0);#endif	afs_put_cell(cell);	kfree(vlocation);	_leave(" [destroyed]");} /* end afs_vlocation_do_timeout() *//*****************************************************************************//* * send an update operation to the currently selected server */static int afs_vlocation_update_begin(struct afs_vlocation *vlocation){	afs_voltype_t voltype;	afs_volid_t vid;	int ret;	_enter("%s{ufs=%u ucs=%u}",	       vlocation->vldb.name,	       vlocation->upd_first_svix,	       vlocation->upd_curr_svix);	/* try to look up a cached volume in the cell VL databases by ID */	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;	}	/* contact the chosen server */	ret = afs_server_lookup(		vlocation->cell,		&vlocation->cell->vl_addrs[vlocation->upd_curr_svix],		&vlocation->upd_op.server);	switch (ret) {	case 0:		break;	case -ENOMEM:	case -ENONET:	default:		_leave(" = %d", ret);		return ret;	}	/* initiate the update operation */	ret = afs_rxvl_get_entry_by_id_async(&vlocation->upd_op, vid, voltype);	if (ret < 0) {		_leave(" = %d", ret);		return ret;	}	_leave(" = %d", ret);	return ret;} /* end afs_vlocation_update_begin() *//*****************************************************************************//* * abandon updating a VL record * - does not restart the update timer */static void afs_vlocation_update_abandon(struct afs_vlocation *vlocation,					 afs_vlocation_upd_t state,					 int ret){	_enter("%s,%u", vlocation->vldb.name, state);	if (ret < 0)		printk("kAFS: Abandoning VL update '%s': %d\n",		       vlocation->vldb.name, ret);	/* discard the server record */	afs_put_server(vlocation->upd_op.server);	vlocation->upd_op.server = NULL;	spin_lock(&afs_vlocation_update_lock);	afs_vlocation_update = NULL;	vlocation->upd_state = state;	/* TODO: start updating next VL record on pending list */	spin_unlock(&afs_vlocation_update_lock);	_leave("");} /* end afs_vlocation_update_abandon() *//*****************************************************************************//* * handle periodic update timeouts and busy retry timeouts * - called from kafstimod */static void afs_vlocation_update_timer(struct afs_timer *timer){	struct afs_vlocation *vlocation =		list_entry(timer, struct afs_vlocation, upd_timer);	int ret;	_enter("%s", vlocation->vldb.name);	/* only update if not in the graveyard (defend against putting too) */	spin_lock(&vlocation->cell->vl_gylock);	if (!atomic_read(&vlocation->usage))		goto out_unlock1;	spin_lock(&afs_vlocation_update_lock);	/* if we were woken up due to EBUSY sleep then restart immediately if	 * possible or else jump to front of pending queue */	if (vlocation->upd_state == AFS_VLUPD_BUSYSLEEP) {		if (afs_vlocation_update) {			list_add(&vlocation->upd_op.link,				 &afs_vlocation_update_pendq);		}		else {			afs_get_vlocation(vlocation);			afs_vlocation_update = vlocation;			vlocation->upd_state = AFS_VLUPD_INPROGRESS;		}		goto out_unlock2;	}	/* put on pending queue if there's already another update in progress */	if (afs_vlocation_update) {		vlocation->upd_state = AFS_VLUPD_PENDING;		list_add_tail(&vlocation->upd_op.link,			      &afs_vlocation_update_pendq);		goto out_unlock2;	}	/* hold a ref on it while actually updating */	afs_get_vlocation(vlocation);	afs_vlocation_update = vlocation;	vlocation->upd_state = AFS_VLUPD_INPROGRESS;	spin_unlock(&afs_vlocation_update_lock);	spin_unlock(&vlocation->cell->vl_gylock);	/* okay... we can start the update */	_debug("BEGIN VL UPDATE [%s]", vlocation->vldb.name);	vlocation->upd_first_svix = vlocation->cell->vl_curr_svix;	vlocation->upd_curr_svix = vlocation->upd_first_svix;	vlocation->upd_rej_cnt = 0;	vlocation->upd_busy_cnt = 0;	ret = afs_vlocation_update_begin(vlocation);	if (ret < 0) {		afs_vlocation_update_abandon(vlocation, AFS_VLUPD_SLEEP, ret);		afs_kafstimod_add_timer(&vlocation->upd_timer,					AFS_VLDB_TIMEOUT);		afs_put_vlocation(vlocation);	}	_leave("");	return; out_unlock2:	spin_unlock(&afs_vlocation_update_lock); out_unlock1:	spin_unlock(&vlocation->cell->vl_gylock);	_leave("");	return;} /* end afs_vlocation_update_timer() *//*****************************************************************************//* * attend to an update operation upon which an event happened * - called in kafsasyncd context */static void afs_vlocation_update_attend(struct afs_async_op *op){	struct afs_cache_vlocation vldb;	struct afs_vlocation *vlocation =		list_entry(op, struct afs_vlocation, upd_op);	unsigned tmp;	int ret;	_enter("%s", vlocation->vldb.name);	ret = afs_rxvl_get_entry_by_id_async2(op, &vldb);	switch (ret) {	case -EAGAIN:		_leave(" [unfinished]");		return;	case 0:		_debug("END VL UPDATE: %d\n", ret);		vlocation->valid = 1;		_debug("Done VL Lookup: %02x { %08x(%x) %08x(%x) %08x(%x) }",		       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]);		afs_vlocation_update_abandon(vlocation, AFS_VLUPD_SLEEP, 0);		down_write(&vlocation->cell->vl_sem);		/* actually update the cache */		if (strncmp(vldb.name, vlocation->vldb.name,			    sizeof(vlocation->vldb.name)) != 0)			printk("kAFS: name of volume '%s'"			       " changed to '%s' on server\n",			       vlocation->vldb.name, vldb.name);		memcpy(&vlocation->vldb, &vldb, sizeof(vlocation->vldb));#if 0		/* TODO update volume entry in local cache */#endif		up_write(&vlocation->cell->vl_sem);		if (ret < 0)			printk("kAFS: failed to update local cache: %d\n", ret);		afs_kafstimod_add_timer(&vlocation->upd_timer,					AFS_VLDB_TIMEOUT);		afs_put_vlocation(vlocation);		_leave(" [found]");		return;	case -ENOMEDIUM:		vlocation->upd_rej_cnt++;		goto try_next;		/* the server is locked - retry in a very short while */	case -EBUSY:		vlocation->upd_busy_cnt++;		if (vlocation->upd_busy_cnt > 3)			goto try_next; /* too many retries */		afs_vlocation_update_abandon(vlocation,					     AFS_VLUPD_BUSYSLEEP, 0);		afs_kafstimod_add_timer(&vlocation->upd_timer, HZ / 2);		afs_put_vlocation(vlocation);		_leave(" [busy]");		return;	case -ENETUNREACH:	case -EHOSTUNREACH:	case -ECONNREFUSED:	case -EREMOTEIO:		/* record bad vlserver info in the cell too		 * - TODO: use down_write_trylock() if available		 */		if (vlocation->upd_curr_svix == vlocation->cell->vl_curr_svix)			vlocation->cell->vl_curr_svix =				vlocation->cell->vl_curr_svix %				vlocation->cell->vl_naddrs;	case -EBADRQC:	case -EINVAL:	case -EACCES:	case -EBADMSG:		goto try_next;	default:		goto abandon;	}	/* try contacting the next server */ try_next:	vlocation->upd_busy_cnt = 0;	/* discard the server record */	afs_put_server(vlocation->upd_op.server);	vlocation->upd_op.server = NULL;	tmp = vlocation->cell->vl_naddrs;	if (tmp == 0)		goto abandon;	vlocation->upd_curr_svix++;	if (vlocation->upd_curr_svix >= tmp)		vlocation->upd_curr_svix = 0;	if (vlocation->upd_first_svix >= tmp)		vlocation->upd_first_svix = tmp - 1;	/* move to the next server */	if (vlocation->upd_curr_svix != vlocation->upd_first_svix) {		afs_vlocation_update_begin(vlocation);		_leave(" [next]");		return;	}	/* run out of servers to try - was the volume rejected? */	if (vlocation->upd_rej_cnt > 0) {		printk("kAFS: Active volume no longer valid '%s'\n",		       vlocation->vldb.name);		vlocation->valid = 0;		afs_vlocation_update_abandon(vlocation, AFS_VLUPD_SLEEP, 0);		afs_kafstimod_add_timer(&vlocation->upd_timer,					AFS_VLDB_TIMEOUT);		afs_put_vlocation(vlocation);		_leave(" [invalidated]");		return;	}	/* abandon the update */ abandon:	afs_vlocation_update_abandon(vlocation, AFS_VLUPD_SLEEP, ret);	afs_kafstimod_add_timer(&vlocation->upd_timer, HZ * 10);	afs_put_vlocation(vlocation);	_leave(" [abandoned]");} /* end afs_vlocation_update_attend() *//*****************************************************************************//* * deal with an update operation being discarded * - called in kafsasyncd context when it's dying due to rmmod * - the call has already been aborted and put()'d */static void afs_vlocation_update_discard(struct afs_async_op *op){	struct afs_vlocation *vlocation =		list_entry(op, struct afs_vlocation, upd_op);	_enter("%s", vlocation->vldb.name);	afs_put_server(op->server);	op->server = NULL;	afs_put_vlocation(vlocation);	_leave("");} /* end afs_vlocation_update_discard() *//*****************************************************************************//* * match a VLDB record stored in the cache * - may also load target from entry */#ifdef AFS_CACHING_SUPPORTstatic cachefs_match_val_t afs_vlocation_cache_match(void *target,						     const void *entry){	const struct afs_cache_vlocation *vldb = entry;	struct afs_vlocation *vlocation = target;	_enter("{%s},{%s}", vlocation->vldb.name, vldb->name);	if (strncmp(vlocation->vldb.name, vldb->name, sizeof(vldb->name)) == 0	    ) {		if (!vlocation->valid ||		    vlocation->vldb.rtime == vldb->rtime		    ) {			vlocation->vldb = *vldb;			vlocation->valid = 1;			_leave(" = SUCCESS [c->m]");			return CACHEFS_MATCH_SUCCESS;		}		/* need to update cache if cached info differs */		else if (memcmp(&vlocation->vldb, vldb, sizeof(*vldb)) != 0) {			/* delete if VIDs for this name differ */			if (memcmp(&vlocation->vldb.vid,				   &vldb->vid,				   sizeof(vldb->vid)) != 0) {				_leave(" = DELETE");				return CACHEFS_MATCH_SUCCESS_DELETE;			}			_leave(" = UPDATE");			return CACHEFS_MATCH_SUCCESS_UPDATE;		}		else {			_leave(" = SUCCESS");			return CACHEFS_MATCH_SUCCESS;		}	}	_leave(" = FAILED");	return CACHEFS_MATCH_FAILED;} /* end afs_vlocation_cache_match() */#endif/*****************************************************************************//* * update a VLDB record stored in the cache */#ifdef AFS_CACHING_SUPPORTstatic void afs_vlocation_cache_update(void *source, void *entry){	struct afs_cache_vlocation *vldb = entry;	struct afs_vlocation *vlocation = source;	_enter("");	*vldb = vlocation->vldb;} /* end afs_vlocation_cache_update() */#endif

⌨️ 快捷键说明

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