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->vlserver; 37 unsigned int server_index = call->server_index; 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 struct afs_call *call; 145 bool in_progress = false; 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 call = afs_vl_get_capabilities(net, &ac, key, server, 160 server_index); 161 if (!IS_ERR(call)) { 162 afs_put_call(call); 163 in_progress = true; 164 } else { 165 afs_prioritise_error(_e, PTR_ERR(call), ac.abort_code); 166 } 167 } 168 169 if (!in_progress) 170 afs_vl_probe_done(server); 171 return in_progress; 172 } 173 174 /* 175 * Send off probes to all unprobed servers. 176 */ 177 int afs_send_vl_probes(struct afs_net *net, struct key *key, 178 struct afs_vlserver_list *vllist) 179 { 180 struct afs_vlserver *server; 181 struct afs_error e; 182 bool in_progress = false; 183 int i; 184 185 e.error = 0; 186 e.responded = false; 187 for (i = 0; i < vllist->nr_servers; i++) { 188 server = vllist->servers[i].server; 189 if (test_bit(AFS_VLSERVER_FL_PROBED, &server->flags)) 190 continue; 191 192 if (!test_and_set_bit_lock(AFS_VLSERVER_FL_PROBING, &server->flags) && 193 afs_do_probe_vlserver(net, server, key, i, &e)) 194 in_progress = true; 195 } 196 197 return in_progress ? 0 : e.error; 198 } 199 200 /* 201 * Wait for the first as-yet untried server to respond. 202 */ 203 int afs_wait_for_vl_probes(struct afs_vlserver_list *vllist, 204 unsigned long untried) 205 { 206 struct wait_queue_entry *waits; 207 struct afs_vlserver *server; 208 unsigned int rtt = UINT_MAX; 209 bool have_responders = false; 210 int pref = -1, i; 211 212 _enter("%u,%lx", vllist->nr_servers, untried); 213 214 /* Only wait for servers that have a probe outstanding. */ 215 for (i = 0; i < vllist->nr_servers; i++) { 216 if (test_bit(i, &untried)) { 217 server = vllist->servers[i].server; 218 if (!test_bit(AFS_VLSERVER_FL_PROBING, &server->flags)) 219 __clear_bit(i, &untried); 220 if (server->probe.responded) 221 have_responders = true; 222 } 223 } 224 if (have_responders || !untried) 225 return 0; 226 227 waits = kmalloc(array_size(vllist->nr_servers, sizeof(*waits)), GFP_KERNEL); 228 if (!waits) 229 return -ENOMEM; 230 231 for (i = 0; i < vllist->nr_servers; i++) { 232 if (test_bit(i, &untried)) { 233 server = vllist->servers[i].server; 234 init_waitqueue_entry(&waits[i], current); 235 add_wait_queue(&server->probe_wq, &waits[i]); 236 } 237 } 238 239 for (;;) { 240 bool still_probing = false; 241 242 set_current_state(TASK_INTERRUPTIBLE); 243 for (i = 0; i < vllist->nr_servers; i++) { 244 if (test_bit(i, &untried)) { 245 server = vllist->servers[i].server; 246 if (server->probe.responded) 247 goto stop; 248 if (test_bit(AFS_VLSERVER_FL_PROBING, &server->flags)) 249 still_probing = true; 250 } 251 } 252 253 if (!still_probing || signal_pending(current)) 254 goto stop; 255 schedule(); 256 } 257 258 stop: 259 set_current_state(TASK_RUNNING); 260 261 for (i = 0; i < vllist->nr_servers; i++) { 262 if (test_bit(i, &untried)) { 263 server = vllist->servers[i].server; 264 if (server->probe.responded && 265 server->probe.rtt < rtt) { 266 pref = i; 267 rtt = server->probe.rtt; 268 } 269 270 remove_wait_queue(&server->probe_wq, &waits[i]); 271 } 272 } 273 274 kfree(waits); 275 276 if (pref == -1 && signal_pending(current)) 277 return -ERESTARTSYS; 278 279 if (pref >= 0) 280 vllist->preferred = pref; 281 282 _leave(" = 0 [%u]", pref); 283 return 0; 284 } 285