mirror of
				https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
				synced 2025-10-31 09:36:25 +00:00 
			
		
		
		
	 f116629d03
			
		
	
	
		f116629d03
		
	
	
	
	
		
			
			This patch converts the combination of list_del(A) and list_add(A, B) to list_move(A, B) under fs/. Cc: Ian Kent <raven@themaw.net> Acked-by: Joel Becker <joel.becker@oracle.com> Cc: Neil Brown <neilb@cse.unsw.edu.au> Cc: Hans Reiser <reiserfs-dev@namesys.com> Cc: Urban Widmark <urban@teststation.com> Acked-by: David Howells <dhowells@redhat.com> Acked-by: Mark Fasheh <mark.fasheh@oracle.com> Signed-off-by: Akinobu Mita <mita@miraclelinux.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
		
			
				
	
	
		
			569 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			569 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* cell.c: AFS cell and server record 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/module.h>
 | |
| #include <linux/sched.h>
 | |
| #include <linux/slab.h>
 | |
| #include <rxrpc/peer.h>
 | |
| #include <rxrpc/connection.h>
 | |
| #include "volume.h"
 | |
| #include "cell.h"
 | |
| #include "server.h"
 | |
| #include "transport.h"
 | |
| #include "vlclient.h"
 | |
| #include "kafstimod.h"
 | |
| #include "super.h"
 | |
| #include "internal.h"
 | |
| 
 | |
| DECLARE_RWSEM(afs_proc_cells_sem);
 | |
| LIST_HEAD(afs_proc_cells);
 | |
| 
 | |
| static struct list_head afs_cells = LIST_HEAD_INIT(afs_cells);
 | |
| static DEFINE_RWLOCK(afs_cells_lock);
 | |
| static DECLARE_RWSEM(afs_cells_sem); /* add/remove serialisation */
 | |
| static struct afs_cell *afs_cell_root;
 | |
| 
 | |
| #ifdef AFS_CACHING_SUPPORT
 | |
| static cachefs_match_val_t afs_cell_cache_match(void *target,
 | |
| 						const void *entry);
 | |
| static void afs_cell_cache_update(void *source, void *entry);
 | |
| 
 | |
| struct cachefs_index_def afs_cache_cell_index_def = {
 | |
| 	.name			= "cell_ix",
 | |
| 	.data_size		= sizeof(struct afs_cache_cell),
 | |
| 	.keys[0]		= { CACHEFS_INDEX_KEYS_ASCIIZ, 64 },
 | |
| 	.match			= afs_cell_cache_match,
 | |
| 	.update			= afs_cell_cache_update,
 | |
| };
 | |
| #endif
 | |
| 
 | |
| /*****************************************************************************/
 | |
| /*
 | |
|  * create a cell record
 | |
|  * - "name" is the name of the cell
 | |
|  * - "vllist" is a colon separated list of IP addresses in "a.b.c.d" format
 | |
|  */
 | |
| int afs_cell_create(const char *name, char *vllist, struct afs_cell **_cell)
 | |
