summaryrefslogtreecommitdiff
path: root/fs/afs/rotate.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2020-04-25 10:26:02 +0100
committerDavid Howells <dhowells@redhat.com>2020-06-04 15:37:57 +0100
commit8a070a964877c71139cba46202f6f263c2b9419d (patch)
tree3076bf377e85c77a1fcf20bc5436ccbadeb4987b /fs/afs/rotate.c
parentc3e9f888263bb4df11cbd623ceced02081cb2f9f (diff)
downloadlwn-8a070a964877c71139cba46202f6f263c2b9419d.tar.gz
lwn-8a070a964877c71139cba46202f6f263c2b9419d.zip
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>
Diffstat (limited to 'fs/afs/rotate.c')
-rw-r--r--fs/afs/rotate.c8
1 files changed, 5 insertions, 3 deletions
diff --git a/fs/afs/rotate.c b/fs/afs/rotate.c
index 8c8dc2397c5d..d67b8c7eb3b9 100644
--- a/fs/afs/rotate.c
+++ b/fs/afs/rotate.c
@@ -25,7 +25,9 @@ static bool afs_start_fs_iteration(struct afs_operation *op,
int i;
read_lock(&op->volume->servers_lock);
- op->server_list = afs_get_serverlist(op->volume->servers);
+ op->server_list = afs_get_serverlist(
+ rcu_dereference_protected(op->volume->servers,
+ lockdep_is_held(&op->volume->servers_lock)));
read_unlock(&op->volume->servers_lock);
op->untried = (1UL << op->server_list->nr_servers) - 1;
@@ -173,7 +175,7 @@ bool afs_select_fileserver(struct afs_operation *op)
/* If the server list didn't change, then assume that
* it's the fileserver having trouble.
*/
- if (op->volume->servers == op->server_list) {
+ if (rcu_access_pointer(op->volume->servers) == op->server_list) {
op->error = -EREMOTEIO;
goto next_server;
}
@@ -263,7 +265,7 @@ bool afs_select_fileserver(struct afs_operation *op)
*
* TODO: Retry a few times with sleeps.
*/
- if (op->volume->servers == op->server_list) {
+ if (rcu_access_pointer(op->volume->servers) == op->server_list) {
op->error = -ENOMEDIUM;
goto failed;
}