diff options
author | David Howells <dhowells@redhat.com> | 2020-05-27 17:51:30 +0300 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2020-06-04 17:37:57 +0300 |
commit | 3c4c4075fc61f5c37a0112b1dc8398025dc3e26a (patch) | |
tree | e78930a53e08984dc1b0f3519233baabd8a74c81 /fs/afs/callback.c | |
parent | 20325960f8750165964a6891a733e4cc15d19076 (diff) | |
download | linux-3c4c4075fc61f5c37a0112b1dc8398025dc3e26a.tar.xz |
afs: Fix the by-UUID server tree to allow servers with the same UUID
Whilst it shouldn't happen, it is possible for multiple fileservers to
share a UUID, particularly if an entire cell has been duplicated, UUIDs and
all. In such a case, it's not necessarily possible to map the effect of
the CB.InitCallBackState3 incoming RPC to a specific server unambiguously
by UUID and thus to a specific cell.
Indeed, there's a problem whereby multiple server records may need to
occupy the same spot in the rb_tree rooted in the afs_net struct.
Fix this by allowing servers to form a list, with the head of the list in
the tree. When the front entry in the list is removed, the second in the
list just replaces it. afs_init_callback_state() then just goes down the
line, poking each server in the list.
This means that some servers will be unnecessarily poked, unfortunately.
An alternative would be to route by call parameters.
Reported-by: Jeffrey Altman <jaltman@auristor.com>
Signed-off-by: David Howells <dhowells@redhat.com>
Fixes: d2ddc776a458 ("afs: Overhaul volume and server record caching and fileserver rotation")
Diffstat (limited to 'fs/afs/callback.c')
-rw-r--r-- | fs/afs/callback.c | 10 |
1 files changed, 8 insertions, 2 deletions
diff --git a/fs/afs/callback.c b/fs/afs/callback.c index b4cb9bb63f0a..7d9b23d981bf 100644 --- a/fs/afs/callback.c +++ b/fs/afs/callback.c @@ -21,11 +21,17 @@ #include "internal.h" /* - * allow the fileserver to request callback state (re-)initialisation + * Allow the fileserver to request callback state (re-)initialisation. + * Unfortunately, UUIDs are not guaranteed unique. */ void afs_init_callback_state(struct afs_server *server) { - server->cb_s_break++; + rcu_read_lock(); + do { + server->cb_s_break++; + server = rcu_dereference(server->uuid_next); + } while (0); + rcu_read_unlock(); } /* |