| {
 | |
| 	struct afs_cell *cell;
 | |
| 	char *next;
 | |
| 	int ret;
 | |
| 
 | |
| 	_enter("%s", name);
 | |
| 
 | |
| 	BUG_ON(!name); /* TODO: want to look up "this cell" in the cache */
 | |
| 
 | |
| 	/* allocate and initialise a cell record */
 | |
| 	cell = kmalloc(sizeof(struct afs_cell) + strlen(name) + 1, GFP_KERNEL);
 | |
| 	if (!cell) {
 | |
| 		_leave(" = -ENOMEM");
 | |
| 		return -ENOMEM;
 | |
| 	}
 | |
| 
 | |
| 	down_write(&afs_cells_sem);
 | |
| 
 | |
| 	memset(cell, 0, sizeof(struct afs_cell));
 | |
| 	atomic_set(&cell->usage, 0);
 | |
| 
 | |
| 	INIT_LIST_HEAD(&cell->link);
 | |
| 
 | |
| 	rwlock_init(&cell->sv_lock);
 | |
| 	INIT_LIST_HEAD(&cell->sv_list);
 | |
| 	INIT_LIST_HEAD(&cell->sv_graveyard);
 | |
| 	spin_lock_init(&cell->sv_gylock);
 | |
| 
 | |
| 	init_rwsem(&cell->vl_sem);
 | |
| 	INIT_LIST_HEAD(&cell->vl_list);
 | |
| 	INIT_LIST_HEAD(&cell->vl_graveyard);
 | |
| 	spin_lock_init(&cell->vl_gylock);
 | |
| 
 | |
| 	strcpy(cell->name,name);
 | |
| 
 | |
| 	/* fill in the VL server list from the rest of the string */
 | |
| 	ret = -EINVAL;
 | |
| 	do {
 | |
| 		unsigned a, b, c, d;
 | |
| 
 | |
| 		next = strchr(vllist, ':');
 | |
| 		if (next)
 | |
| 			*next++ = 0;
 | |
| 
 | |
| 		if (sscanf(vllist, "%u.%u.%u.%u", &a, &b, &c, &d) != 4)
 | |
| 			goto badaddr;
 | |
| 
 | |
| 		if (a > 255 || b > 255 || c > 255 || d > 255)
 | |
| 			goto badaddr;
 | |
| 
 | |
| 		cell->vl_addrs[cell->vl_naddrs++].s_addr =
 | |
| 			htonl((a << 24) | (b << 16) | (c << 8) | d);
 | |
| 
 | |
| 		if (cell->vl_naddrs >= AFS_CELL_MAX_ADDRS)
 | |
| 			break;
 | |
| 
 | |
| 	} while(vllist = next, vllist);
 | |
| 
 | |
| 	/* add a proc dir for this cell */
 | |
| 	ret = afs_proc_cell_setup(cell);
 | |
| 	if (ret < 0)
 | |
| 		goto error;
 | |
| 
 | |
| #ifdef AFS_CACHING_SUPPORT
 | |
| 	/* put it up for caching */
 | |
| 	cachefs_acquire_cookie(afs_cache_netfs.primary_index,
 | |
| 			       &afs_vlocation_cache_index_def,
 | |
| 			       cell,
 | |
| 			       &cell->cache);
 | |
| #endif
 | |
| 
 | |
| 	/* add to the cell lists */
 | |
| 	write_lock(&afs_cells_lock);
 | |
| 	list_add_tail(&cell->link, &afs_cells);
 | |
| 	write_unlock(&afs_cells_lock);
 | |
| 
 | |
| 	down_write(&afs_proc_cells_sem);
 | |
| 	list_add_tail(&cell->proc_link, &afs_proc_cells);
 | |
| 	up_write(&afs_proc_cells_sem);
 | |
| 
 | |
| 	*_cell = cell;
 | |
| 	up_write(&afs_cells_sem);
 | |
| 
 | |
| 	_leave(" = 0 (%p)", cell);
 | |
| 	return 0;
 | |
| 
 | |
|  badaddr:
 | |
| 	printk(KERN_ERR "kAFS: bad VL server IP address: '%s'\n", vllist);
 | |
|  error:
 | |
| 	up_write(&afs_cells_sem);
 | |
| 	kfree(cell);
 | |
| 	_leave(" = %d", ret);
 | |
| 	return ret;
 | |
| } /* end afs_cell_create() */
 | |
| 
 | |
| /*****************************************************************************/
 | |
| /*
 | |
|  * initialise the cell database from module parameters
 | |
|  */
 | |
| int afs_cell_init(char *rootcell)
 | |
