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: Jeffrey Altman <jaltman@auristor.com>
Signed-off-by: David Howells <dhowells@redhat.com>
2020-04-25 17:26:02 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
/* AFS cell alias detection
|
|
|
|
*
|
|
|
|
* Copyright (C) 2020 Red Hat, Inc. All Rights Reserved.
|
|
|
|
* Written by David Howells (dhowells@redhat.com)
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/slab.h>
|
|
|
|
#include <linux/sched.h>
|
|
|
|
#include <linux/namei.h>
|
|
|
|
#include <keys/rxrpc-type.h>
|
|
|
|
#include "internal.h"
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Sample a volume.
|
|
|
|
*/
|
|
|
|
static struct afs_volume *afs_sample_volume(struct afs_cell *cell, struct key *key,
|
|
|
|
const char *name, unsigned int namelen)
|
|
|
|
{
|
|
|
|
struct afs_volume *volume;
|
|
|
|
struct afs_fs_context fc = {
|
|
|
|
.type = 0, /* Explicitly leave it to the VLDB */
|
|
|
|
.volnamesz = namelen,
|
|
|
|
.volname = name,
|
|
|
|
.net = cell->net,
|
|
|
|
.cell = cell,
|
|
|
|
.key = key, /* This might need to be something */
|
|
|
|
};
|
|
|
|
|
|
|
|
volume = afs_create_volume(&fc);
|
2020-06-09 23:25:02 +08:00
|
|
|
_leave(" = %p", volume);
|
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: Jeffrey Altman <jaltman@auristor.com>
Signed-off-by: David Howells <dhowells@redhat.com>
2020-04-25 17:26:02 +08:00
|
|
|
return volume;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Compare the address lists of a pair of fileservers.
|
|
|
|
*/
|
|
|
|
static int afs_compare_fs_alists(const struct afs_server *server_a,
|
|
|
|
const struct afs_server *server_b)
|
|
|
|
{
|
|
|
|
const struct afs_addr_list *la, *lb;
|
|
|
|
int a = 0, b = 0, addr_matches = 0;
|
|
|
|
|
2023-11-01 00:30:37 +08:00
|
|
|
la = rcu_dereference(server_a->endpoint_state)->addresses;
|
|
|
|
lb = rcu_dereference(server_b->endpoint_state)->addresses;
|
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: Jeffrey Altman <jaltman@auristor.com>
Signed-off-by: David Howells <dhowells@redhat.com>
2020-04-25 17:26:02 +08:00
|
|
|
|
|
|
|
while (a < la->nr_addrs && b < lb->nr_addrs) {
|
rxrpc, afs: Allow afs to pin rxrpc_peer objects
Change rxrpc's API such that:
(1) A new function, rxrpc_kernel_lookup_peer(), is provided to look up an
rxrpc_peer record for a remote address and a corresponding function,
rxrpc_kernel_put_peer(), is provided to dispose of it again.
(2) When setting up a call, the rxrpc_peer object used during a call is
now passed in rather than being set up by rxrpc_connect_call(). For
afs, this meenat passing it to rxrpc_kernel_begin_call() rather than
the full address (the service ID then has to be passed in as a
separate parameter).
(3) A new function, rxrpc_kernel_remote_addr(), is added so that afs can
get a pointer to the transport address for display purposed, and
another, rxrpc_kernel_remote_srx(), to gain a pointer to the full
rxrpc address.
(4) The function to retrieve the RTT from a call, rxrpc_kernel_get_srtt(),
is then altered to take a peer. This now returns the RTT or -1 if
there are insufficient samples.
(5) Rename rxrpc_kernel_get_peer() to rxrpc_kernel_call_get_peer().
(6) Provide a new function, rxrpc_kernel_get_peer(), to get a ref on a
peer the caller already has.
This allows the afs filesystem to pin the rxrpc_peer records that it is
using, allowing faster lookups and pointer comparisons rather than
comparing sockaddr_rxrpc contents. It also makes it easier to get hold of
the RTT. The following changes are made to afs:
(1) The addr_list struct's addrs[] elements now hold a peer struct pointer
and a service ID rather than a sockaddr_rxrpc.
(2) When displaying the transport address, rxrpc_kernel_remote_addr() is
used.
(3) The port arg is removed from afs_alloc_addrlist() since it's always
overridden.
(4) afs_merge_fs_addr4() and afs_merge_fs_addr6() do peer lookup and may
now return an error that must be handled.
(5) afs_find_server() now takes a peer pointer to specify the address.
(6) afs_find_server(), afs_compare_fs_alists() and afs_merge_fs_addr[46]{}
now do peer pointer comparison rather than address comparison.
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: linux-afs@lists.infradead.org
2023-10-19 19:55:11 +08:00
|
|
|
unsigned long pa = (unsigned long)la->addrs[a].peer;
|
|
|
|
unsigned long pb = (unsigned long)lb->addrs[b].peer;
|
|
|
|
long diff = pa - pb;
|
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: Jeffrey Altman <jaltman@auristor.com>
Signed-off-by: David Howells <dhowells@redhat.com>
2020-04-25 17:26:02 +08:00
|
|
|
|
|
|
|
if (diff < 0) {
|
|
|
|
a++;
|
|
|
|
} else if (diff > 0) {
|
|
|
|
b++;
|
|
|
|
} else {
|
|
|
|
addr_matches++;
|
|
|
|
a++;
|
|
|
|
b++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return addr_matches;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Compare the fileserver lists of two volumes. The server lists are sorted in
|
|
|
|
* order of ascending UUID.
|
|
|
|
*/
|
|
|
|
static int afs_compare_volume_slists(const struct afs_volume *vol_a,
|
|
|
|
const struct afs_volume *vol_b)
|
|
|
|
{
|
|
|
|
const struct afs_server_list *la, *lb;
|
|
|
|
int i, a = 0, b = 0, uuid_matches = 0, addr_matches = 0;
|
|
|
|
|
|
|
|
la = rcu_dereference(vol_a->servers);
|
|
|
|
lb = rcu_dereference(vol_b->servers);
|
|
|
|
|
|
|
|
for (i = 0; i < AFS_MAXTYPES; i++)
|
2023-11-03 00:08:43 +08:00
|
|
|
if (vol_a->vids[i] != vol_b->vids[i])
|
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: Jeffrey Altman <jaltman@auristor.com>
Signed-off-by: David Howells <dhowells@redhat.com>
2020-04-25 17:26:02 +08:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
while (a < la->nr_servers && b < lb->nr_servers) {
|
|
|
|
const struct afs_server *server_a = la->servers[a].server;
|
|
|
|
const struct afs_server *server_b = lb->servers[b].server;
|
|
|
|
int diff = memcmp(&server_a->uuid, &server_b->uuid, sizeof(uuid_t));
|
|
|
|
|
|
|
|
if (diff < 0) {
|
|
|
|
a++;
|
|
|
|
} else if (diff > 0) {
|
|
|
|
b++;
|
|
|
|
} else {
|
|
|
|
uuid_matches++;
|
|
|
|
addr_matches += afs_compare_fs_alists(server_a, server_b);
|
|
|
|
a++;
|
|
|
|
b++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_leave(" = %d [um %d]", addr_matches, uuid_matches);
|
|
|
|
return addr_matches;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Compare root.cell volumes.
|
|
|
|
*/
|
|
|
|
static int afs_compare_cell_roots(struct afs_cell *cell)
|
|
|
|
{
|
|
|
|
struct afs_cell *p;
|
|
|
|
|
|
|
|
_enter("");
|
|
|
|
|
|
|
|
rcu_read_lock();
|
|
|
|
|
|
|
|
hlist_for_each_entry_rcu(p, &cell->net->proc_cells, proc_link) {
|
|
|
|
if (p == cell || p->alias_of)
|
|
|
|
continue;
|
|
|
|
if (!p->root_volume)
|
|
|
|
continue; /* Ignore cells that don't have a root.cell volume. */
|
|
|
|
|
|
|
|
if (afs_compare_volume_slists(cell->root_volume, p->root_volume) != 0)
|
|
|
|
goto is_alias;
|
|
|
|
}
|
|
|
|
|
|
|
|
rcu_read_unlock();
|
|
|
|
_leave(" = 0");
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
is_alias:
|
|
|
|
rcu_read_unlock();
|
2020-10-14 03:51:59 +08:00
|
|
|
cell->alias_of = afs_use_cell(p, afs_cell_trace_use_alias);
|
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: Jeffrey Altman <jaltman@auristor.com>
Signed-off-by: David Howells <dhowells@redhat.com>
2020-04-25 17:26:02 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2020-04-26 17:12:27 +08:00
|
|
|
/*
|
|
|
|
* Query the new cell for a volume from a cell we're already using.
|
|
|
|
*/
|
|
|
|
static int afs_query_for_alias_one(struct afs_cell *cell, struct key *key,
|
|
|
|
struct afs_cell *p)
|
|
|
|
{
|
|
|
|
struct afs_volume *volume, *pvol = NULL;
|
|
|
|
int ret;
|
|
|
|
|
2020-04-30 08:03:49 +08:00
|
|
|
/* Arbitrarily pick a volume from the list. */
|
|
|
|
read_seqlock_excl(&p->volume_lock);
|
|
|
|
if (!RB_EMPTY_ROOT(&p->volumes))
|
|
|
|
pvol = afs_get_volume(rb_entry(p->volumes.rb_node,
|
|
|
|
struct afs_volume, cell_node),
|
2020-04-30 00:02:04 +08:00
|
|
|
afs_volume_trace_get_query_alias);
|
2020-04-30 08:03:49 +08:00
|
|
|
read_sequnlock_excl(&p->volume_lock);
|
2020-04-26 17:12:27 +08:00
|
|
|
if (!pvol)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
_enter("%s:%s", cell->name, pvol->name);
|
|
|
|
|
|
|
|
/* And see if it's in the new cell. */
|
|
|
|
volume = afs_sample_volume(cell, key, pvol->name, pvol->name_len);
|
|
|
|
if (IS_ERR(volume)) {
|
2023-11-08 21:01:11 +08:00
|
|
|
afs_put_volume(pvol, afs_volume_trace_put_query_alias);
|
2020-04-26 17:12:27 +08:00
|
|
|
if (PTR_ERR(volume) != -ENOMEDIUM)
|
|
|
|
return PTR_ERR(volume);
|
|
|
|
/* That volume is not in the new cell, so not an alias */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The new cell has a like-named volume also - compare volume ID,
|
|
|
|
* server and address lists.
|
|
|
|
*/
|
|
|
|
ret = 0;
|
|
|
|
if (pvol->vid == volume->vid) {
|
|
|
|
rcu_read_lock();
|
|
|
|
if (afs_compare_volume_slists(volume, pvol))
|
|
|
|
ret = 1;
|
|
|
|
rcu_read_unlock();
|
|
|
|
}
|
|
|
|
|
2023-11-08 21:01:11 +08:00
|
|
|
afs_put_volume(volume, afs_volume_trace_put_query_alias);
|
|
|
|
afs_put_volume(pvol, afs_volume_trace_put_query_alias);
|
2020-04-26 17:12:27 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Query the new cell for volumes we know exist in cells we're already using.
|
|
|
|
*/
|
|
|
|
static int afs_query_for_alias(struct afs_cell *cell, struct key *key)
|
|
|
|
{
|
|
|
|
struct afs_cell *p;
|
|
|
|
|
|
|
|
_enter("%s", cell->name);
|
|
|
|
|
|
|
|
if (mutex_lock_interruptible(&cell->net->proc_cells_lock) < 0)
|
|
|
|
return -ERESTARTSYS;
|
|
|
|
|
|
|
|
hlist_for_each_entry(p, &cell->net->proc_cells, proc_link) {
|
|
|
|
if (p == cell || p->alias_of)
|
|
|
|
continue;
|
2020-04-30 08:03:49 +08:00
|
|
|
if (RB_EMPTY_ROOT(&p->volumes))
|
2020-04-26 17:12:27 +08:00
|
|
|
continue;
|
|
|
|
if (p->root_volume)
|
|
|
|
continue; /* Ignore cells that have a root.cell volume. */
|
2020-10-14 03:51:59 +08:00
|
|
|
afs_use_cell(p, afs_cell_trace_use_check_alias);
|
2020-04-26 17:12:27 +08:00
|
|
|
mutex_unlock(&cell->net->proc_cells_lock);
|
|
|
|
|
|
|
|
if (afs_query_for_alias_one(cell, key, p) != 0)
|
|
|
|
goto is_alias;
|
|
|
|
|
|
|
|
if (mutex_lock_interruptible(&cell->net->proc_cells_lock) < 0) {
|
2020-10-14 03:51:59 +08:00
|
|
|
afs_unuse_cell(cell->net, p, afs_cell_trace_unuse_check_alias);
|
2020-04-26 17:12:27 +08:00
|
|
|
return -ERESTARTSYS;
|
|
|
|
}
|
|
|
|
|
2020-10-14 03:51:59 +08:00
|
|
|
afs_unuse_cell(cell->net, p, afs_cell_trace_unuse_check_alias);
|
2020-04-26 17:12:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
mutex_unlock(&cell->net->proc_cells_lock);
|
|
|
|
_leave(" = 0");
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
is_alias:
|
|
|
|
cell->alias_of = p; /* Transfer our ref */
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2020-04-27 22:01:09 +08:00
|
|
|
/*
|
|
|
|
* Look up a VLDB record for a volume.
|
|
|
|
*/
|
|
|
|
static char *afs_vl_get_cell_name(struct afs_cell *cell, struct key *key)
|
|
|
|
{
|
|
|
|
struct afs_vl_cursor vc;
|
|
|
|
char *cell_name = ERR_PTR(-EDESTADDRREQ);
|
|
|
|
bool skipped = false, not_skipped = false;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!afs_begin_vlserver_operation(&vc, cell, key))
|
|
|
|
return ERR_PTR(-ERESTARTSYS);
|
|
|
|
|
|
|
|
while (afs_select_vlserver(&vc)) {
|
|
|
|
if (!test_bit(AFS_VLSERVER_FL_IS_YFS, &vc.server->flags)) {
|
2023-10-26 00:53:33 +08:00
|
|
|
vc.call_error = -EOPNOTSUPP;
|
2020-04-27 22:01:09 +08:00
|
|
|
skipped = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
not_skipped = true;
|
|
|
|
cell_name = afs_yfsvl_get_cell_name(&vc);
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = afs_end_vlserver_operation(&vc);
|
|
|
|
if (skipped && !not_skipped)
|
|
|
|
ret = -EOPNOTSUPP;
|
|
|
|
return ret < 0 ? ERR_PTR(ret) : cell_name;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int yfs_check_canonical_cell_name(struct afs_cell *cell, struct key *key)
|
|
|
|
{
|
|
|
|
struct afs_cell *master;
|
|
|
|
char *cell_name;
|
|
|
|
|
|
|
|
cell_name = afs_vl_get_cell_name(cell, key);
|
|
|
|
if (IS_ERR(cell_name))
|
|
|
|
return PTR_ERR(cell_name);
|
|
|
|
|
|
|
|
if (strcmp(cell_name, cell->name) == 0) {
|
|
|
|
kfree(cell_name);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
master = afs_lookup_cell(cell->net, cell_name, strlen(cell_name),
|
|
|
|
NULL, false);
|
|
|
|
kfree(cell_name);
|
|
|
|
if (IS_ERR(master))
|
|
|
|
return PTR_ERR(master);
|
|
|
|
|
|
|
|
cell->alias_of = master; /* Transfer our ref */
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
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: Jeffrey Altman <jaltman@auristor.com>
Signed-off-by: David Howells <dhowells@redhat.com>
2020-04-25 17:26:02 +08:00
|
|
|
static int afs_do_cell_detect_alias(struct afs_cell *cell, struct key *key)
|
|
|
|
{
|
|
|
|
struct afs_volume *root_volume;
|
2020-04-27 22:01:09 +08:00
|
|
|
int ret;
|
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: Jeffrey Altman <jaltman@auristor.com>
Signed-off-by: David Howells <dhowells@redhat.com>
2020-04-25 17:26:02 +08:00
|
|
|
|
|
|
|
_enter("%s", cell->name);
|
|
|
|
|
2020-04-27 22:01:09 +08:00
|
|
|
ret = yfs_check_canonical_cell_name(cell, key);
|
|
|
|
if (ret != -EOPNOTSUPP)
|
|
|
|
return ret;
|
|
|
|
|
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: Jeffrey Altman <jaltman@auristor.com>
Signed-off-by: David Howells <dhowells@redhat.com>
2020-04-25 17:26:02 +08:00
|
|
|
/* Try and get the root.cell volume for comparison with other cells */
|
|
|
|
root_volume = afs_sample_volume(cell, key, "root.cell", 9);
|
|
|
|
if (!IS_ERR(root_volume)) {
|
|
|
|
cell->root_volume = root_volume;
|
|
|
|
return afs_compare_cell_roots(cell);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (PTR_ERR(root_volume) != -ENOMEDIUM)
|
|
|
|
return PTR_ERR(root_volume);
|
|
|
|
|
|
|
|
/* Okay, this cell doesn't have an root.cell volume. We need to
|
|
|
|
* locate some other random volume and use that to check.
|
|
|
|
*/
|
2020-04-26 17:12:27 +08:00
|
|
|
return afs_query_for_alias(cell, key);
|
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: Jeffrey Altman <jaltman@auristor.com>
Signed-off-by: David Howells <dhowells@redhat.com>
2020-04-25 17:26:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check to see if a new cell is an alias of a cell we already have. At this
|
|
|
|
* point we have the cell's volume server list.
|
|
|
|
*
|
|
|
|
* Returns 0 if we didn't detect an alias, 1 if we found an alias and an error
|
|
|
|
* if we had problems gathering the data required. In the case the we did
|
|
|
|
* detect an alias, cell->alias_of is set to point to the assumed master.
|
|
|
|
*/
|
|
|
|
int afs_cell_detect_alias(struct afs_cell *cell, struct key *key)
|
|
|
|
{
|
|
|
|
struct afs_net *net = cell->net;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (mutex_lock_interruptible(&net->cells_alias_lock) < 0)
|
|
|
|
return -ERESTARTSYS;
|
|
|
|
|
|
|
|
if (test_bit(AFS_CELL_FL_CHECK_ALIAS, &cell->flags)) {
|
|
|
|
ret = afs_do_cell_detect_alias(cell, key);
|
|
|
|
if (ret >= 0)
|
|
|
|
clear_bit_unlock(AFS_CELL_FL_CHECK_ALIAS, &cell->flags);
|
|
|
|
} else {
|
|
|
|
ret = cell->alias_of ? 1 : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
mutex_unlock(&net->cells_alias_lock);
|
|
|
|
|
|
|
|
if (ret == 1)
|
|
|
|
pr_notice("kAFS: Cell %s is an alias of %s\n",
|
|
|
|
cell->name, cell->alias_of->name);
|
|
|
|
return ret;
|
|
|
|
}
|