Commit 8a070a96 authored by David Howells's avatar David Howells
Browse files

afs: Detect cell aliases 1 - Cells with root volumes



Put in the first phase of cell alias detection.  This part handles alias
detection for cells that have root.cell volumes (which is expected to be
likely).

When a cell becomes newly active, it is probed for its root.cell volume,
and if it has one, this volume is compared against other root.cell volumes
to find out if the list of fileserver UUIDs have any in common - and if
that's the case, do the address lists of those fileservers have any
addresses in common.  If they do, the new cell is adjudged to be an alias
of the old cell and the old cell is used instead.

Comparing is aided by the server list in struct afs_server_list being
sorted in UUID order and the addresses in the fileserver address lists
being sorted in address order.

The cell then retains the afs_volume object for the root.cell volume, even
if it's not mounted for future alias checking.

This necessary because:

 (1) Whilst fileservers have UUIDs that are meant to be globally unique, in
     practice they are not because cells get cloned without changing the
     UUIDs - so afs_server records need to be per cell.

 (2) Sometimes the DNS is used to make cell aliases - but if we don't know
     they're the same, we may end up with multiple superblocks and multiple
     afs_server records for the same thing, impairing our ability to
     deliver callback notifications of third party changes

 (3) The fileserver RPC API doesn't contain the cell name, so it can't tell
     us which cell it's notifying and can't see that a change made to to
     one cell should notify the same client that's also accessed as the
     other cell.

Reported-by: default avatarJeffrey Altman <jaltman@auristor.com>
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
parent c3e9f888
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ kafs-y := \
	server_list.o \
	super.o \
	vlclient.o \
	vl_alias.o \
	vl_list.o \
	vl_probe.o \
	vl_rotate.o \
+3 −0
Original line number Diff line number Diff line
@@ -164,6 +164,7 @@ static struct afs_cell *afs_alloc_cell(struct afs_net *net,
	INIT_LIST_HEAD(&cell->proc_volumes);
	rwlock_init(&cell->proc_lock);
	rwlock_init(&cell->vl_servers_lock);
	cell->flags = (1 << AFS_CELL_FL_CHECK_ALIAS);

	/* Provide a VL server list, filling it in if we were given a list of
	 * addresses to use.
@@ -481,7 +482,9 @@ static void afs_cell_destroy(struct rcu_head *rcu)

	ASSERTCMP(atomic_read(&cell->usage), ==, 0);

	afs_put_volume(cell->net, cell->root_volume);
	afs_put_vlserverlist(cell->net, rcu_access_pointer(cell->vl_servers));
	afs_put_cell(cell->net, cell->alias_of);
	key_put(cell->anonymous_key);
	kfree(cell);

+14 −3
Original line number Diff line number Diff line
@@ -269,6 +269,7 @@ struct afs_net {
	struct timer_list	cells_timer;
	atomic_t		cells_outstanding;
	seqlock_t		cells_lock;
	struct mutex		cells_alias_lock;

	struct mutex		proc_cells_lock;
	struct hlist_head	proc_cells;
@@ -342,8 +343,10 @@ enum afs_cell_state {
 * for authentication and encryption.  The cell name is not typically used in
 * the protocol.
 *
 * There is no easy way to determine if two cells are aliases or one is a
 * subset of another.
 * Two cells are determined to be aliases if they have an explicit alias (YFS
 * only), share any VL servers in common or have at least one volume in common.
 * "In common" means that the address list of the VL servers or the fileservers
 * share at least one endpoint.
 */
struct afs_cell {
	union {
@@ -351,6 +354,8 @@ struct afs_cell {
		struct rb_node	net_node;	/* Node in net->cells */
	};
	struct afs_net		*net;
	struct afs_cell		*alias_of;	/* The cell this is an alias of */
	struct afs_volume	*root_volume;	/* The root.cell volume if there is one */
	struct key		*anonymous_key;	/* anonymous user key for this cell */
	struct work_struct	manager;	/* Manager for init/deinit/dns */
	struct hlist_node	proc_link;	/* /proc cell list link */
@@ -363,6 +368,7 @@ struct afs_cell {
	unsigned long		flags;
#define AFS_CELL_FL_NO_GC	0		/* The cell was added manually, don't auto-gc */
#define AFS_CELL_FL_DO_LOOKUP	1		/* DNS lookup requested */
#define AFS_CELL_FL_CHECK_ALIAS	2		/* Need to check for aliases */
	enum afs_cell_state	state;
	short			error;
	enum dns_record_source	dns_source:8;	/* Latest source of data from lookup */
@@ -584,7 +590,7 @@ struct afs_volume {
#ifdef CONFIG_AFS_FSCACHE
	struct fscache_cookie	*cache;		/* caching cookie */
#endif
	struct afs_server_list	*servers;	/* List of servers on which volume resides */
	struct afs_server_list __rcu *servers;	/* List of servers on which volume resides */
	rwlock_t		servers_lock;	/* Lock for ->servers */
	unsigned int		servers_seq;	/* Incremented each time ->servers changes */

@@ -1376,6 +1382,11 @@ extern struct afs_call *afs_vl_get_capabilities(struct afs_net *, struct afs_add
extern struct afs_addr_list *afs_yfsvl_get_endpoints(struct afs_vl_cursor *, const uuid_t *);
extern char *afs_yfsvl_get_cell_name(struct afs_vl_cursor *);

/*
 * vl_alias.c
 */
extern int afs_cell_detect_alias(struct afs_cell *, struct key *);

/*
 * vl_probe.c
 */
+1 −0
Original line number Diff line number Diff line
@@ -82,6 +82,7 @@ static int __net_init afs_net_init(struct net *net_ns)
	INIT_WORK(&net->cells_manager, afs_manage_cells);
	timer_setup(&net->cells_timer, afs_cells_timer, 0);

	mutex_init(&net->cells_alias_lock);
	mutex_init(&net->proc_cells_lock);
	INIT_HLIST_HEAD(&net->proc_cells);

+3 −2
Original line number Diff line number Diff line
@@ -38,7 +38,7 @@ static int afs_proc_cells_show(struct seq_file *m, void *v)

	if (v == SEQ_START_TOKEN) {
		/* display header on line 1 */
		seq_puts(m, "USE    TTL SV NAME\n");
		seq_puts(m, "USE    TTL SV ST NAME\n");
		return 0;
	}

@@ -46,10 +46,11 @@ static int afs_proc_cells_show(struct seq_file *m, void *v)
	vllist = rcu_dereference(cell->vl_servers);

	/* display one cell per line on subsequent lines */
	seq_printf(m, "%3u %6lld %2u %s\n",
	seq_printf(m, "%3u %6lld %2u %2u %s\n",
		   atomic_read(&cell->usage),
		   cell->dns_expiry - ktime_get_real_seconds(),
		   vllist->nr_servers,
		   cell->state,
		   cell->name);
	return 0;
}
Loading