1 /* AFS fileserver 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_fs_probe_done(struct afs_server *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_SERVER_FL_PROBING, &server->flags); 25 wake_up_bit(&server->flags, AFS_SERVER_FL_PROBING); 26 return true; 27 } 28 29 /* 30 * Process the result of probing a fileserver. This is called after successful 31 * or failed delivery of an FS.GetCapabilities operation. 32 */ 33 void afs_fileserver_probe_result(struct afs_call *call) 34 { 35 struct afs_addr_list *alist = call->alist; 36 struct afs_server *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("%pU,%u", &server->uuid, index); 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_fs_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_fs_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_FS_SERVICE) { 89 server->probe.is_yfs = true; 90 set_bit(AFS_SERVER_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_SERVER_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_SERVER_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_fs_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 fileserver's addresses to find out the best route and to 133 * query its capabilities. 134 */ 135 static int afs_do_probe_fileserver(struct afs_net *net, 136 struct afs_server *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("%pU", &server->uuid); 148 149 read_lock(&server->fs_lock); 150 ac.alist = rcu_dereference_protected(server->addresses, 151 lockdep_is_held(&server->fs_lock)); 152 read_unlock(&server->fs_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_fs_get_capabilities(net, server, &ac, key, server_index); 160 if (!IS_ERR(call)) { 161 afs_put_call(call); 162 in_progress = true; 163 } else { 164 afs_prioritise_error(_e, PTR_ERR(call), ac.abort_code); 165 } 166 } 167 168 if (!in_progress) 169 afs_fs_probe_done(server); 170 return in_progress; 171 } 172 173 /* 174 * Send off probes to all unprobed servers. 175 */ 176 int afs_probe_fileservers(struct afs_net *net, struct key *key, 177 struct afs_server_list *list) 178 { 179 struct afs_server *server; 180 struct afs_error e; 181 bool in_progress = false; 182 int i; 183 184 e.error = 0; 185 e.responded = false; 186 for (i = 0; i < list->nr_servers; i++) { 187 server = list->servers[i].server; 188 if (test_bit(AFS_SERVER_FL_PROBED, &server->flags)) 189 continue; 190 191 if (!test_and_set_bit_lock(AFS_SERVER_FL_PROBING, &server->flags) && 192 afs_do_probe_fileserver(net, server, key, i, &e)) 193 in_progress = true; 194 } 195 196 return in_progress ? 0 : e.error; 197 } 198 199 /* 200 * Wait for the first as-yet untried fileserver to respond. 201 */ 202 int afs_wait_for_fs_probes(struct afs_server_list *slist, unsigned long untried) 203 { 204 struct wait_queue_entry *waits; 205 struct afs_server *server; 206 unsigned int rtt = UINT_MAX; 207 bool have_responders = false; 208 int pref = -1, i; 209 210 _enter("%u,%lx", slist->nr_servers, untried); 211 212 /* Only wait for servers that have a probe outstanding. */ 213 for (i = 0; i < slist->nr_servers; i++) { 214 if (test_bit(i, &untried)) { 215 server = slist->servers[i].server; 216 if (!test_bit(AFS_SERVER_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(slist->nr_servers, sizeof(*waits)), GFP_KERNEL); 226 if (!waits) 227 return -ENOMEM; 228 229 for (i = 0; i < slist->nr_servers; i++) { 230 if (test_bit(i, &untried)) { 231 server = slist->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 < slist->nr_servers; i++) { 242 if (test_bit(i, &untried)) { 243 server = slist->servers[i].server; 244 if (server->probe.responded) 245 goto stop; 246 if (test_bit(AFS_SERVER_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 < slist->nr_servers; i++) { 260 if (test_bit(i, &untried)) { 261 server = slist->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 slist->preferred = pref; 279 return 0; 280 } 281