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 bool in_progress = false; 145 int err; 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 err = afs_fs_get_capabilities(net, server, &ac, key, server_index, 160 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_fs_probe_done(server); 169 return in_progress; 170 } 171 172 /* 173 * Send off probes to all unprobed servers. 174 */ 175 int afs_probe_fileservers(struct afs_net *net, struct key *key, 176 struct afs_server_list *list) 177 { 178 struct afs_server *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 < list->nr_servers; i++) { 186 server = list->servers[i].server; 187 if (test_bit(AFS_SERVER_FL_PROBED, &server->flags)) 188 continue; 189 190 if (!test_and_set_bit_lock(AFS_SERVER_FL_PROBING, &server->flags) && 191 afs_do_probe_fileserver(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 fileserver to respond. 200 */ 201 int afs_wait_for_fs_probes(struct afs_server_list *slist, unsigned long untried) 202 { 203 struct wait_queue_entry *waits; 204 struct afs_server *server; 205 unsigned int rtt = UINT_MAX; 206 bool have_responders = false; 207 int pref = -1, i; 208 209 _enter("%u,%lx", slist->nr_servers, untried); 210 211 /* Only wait for servers that have a probe outstanding. */ 212 for (i = 0; i < slist->nr_servers; i++) { 213 if (test_bit(i, &untried)) { 214 server = slist->servers[i].server; 215 if (!test_bit(AFS_SERVER_FL_PROBING, &server->flags)) 216 __clear_bit(i, &untried); 217 if (server->probe.responded) 218 have_responders = true; 219 } 220 } 221 if (have_responders || !untried) 222 return 0; 223 224 waits = kmalloc(array_size(slist->nr_servers, sizeof(*waits)), GFP_KERNEL); 225 if (!waits) 226 return -ENOMEM; 227 228 for (i = 0; i < slist->nr_servers; i++) { 229 if (test_bit(i, &untried)) { 230 server = slist->servers[i].server; 231 init_waitqueue_entry(&waits[i], current); 232 add_wait_queue(&server->probe_wq, &waits[i]); 233 } 234 } 235 236 for (;;) { 237 bool still_probing = false; 238 239 set_current_state(TASK_INTERRUPTIBLE); 240 for (i = 0; i < slist->nr_servers; i++) { 241 if (test_bit(i, &untried)) { 242 server = slist->servers[i].server; 243 if (server->probe.responded) 244 goto stop; 245 if (test_bit(AFS_SERVER_FL_PROBING, &server->flags)) 246 still_probing = true; 247 } 248 } 249 250 if (!still_probing || signal_pending(current)) 251 goto stop; 252 schedule(); 253 } 254 255 stop: 256 set_current_state(TASK_RUNNING); 257 258 for (i = 0; i < slist->nr_servers; i++) { 259 if (test_bit(i, &untried)) { 260 server = slist->servers[i].server; 261 if (server->probe.responded && 262 server->probe.rtt < rtt) { 263 pref = i; 264 rtt = server->probe.rtt; 265 } 266 267 remove_wait_queue(&server->probe_wq, &waits[i]); 268 } 269 } 270 271 kfree(waits); 272 273 if (pref == -1 && signal_pending(current)) 274 return -ERESTARTSYS; 275 276 if (pref >= 0) 277 slist->preferred = pref; 278 return 0; 279 } 280