1 /* AFS vlserver probing 2 * 3 * Copyright (C) 2018 Red Hat, Inc. All Rights Reserved. 4 * Written by David Howells (dhowells@redhat.com) 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public Licence 8 * as published by the Free Software Foundation; either version 9 * 2 of the Licence, or (at your option) any later version. 10 */ 11 12 #include <linux/sched.h> 13 #include <linux/slab.h> 14 #include "afs_fs.h" 15 #include "internal.h" 16 #include "protocol_yfs.h" 17 18 static bool afs_vl_probe_done(struct afs_vlserver *server) 19 { 20 if (!atomic_dec_and_test(&server->probe_outstanding)) 21 return false; 22 23 wake_up_var(&server->probe_outstanding); 24 clear_bit_unlock(AFS_VLSERVER_FL_PROBING, &server->flags); 25 wake_up_bit(&server->flags, AFS_VLSERVER_FL_PROBING); 26 return true; 27 } 28 29 /* 30 * Process the result of probing a vlserver. This is called after successful 31 * or failed delivery of an VL.GetCapabilities operation. 32 */ 33 void afs_vlserver_probe_result(struct afs_call *call) 34 { 35 struct afs_addr_list *alist = call->alist; 36 struct afs_vlserver *server = call->reply[0]; 37 unsigned int server_index = (long)call->reply[1]; 38 unsigned int index = call->addr_ix; 39 unsigned int rtt = UINT_MAX; 40 bool have_result = false; 41 u64 _rtt; 42 int ret = call->error; 43 44 _enter("%s,%u,%u,%d,%d", server->name, server_index, index, ret, call->abort_code); 45 46 spin_lock(&server->probe_lock); 47 48 switch (ret) { 49 case 0: 50 server->probe.error = 0; 51 goto responded; 52 case -ECONNABORTED: 53 if (!server->probe.responded) { 54 server->probe.abort_code = call->abort_code; 55 server->probe.error = ret; 56 } 57 goto responded; 58 case -ENOMEM: 59 case -ENONET: 60 server->probe.local_failure = true; 61 afs_io_error(call, afs_io_error_vl_probe_fail); 62 goto out; 63 case -ECONNRESET: /* Responded, but call expired. */ 64 case -ERFKILL: 65 case -EADDRNOTAVAIL: 66 case -ENETUNREACH: 67 case -EHOSTUNREACH: 68 case -EHOSTDOWN: 69 case -ECONNREFUSED: 70 case -ETIMEDOUT: 71 case -ETIME: 72 default: 73 clear_bit(index, &alist->responded); 74 set_bit(index, &alist->failed); 75 if (!server->probe.responded && 76 (server->probe.error == 0 || 77 server->probe.error == -ETIMEDOUT || 78 server->probe.error == -ETIME)) 79 server->probe.error = ret; 80 afs_io_error(call, afs_io_error_vl_probe_fail); 81 goto out; 82 } 83 84 responded: 85 set_bit(index, &alist->responded); 86 clear_bit(index, &alist->failed); 87 88 if (call->service_id == YFS_VL_SERVICE) { 89 server->probe.is_yfs = true; 90 set_bit(AFS_VLSERVER_FL_IS_YFS, &server->flags); 91 alist->addrs[index].srx_service = call->service_id; 92 } else { 93 server->probe.not_yfs = true; 94 if (!server->probe.is_yfs) { 95 clear_bit(AFS_VLSERVER_FL_IS_YFS, &server->flags); 96 alist->addrs[index].srx_service = call->service_id; 97 } 98 } 99 100 /* Get the RTT and scale it to fit into a 32-bit value that represents 101 * over a minute of time so that we can access it with one instruction 102 * on a 32-bit system. 103 */ 104 _rtt = rxrpc_kernel_get_rtt(call->net->socket, call->rxcall); 105 _rtt /= 64; 106 rtt = (_rtt > UINT_MAX) ? UINT_MAX : _rtt; 107 if (rtt < server->probe.rtt) { 108 server->probe.rtt = rtt; 109 alist->preferred = index; 110 have_result = true; 111 } 112 113 smp_wmb(); /* Set rtt before responded. */ 114 server->probe.responded = true; 115 set_bit(AFS_VLSERVER_FL_PROBED, &server->flags); 116 out: 117 spin_unlock(&server->probe_lock); 118 119 _debug("probe [%u][%u] %pISpc rtt=%u ret=%d", 120 server_index, index, &alist->addrs[index].transport, 121 (unsigned int)rtt, ret); 122 123 have_result |= afs_vl_probe_done(server); 124 if (have_result) { 125 server->probe.have_result = true; 126 wake_up_var(&server->probe.have_result); 127 wake_up_all(&server->probe_wq); 128 } 129 } 130 131 /* 132 * Probe all of a vlserver's addresses to find out the best route and to 133 * query its capabilities. 134 */ 135 static bool afs_do_probe_vlserver(struct afs_net *net, 136 struct afs_vlserver *server, 137 struct key *key, 138 unsigned int server_index, 139 struct afs_error *_e) 140 { 141 struct afs_addr_cursor ac = { 142 .index = 0, 143 }; 144 bool in_progress = false; 145 int err; 146 147 _enter("%s", server->name); 148 149 read_lock(&server->lock); 150 ac.alist = rcu_dereference_protected(server->addresses, 151 lockdep_is_held(&server->lock)); 152 read_unlock(&server->lock); 153 154 atomic_set(&server->probe_outstanding, ac.alist->nr_addrs); 155 memset(&server->probe, 0, sizeof(server->probe)); 156 server->probe.rtt = UINT_MAX; 157 158 for (ac.index = 0; ac.index < ac.alist->nr_addrs; ac.index++) { 159 err = afs_vl_get_capabilities(net, &ac, key, server, 160 server_index, true); 161 if (err == -EINPROGRESS) 162 in_progress = true; 163 else 164 afs_prioritise_error(_e, err, ac.abort_code); 165 } 166 167 if (!in_progress) 168 afs_vl_probe_done(server); 169 return in_progress; 170 } 171 172 /* 173 * Send off probes to all unprobed servers. 174 */ 175 int afs_send_vl_probes(struct afs_net *net, struct key *key, 176 struct afs_vlserver_list *vllist) 177 { 178 struct afs_vlserver *server; 179 struct afs_error e; 180 bool in_progress = false; 181 int i; 182 183 e.error = 0; 184 e.responded = false; 185 for (i = 0; i < vllist->nr_servers; i++) { 186 server = vllist->servers[i].server; 187 if (test_bit(AFS_VLSERVER_FL_PROBED, &server->flags)) 188 continue; 189 190 if (!test_and_set_bit_lock(AFS_VLSERVER_FL_PROBING, &server->flags) && 191 afs_do_probe_vlserver(net, server, key, i, &e)) 192 in_progress = true; 193 } 194 195 return in_progress ? 0 : e.error; 196 } 197 198 /* 199 * Wait for the first as-yet untried server to respond. 200 */ 201 int afs_wait_for_vl_probes(struct afs_vlserver_list *vllist, 202 unsigned long untried) 203 { 204 struct wait_queue_entry *waits; 205 struct afs_vlserver *server; 206 unsigned int rtt = UINT_MAX; 207 bool have_responders = false; 208 int pref = -1, i; 209 210 _enter("%u,%lx", vllist->nr_servers, untried); 211 212 /* Only wait for servers that have a probe outstanding. */ 213 for (i = 0; i < vllist->nr_servers; i++) { 214 if (test_bit(i, &untried)) { 215 server = vllist->servers[i].server; 216 if (!test_bit(AFS_VLSERVER_FL_PROBING, &server->flags)) 217 __clear_bit(i, &untried); 218 if (server->probe.responded) 219 have_responders = true; 220 } 221 } 222 if (have_responders || !untried) 223 return 0; 224 225 waits = kmalloc(array_size(vllist->nr_servers, sizeof(*waits)), GFP_KERNEL); 226 if (!waits) 227 return -ENOMEM; 228 229 for (i = 0; i < vllist->nr_servers; i++) { 230 if (test_bit(i, &untried)) { 231 server = vllist->servers[i].server; 232 init_waitqueue_entry(&waits[i], current); 233 add_wait_queue(&server->probe_wq, &waits[i]); 234 } 235 } 236 237 for (;;) { 238 bool still_probing = false; 239 240 set_current_state(TASK_INTERRUPTIBLE); 241 for (i = 0; i < vllist->nr_servers; i++) { 242 if (test_bit(i, &untried)) { 243 server = vllist->servers[i].server; 244 if (server->probe.responded) 245 goto stop; 246 if (test_bit(AFS_VLSERVER_FL_PROBING, &server->flags)) 247 still_probing = true; 248 } 249 } 250 251 if (!still_probing || signal_pending(current)) 252 goto stop; 253 schedule(); 254 } 255 256 stop: 257 set_current_state(TASK_RUNNING); 258 259 for (i = 0; i < vllist->nr_servers; i++) { 260 if (test_bit(i, &untried)) { 261 server = vllist->servers[i].server; 262 if (server->probe.responded && 263 server->probe.rtt < rtt) { 264 pref = i; 265 rtt = server->probe.rtt; 266 } 267 268 remove_wait_queue(&server->probe_wq, &waits[i]); 269 } 270 } 271 272 kfree(waits); 273 274 if (pref == -1 && signal_pending(current)) 275 return -ERESTARTSYS; 276 277 if (pref >= 0) 278 vllist->preferred = pref; 279 280 _leave(" = 0 [%u]", pref); 281 return 0; 282 } 283