Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

afs: Don't use VL probe running state to make decisions outside probe code

Don't use the running state for VL server probes to make decisions about
which server to use as the state is cleared at the start of a probe and
intermediate values might also be misleading.

Instead, add a separate 'latest known' rtt in the afs_vlserver struct and a
flag to indicate if the server is known to be responding and update these
as and when we know what to change them to.

Fixes: 3bf0fb6f33dd ("afs: Probe multiple fileservers simultaneously")
Signed-off-by: David Howells <dhowells@redhat.com>

+47 -21
+3 -1
fs/afs/internal.h
··· 401 401 #define AFS_VLSERVER_FL_PROBED 0 /* The VL server has been probed */ 402 402 #define AFS_VLSERVER_FL_PROBING 1 /* VL server is being probed */ 403 403 #define AFS_VLSERVER_FL_IS_YFS 2 /* Server is YFS not AFS */ 404 + #define AFS_VLSERVER_FL_RESPONDING 3 /* VL server is responding */ 404 405 rwlock_t lock; /* Lock on addresses */ 405 406 atomic_t usage; 407 + unsigned int rtt; /* Server's current RTT in uS */ 406 408 407 409 /* Probe state */ 408 410 wait_queue_head_t probe_wq; 409 411 atomic_t probe_outstanding; 410 412 spinlock_t probe_lock; 411 413 struct { 412 - unsigned int rtt; /* RTT as ktime/64 */ 414 + unsigned int rtt; /* RTT in uS */ 413 415 u32 abort_code; 414 416 short error; 415 417 unsigned short flags;
+1 -1
fs/afs/proc.c
··· 310 310 alist->preferred == i ? '>' : '-', 311 311 &alist->addrs[i].transport); 312 312 } 313 - seq_printf(m, " info: fl=%lx rtt=%d\n", vlserver->flags, vlserver->probe.rtt); 313 + seq_printf(m, " info: fl=%lx rtt=%d\n", vlserver->flags, vlserver->rtt); 314 314 seq_printf(m, " probe: fl=%x e=%d ac=%d out=%d\n", 315 315 vlserver->probe.flags, vlserver->probe.error, 316 316 vlserver->probe.abort_code,
+1
fs/afs/vl_list.c
··· 21 21 rwlock_init(&vlserver->lock); 22 22 init_waitqueue_head(&vlserver->probe_wq); 23 23 spin_lock_init(&vlserver->probe_lock); 24 + vlserver->rtt = UINT_MAX; 24 25 vlserver->name_len = name_len; 25 26 vlserver->port = port; 26 27 memcpy(vlserver->name, name, name_len);
+41 -18
fs/afs/vl_probe.c
··· 11 11 #include "internal.h" 12 12 #include "protocol_yfs.h" 13 13 14 - static bool afs_vl_probe_done(struct afs_vlserver *server) 15 - { 16 - if (!atomic_dec_and_test(&server->probe_outstanding)) 17 - return false; 18 14 19 - wake_up_var(&server->probe_outstanding); 15 + /* 16 + * Handle the completion of a set of probes. 17 + */ 18 + static void afs_finished_vl_probe(struct afs_vlserver *server) 19 + { 20 + if (!(server->probe.flags & AFS_VLSERVER_PROBE_RESPONDED)) { 21 + server->rtt = UINT_MAX; 22 + clear_bit(AFS_VLSERVER_FL_RESPONDING, &server->flags); 23 + } 24 + 20 25 clear_bit_unlock(AFS_VLSERVER_FL_PROBING, &server->flags); 21 26 wake_up_bit(&server->flags, AFS_VLSERVER_FL_PROBING); 22 - return true; 27 + } 28 + 29 + /* 30 + * Handle the completion of a probe RPC call. 31 + */ 32 + static void afs_done_one_vl_probe(struct afs_vlserver *server, bool wake_up) 33 + { 34 + if (atomic_dec_and_test(&server->probe_outstanding)) { 35 + afs_finished_vl_probe(server); 36 + wake_up = true; 37 + } 38 + 39 + if (wake_up) 40 + wake_up_all(&server->probe_wq); 23 41 } 24 42 25 43 /* ··· 70 52 goto responded; 71 53 case -ENOMEM: 72 54 case -ENONET: 55 + case -EKEYEXPIRED: 56 + case -EKEYREVOKED: 57 + case -EKEYREJECTED: 73 58 server->probe.flags |= AFS_VLSERVER_PROBE_LOCAL_FAILURE; 74 - afs_io_error(call, afs_io_error_vl_probe_fail); 59 + if (server->probe.error == 0) 60 + server->probe.error = ret; 61 + trace_afs_io_error(call->debug_id, ret, afs_io_error_vl_probe_fail); 75 62 goto out; 76 63 case -ECONNRESET: /* Responded, but call expired. */ 77 64 case -ERFKILL: ··· 95 72 server->probe.error == -ETIMEDOUT || 96 73 server->probe.error == -ETIME)) 97 74 server->probe.error = ret; 98 - afs_io_error(call, afs_io_error_vl_probe_fail); 75 + trace_afs_io_error(call->debug_id, ret, afs_io_error_vl_probe_fail); 99 76 goto out; 100 77 } 101 78 ··· 118 95 if (rxrpc_kernel_get_srtt(call->net->socket, call->rxcall, &rtt_us) && 119 96 rtt_us < server->probe.rtt) { 120 97 server->probe.rtt = rtt_us; 98 + server->rtt = rtt_us; 121 99 alist->preferred = index; 122 - have_result = true; 123 100 } 124 101 125 102 smp_wmb(); /* Set rtt before responded. */ 126 103 server->probe.flags |= AFS_VLSERVER_PROBE_RESPONDED; 127 104 set_bit(AFS_VLSERVER_FL_PROBED, &server->flags); 105 + set_bit(AFS_VLSERVER_FL_RESPONDING, &server->flags); 106 + have_result = true; 128 107 out: 129 108 spin_unlock(&server->probe_lock); 130 109 131 110 _debug("probe [%u][%u] %pISpc rtt=%u ret=%d", 132 111 server_index, index, &alist->addrs[index].transport, rtt_us, ret); 133 112 134 - have_result |= afs_vl_probe_done(server); 135 - if (have_result) 136 - wake_up_all(&server->probe_wq); 113 + afs_done_one_vl_probe(server, have_result); 137 114 } 138 115 139 116 /* ··· 171 148 in_progress = true; 172 149 } else { 173 150 afs_prioritise_error(_e, PTR_ERR(call), ac.abort_code); 151 + afs_done_one_vl_probe(server, false); 174 152 } 175 153 } 176 154 177 - if (!in_progress) 178 - afs_vl_probe_done(server); 179 155 return in_progress; 180 156 } 181 157 ··· 212 190 { 213 191 struct wait_queue_entry *waits; 214 192 struct afs_vlserver *server; 215 - unsigned int rtt = UINT_MAX; 193 + unsigned int rtt = UINT_MAX, rtt_s; 216 194 bool have_responders = false; 217 195 int pref = -1, i; 218 196 ··· 268 246 for (i = 0; i < vllist->nr_servers; i++) { 269 247 if (test_bit(i, &untried)) { 270 248 server = vllist->servers[i].server; 271 - if ((server->probe.flags & AFS_VLSERVER_PROBE_RESPONDED) && 272 - server->probe.rtt < rtt) { 249 + rtt_s = READ_ONCE(server->rtt); 250 + if (test_bit(AFS_VLSERVER_FL_RESPONDING, &server->flags) && 251 + rtt_s < rtt) { 273 252 pref = i; 274 - rtt = server->probe.rtt; 253 + rtt = rtt_s; 275 254 } 276 255 277 256 remove_wait_queue(&server->probe_wq, &waits[i]);
+1 -1
fs/afs/vl_rotate.c
··· 193 193 struct afs_vlserver *s = vc->server_list->servers[i].server; 194 194 195 195 if (!test_bit(i, &vc->untried) || 196 - !(s->probe.flags & AFS_VLSERVER_PROBE_RESPONDED)) 196 + !test_bit(AFS_VLSERVER_FL_RESPONDING, &s->flags)) 197 197 continue; 198 198 if (s->probe.rtt < rtt) { 199 199 vc->index = i;