| {
 | |
| 	struct afs_cell *old_root, *new_root;
 | |
| 	char *cp;
 | |
| 	int ret;
 | |
| 
 | |
| 	_enter("");
 | |
| 
 | |
| 	if (!rootcell) {
 | |
| 		/* module is loaded with no parameters, or built statically.
 | |
| 		 * - in the future we might initialize cell DB here.
 | |
| 		 */
 | |
| 		_leave(" = 0 (but no root)");
 | |
| 		return 0;
 | |
| 	}
 | |
| 
 | |
| 	cp = strchr(rootcell, ':');
 | |
| 	if (!cp) {
 | |
| 		printk(KERN_ERR "kAFS: no VL server IP addresses specified\n");
 | |
| 		_leave(" = %d (no colon)", -EINVAL);
 | |
| 		return -EINVAL;
 | |
| 	}
 | |
| 
 | |
| 	/* allocate a cell record for the root cell */
 | |
| 	*cp++ = 0;
 | |
| 	ret = afs_cell_create(rootcell, cp, &new_root);
 | |
| 	if (ret < 0) {
 | |
| 		_leave(" = %d", ret);
 | |
| 		return ret;
 | |
| 	}
 | |
| 
 | |
| 	/* as afs_put_cell() takes locks by itself, we have to do
 | |
| 	 * a little gymnastics to be race-free.
 | |
| 	 */
 | |
| 	afs_get_cell(new_root);
 | |
| 
 | |
| 	write_lock(&afs_cells_lock);
 | |
| 	while (afs_cell_root) {
 | |
| 		old_root = afs_cell_root;
 | |
| 		afs_cell_root = NULL;
 | |
| 		write_unlock(&afs_cells_lock);
 | |
| 		afs_put_cell(old_root);
 | |
| 		write_lock(&afs_cells_lock);
 | |
| 	}
 | |
| 	afs_cell_root = new_root;
 | |
| 	write_unlock(&afs_cells_lock);
 | |
| 
 | |
| 	_leave(" = %d", ret);
 | |
| 	return ret;
 | |
| 
 | |
| } /* end afs_cell_init() */
 | |
| 
 | |
| /*****************************************************************************/
 | |
| /*
 | |
|  * lookup a cell record
 | |
|  */
 | |
| int afs_cell_lookup(const char *name, unsigned namesz, struct afs_cell **_cell)
 | |
| {
 | |
| 	struct afs_cell *cell;
 | |
| 	int ret;
 | |
| 
 | |
| 	_enter("\"%*.*s\",", namesz, namesz, name ? name : "");
 | |
| 
 | |
| 	*_cell = NULL;
 | |
| 
 | |
| 	if (name) {
 | |
| 		/* if the cell was named, look for it in the cell record list */
 | |
| 		ret = -ENOENT;
 | |
| 		cell = NULL;
 | |
| 		read_lock(&afs_cells_lock);
 | |
| 
 | |
| 		list_for_each_entry(cell, &afs_cells, link) {
 | |
| 			if (strncmp(cell->name, name, namesz) == 0) {
 | |
| 				afs_get_cell(cell);
 | |
| 				goto found;
 | |
| 			}
 | |
| 		}
 | |
| 		cell = NULL;
 | |
| 	found:
 | |
| 
 | |
| 		read_unlock(&afs_cells_lock);
 | |
| 
 | |
| 		if (cell)
 | |
| 			ret = 0;
 | |
| 	}
 | |
| 	else {
 | |
| 		read_lock(&afs_cells_lock);
 | |
| 
 | |
| 		cell = afs_cell_root;
 | |
| 		if (!cell) {
 | |
| 			/* this should not happen unless user tries to mount
 | |
| 			 * when root cell is not set. Return an impossibly
 | |
| 			 * bizzare errno to alert the user. Things like
 | |
| 			 * ENOENT might be "more appropriate" but they happen
 | |
| 			 * for other reasons.
 | |
| 			 */
 | |
| 			ret = -EDESTADDRREQ;
 | |
| 		}
 | |
| 		else {
 | |
| 			afs_get_cell(cell);
 | |
| 			ret = 0;
 | |
| 		}
 | |
| 
 | |
| 		read_unlock(&afs_cells_lock);
 | |
| 	}
 | |
| 
 | |
| 	*_cell = cell;
 | |
| 	_leave(" = %d (%p)", ret, cell);
 | |
| 	return ret;
 | |
| 
 | |
| } /* end afs_cell_lookup() */
 | |
| 
 | |
| /*****************************************************************************/
 | |
| /*
 | |
|  * try and get a cell record
 | |
|  */
 | |
| struct afs_cell *afs_get_cell_maybe(struct afs_cell **_cell)
 | |
| {
 | |
| 	struct afs_cell *cell;
 | |
| 
 | |
| 	write_lock(&afs_cells_lock);
 | |
| 
 | |
| 	cell = *_cell;
 | |
| 	if (cell && !list_empty(&cell->link))
 | |
| 		afs_get_cell(cell);
 | |
| 	else
 | |
| 		cell = NULL;
 | |
| 
 | |
| 	write_unlock(&afs_cells_lock);
 | |
| 
 | |
| 	return cell;
 | |
| } /* end afs_get_cell_maybe() */
 | |
| 
 | |
| /*****************************************************************************/
 | |
| /*
 | |
|  * destroy a cell record
 | |
|  */
 | |
| void afs_put_cell(struct afs_cell *cell)
 | |
| {
 | |
| 	if (!cell)
 | |
| 		return;
 | |
| 
 | |
| 	_enter("%p{%d,%s}", cell, atomic_read(&cell->usage), cell->name);
 | |
| 
 | |
| 	/* sanity check */
 | |
| 	BUG_ON(atomic_read(&cell->usage) <= 0);
 | |
| 
 | |
| 	/* to prevent a race, the decrement and the dequeue must be effectively
 | |
| 	 * atomic */
 | |
| 	write_lock(&afs_cells_lock);
 | |
| 
 | |
| 	if (likely(!atomic_dec_and_test(&cell->usage))) {
 | |
| 		write_unlock(&afs_cells_lock);
 | |
| 		_leave("");
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	write_unlock(&afs_cells_lock);
 | |
| 
 | |
| 	BUG_ON(!list_empty(&cell->sv_list));
 | |
| 	BUG_ON(!list_empty(&cell->sv_graveyard));
 | |
| 	BUG_ON(!list_empty(&cell->vl_list));
 | |
| 	BUG_ON(!list_empty(&cell->vl_graveyard));
 | |
| 
 | |
| 	_leave(" [unused]");
 | |
| } /* end afs_put_cell() */
 | |
| 
 | |
| /*****************************************************************************/
 | |
| /*
 | |
|  * destroy a cell record
 | |
|  */
 | |
| static void afs_cell_destroy(struct afs_cell *cell)
 | |
| {
 | |
| 	_enter("%p{%d,%s}", cell, atomic_read(&cell->usage), cell->name);
 | |
| 
 | |
| 	/* to prevent a race, the decrement and the dequeue must be effectively
 | |
| 	 * atomic */
 | |
| 	write_lock(&afs_cells_lock);
 | |
| 
 | |
| 	/* sanity check */
 | |
| 	BUG_ON(atomic_read(&cell->usage) != 0);
 | |
| 
 | |
| 	list_del_init(&cell->link);
 | |
| 
 | |
| 	write_unlock(&afs_cells_lock);
 | |
| 
 | |
| 	down_write(&afs_cells_sem);
 | |
| 
 | |
| 	afs_proc_cell_remove(cell);
 | |
| 
 | |
| 	down_write(&afs_proc_cells_sem);
 | |
| 	list_del_init(&cell->proc_link);
 | |
| 	up_write(&afs_proc_cells_sem);
 | |
| 
 | |
| #ifdef AFS_CACHING_SUPPORT
 | |
| 	cachefs_relinquish_cookie(cell->cache, 0);
 | |
| #endif
 | |
| 
 | |
| 	up_write(&afs_cells_sem);
 | |
| 
 | |
| 	BUG_ON(!list_empty(&cell->sv_list));
 | |
| 	BUG_ON(!list_empty(&cell->sv_graveyard));
 | |
| 	BUG_ON(!list_empty(&cell->vl_list));
 | |
| 	BUG_ON(!list_empty(&cell->vl_graveyard));
 | |
| 
 | |
| 	/* finish cleaning up the cell */
 | |
| 	kfree(cell);
 | |
| 
 | |
| 	_leave(" [destroyed]");
 | |
| } /* end afs_cell_destroy() */
 | |
| 
 | |
| /*****************************************************************************/
 | |
| /*
 | |
|  * lookup the server record corresponding to an Rx RPC peer
 | |
|  */
 | |
| int afs_server_find_by_peer(const struct rxrpc_peer *peer,
 | |
| 			    struct afs_server **_server)
 | |
| {
 | |
| 	struct afs_server *server;
 | |
| 	struct afs_cell *cell;
 | |
| 
 | |
| 	_enter("%p{a=%08x},", peer, ntohl(peer->addr.s_addr));
 | |
| 
 | |
| 	/* search the cell list */
 | |
| 	read_lock(&afs_cells_lock);
 | |
| 
 | |
| 	list_for_each_entry(cell, &afs_cells, link) {
 | |
| 
 | |
| 		_debug("? cell %s",cell->name);
 | |
| 
 | |
| 		write_lock(&cell->sv_lock);
 | |
| 
 | |
| 		/* check the active list */
 | |
| 		list_for_each_entry(server, &cell->sv_list, link) {
 | |
| 			_debug("?? server %08x", ntohl(server->addr.s_addr));
 | |
| 
 | |
| 			if (memcmp(&server->addr, &peer->addr,
 | |
| 				   sizeof(struct in_addr)) == 0)
 | |
| 				goto found_server;
 | |
| 		}
 | |
| 
 | |
| 		/* check the inactive list */
 | |
| 		spin_lock(&cell->sv_gylock);
 | |
| 		list_for_each_entry(server, &cell->sv_graveyard, link) {
 | |
| 			_debug("?? dead server %08x",
 | |
| 			       ntohl(server->addr.s_addr));
 | |
| 
 | |
| 			if (memcmp(&server->addr, &peer->addr,
 | |
| 				   sizeof(struct in_addr)) == 0)
 | |
| 				goto found_dead_server;
 | |
| 		}
 | |
| 		spin_unlock(&cell->sv_gylock);
 | |
| 
 | |
| 		write_unlock(&cell->sv_lock);
 | |
| 	}
 | |
| 	read_unlock(&afs_cells_lock);
 | |
| 
 | |
| 	_leave(" = -ENOENT");
 | |
| 	return -ENOENT;
 | |
| 
 | |
| 	/* we found it in the graveyard - resurrect it */
 | |
|  found_dead_server:
 | |
| 	list_move_tail(&server->link, &cell->sv_list);
 | |
| 	afs_get_server(server);
 | |
| 	afs_kafstimod_del_timer(&server->timeout);
 | |
| 	spin_unlock(&cell->sv_gylock);
 | |
| 	goto success;
 | |
| 
 | |
| 	/* we found it - increment its ref count and return it */
 | |
|  found_server:
 | |
| 	afs_get_server(server);
 | |
| 
 | |
|  success:
 | |
| 	write_unlock(&cell->sv_lock);
 | |
| 	read_unlock(&afs_cells_lock);
 | |
| 
 | |
| 	*_server = server;
 | |
| 	_leave(" = 0 (s=%p c=%p)", server, cell);
 | |
| 	return 0;
 | |
| 
 | |
| } /* end afs_server_find_by_peer() */
 | |
| 
 | |
| /*****************************************************************************/
 | |
| /*
 | |
|  * purge in-memory cell database on module unload or afs_init() failure
 | |
|  * - the timeout daemon is stopped before calling this
 | |
|  */
 | |
| void afs_cell_purge(void)
 | |
| {
 | |
| 	struct afs_vlocation *vlocation;
 | |
| 	struct afs_cell *cell;
 | |
| 
 | |
| 	_enter("");
 | |
| 
 | |
| 	afs_put_cell(afs_cell_root);
 | |
| 
 | |
| 	while (!list_empty(&afs_cells)) {
 | |
| 		cell = NULL;
 | |
| 
 | |
| 		/* remove the next cell from the front of the list */
 | |
| 		write_lock(&afs_cells_lock);
 | |
| 
 | |
| 		if (!list_empty(&afs_cells)) {
 | |
| 			cell = list_entry(afs_cells.next,
 | |
| 					  struct afs_cell, link);
 | |
| 			list_del_init(&cell->link);
 | |
| 		}
 | |
| 
 | |
| 		write_unlock(&afs_cells_lock);
 | |
| 
 | |
| 		if (cell) {
 | |
| 			_debug("PURGING CELL %s (%d)",
 | |
| 			       cell->name, atomic_read(&cell->usage));
 | |
| 
 | |
| 			BUG_ON(!list_empty(&cell->sv_list));
 | |
| 			BUG_ON(!list_empty(&cell->vl_list));
 | |
| 
 | |
| 			/* purge the cell's VL graveyard list */
 | |
| 			_debug(" - clearing VL graveyard");
 | |
| 
 | |
| 			spin_lock(&cell->vl_gylock);
 | |
| 
 | |
| 			while (!list_empty(&cell->vl_graveyard)) {
 | |
| 				vlocation = list_entry(cell->vl_graveyard.next,
 | |
| 						       struct afs_vlocation,
 | |
| 						       link);
 | |
| 				list_del_init(&vlocation->link);
 | |
| 
 | |
| 				afs_kafstimod_del_timer(&vlocation->timeout);
 | |
| 
 | |
| 				spin_unlock(&cell->vl_gylock);
 | |
| 
 | |
| 				afs_vlocation_do_timeout(vlocation);
 | |
| 				/* TODO: race if move to use krxtimod instead
 | |
| 				 * of kafstimod */
 | |
| 
 | |
| 				spin_lock(&cell->vl_gylock);
 | |
| 			}
 | |
| 
 | |
| 			spin_unlock(&cell->vl_gylock);
 | |
| 
 | |
| 			/* purge the cell's server graveyard list */
 | |
| 			_debug(" - clearing server graveyard");
 | |
| 
 | |
| 			spin_lock(&cell->sv_gylock);
 | |
| 
 | |
| 			while (!list_empty(&cell->sv_graveyard)) {
 | |
| 				struct afs_server *server;
 | |
| 
 | |
| 				server = list_entry(cell->sv_graveyard.next,
 | |
| 						    struct afs_server, link);
 | |
| 				list_del_init(&server->link);
 | |
| 
 | |
| 				afs_kafstimod_del_timer(&server->timeout);
 | |
| 
 | |
| 				spin_unlock(&cell->sv_gylock);
 | |
| 
 | |
| 				afs_server_do_timeout(server);
 | |
| 
 | |
| 				spin_lock(&cell->sv_gylock);
 | |
| 			}
 | |
| 
 | |
| 			spin_unlock(&cell->sv_gylock);
 | |
| 
 | |
| 			/* now the cell should be left with no references */
 | |
| 			afs_cell_destroy(cell);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	_leave("");
 | |
| } /* end afs_cell_purge() */
 | |
| 
 | |
| /*****************************************************************************/
 | |
| /*
 | |
|  * match a cell record obtained from the cache
 | |
|  */
 | |
| #ifdef AFS_CACHING_SUPPORT
 | |
| static cachefs_match_val_t afs_cell_cache_match(void *target,
 | |
| 						const void *entry)
 | |
| {
 | |
| 	const struct afs_cache_cell *ccell = entry;
 | |
| 	struct afs_cell *cell = target;
 | |
| 
 | |
| 	_enter("{%s},{%s}", ccell->name, cell->name);
 | |
| 
 | |
| 	if (strncmp(ccell->name, cell->name, sizeof(ccell->name)) == 0) {
 | |
| 		_leave(" = SUCCESS");
 | |
| 		return CACHEFS_MATCH_SUCCESS;
 | |
| 	}
 | |
| 
 | |
| 	_leave(" = FAILED");
 | |
| 	return CACHEFS_MATCH_FAILED;
 | |
| } /* end afs_cell_cache_match() */
 | |
| #endif
 | |
| 
 | |
| /*****************************************************************************/
 | |
| /*
 | |
|  * update a cell record in the cache
 | |
|  */
 | |
| #ifdef AFS_CACHING_SUPPORT
 | |
| static void afs_cell_cache_update(void *source, void *entry)
 | |
| {
 | |
| 	struct afs_cache_cell *ccell = entry;
 | |
| 	struct afs_cell *cell = source;
 | |
| 
 | |
| 	_enter("%p,%p", source, entry);
 | |
| 
 | |
| 	strncpy(ccell->name, cell->name, sizeof(ccell->name));
 | |
| 
 | |
| 	memcpy(ccell->vl_servers,
 | |
| 	       cell->vl_addrs,
 | |
| 	       min(sizeof(ccell->vl_servers), sizeof(cell->vl_addrs)));
 | |
| 
 | |
| } /* end afs_cell_cache_update() */
 | |
| #endif
 |