1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* AFS vlserver probing |
3 | * |
4 | * Copyright (C) 2018 Red Hat, Inc. All Rights Reserved. |
5 | * Written by David Howells (dhowells@redhat.com) |
6 | */ |
7 | |
8 | #include <linux/sched.h> |
9 | #include <linux/slab.h> |
10 | #include "afs_fs.h" |
11 | #include "internal.h" |
12 | #include "protocol_yfs.h" |
13 | |
14 | |
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, addr: &server->flags); |
23 | } |
24 | |
25 | clear_bit_unlock(AFS_VLSERVER_FL_PROBING, addr: &server->flags); |
26 | wake_up_bit(word: &server->flags, AFS_VLSERVER_FL_PROBING); |
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(v: &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); |
41 | } |
42 | |
43 | /* |
44 | * Process the result of probing a vlserver. This is called after successful |
45 | * or failed delivery of an VL.GetCapabilities operation. |
46 | */ |
47 | void afs_vlserver_probe_result(struct afs_call *call) |
48 | { |
49 | struct afs_addr_list *alist = call->alist; |
50 | struct afs_vlserver *server = call->vlserver; |
51 | unsigned int server_index = call->server_index; |
52 | unsigned int rtt_us = 0; |
53 | unsigned int index = call->addr_ix; |
54 | bool have_result = false; |
55 | int ret = call->error; |
56 | |
57 | _enter("%s,%u,%u,%d,%d" , server->name, server_index, index, ret, call->abort_code); |
58 | |
59 | spin_lock(lock: &server->probe_lock); |
60 | |
61 | switch (ret) { |
62 | case 0: |
63 | server->probe.error = 0; |
64 | goto responded; |
65 | case -ECONNABORTED: |
66 | if (!(server->probe.flags & AFS_VLSERVER_PROBE_RESPONDED)) { |
67 | server->probe.abort_code = call->abort_code; |
68 | server->probe.error = ret; |
69 | } |
70 | goto responded; |
71 | case -ENOMEM: |
72 | case -ENONET: |
73 | case -EKEYEXPIRED: |
74 | case -EKEYREVOKED: |
75 | case -EKEYREJECTED: |
76 | server->probe.flags |= AFS_VLSERVER_PROBE_LOCAL_FAILURE; |
77 | if (server->probe.error == 0) |
78 | server->probe.error = ret; |
79 | trace_afs_io_error(call: call->debug_id, error: ret, where: afs_io_error_vl_probe_fail); |
80 | goto out; |
81 | case -ECONNRESET: /* Responded, but call expired. */ |
82 | case -ERFKILL: |
83 | case -EADDRNOTAVAIL: |
84 | case -ENETUNREACH: |
85 | case -EHOSTUNREACH: |
86 | case -EHOSTDOWN: |
87 | case -ECONNREFUSED: |
88 | case -ETIMEDOUT: |
89 | case -ETIME: |
90 | default: |
91 | clear_bit(nr: index, addr: &alist->responded); |
92 | set_bit(nr: index, addr: &alist->failed); |
93 | if (!(server->probe.flags & AFS_VLSERVER_PROBE_RESPONDED) && |
94 | (server->probe.error == 0 || |
95 | server->probe.error == -ETIMEDOUT || |
96 | server->probe.error == -ETIME)) |
97 | server->probe.error = ret; |
98 | trace_afs_io_error(call: call->debug_id, error: ret, where: afs_io_error_vl_probe_fail); |
99 | goto out; |
100 | } |
101 | |
102 | responded: |
103 | set_bit(nr: index, addr: &alist->responded); |
104 | clear_bit(nr: index, addr: &alist->failed); |
105 | |
106 | if (call->service_id == YFS_VL_SERVICE) { |
107 | server->probe.flags |= AFS_VLSERVER_PROBE_IS_YFS; |
108 | set_bit(AFS_VLSERVER_FL_IS_YFS, addr: &server->flags); |
109 | alist->addrs[index].srx_service = call->service_id; |
110 | } else { |
111 | server->probe.flags |= AFS_VLSERVER_PROBE_NOT_YFS; |
112 | if (!(server->probe.flags & AFS_VLSERVER_PROBE_IS_YFS)) { |
113 | clear_bit(AFS_VLSERVER_FL_IS_YFS, addr: &server->flags); |
114 | alist->addrs[index].srx_service = call->service_id; |
115 | } |
116 | } |
117 | |
118 | rxrpc_kernel_get_srtt(call->net->socket, call->rxcall, &rtt_us); |
119 | if (rtt_us < server->probe.rtt) { |
120 | server->probe.rtt = rtt_us; |
121 | server->rtt = rtt_us; |
122 | alist->preferred = index; |
123 | } |
124 | |
125 | smp_wmb(); /* Set rtt before responded. */ |
126 | server->probe.flags |= AFS_VLSERVER_PROBE_RESPONDED; |
127 | set_bit(AFS_VLSERVER_FL_PROBED, addr: &server->flags); |
128 | set_bit(AFS_VLSERVER_FL_RESPONDING, addr: &server->flags); |
129 | have_result = true; |
130 | out: |
131 | spin_unlock(lock: &server->probe_lock); |
132 | |
133 | _debug("probe [%u][%u] %pISpc rtt=%u ret=%d" , |
134 | server_index, index, &alist->addrs[index].transport, rtt_us, ret); |
135 | |
136 | afs_done_one_vl_probe(server, wake_up: have_result); |
137 | } |
138 | |
139 | /* |
140 | * Probe all of a vlserver's addresses to find out the best route and to |
141 | * query its capabilities. |
142 | */ |
143 | static bool afs_do_probe_vlserver(struct afs_net *net, |
144 | struct afs_vlserver *server, |
145 | struct key *key, |
146 | unsigned int server_index, |
147 | struct afs_error *_e) |
148 | { |
149 | struct afs_addr_cursor ac = { |
150 | .index = 0, |
151 | }; |
152 | struct afs_call *call; |
153 | bool in_progress = false; |
154 | |
155 | _enter("%s" , server->name); |
156 | |
157 | read_lock(&server->lock); |
158 | ac.alist = rcu_dereference_protected(server->addresses, |
159 | lockdep_is_held(&server->lock)); |
160 | read_unlock(&server->lock); |
161 | |
162 | atomic_set(v: &server->probe_outstanding, i: ac.alist->nr_addrs); |
163 | memset(&server->probe, 0, sizeof(server->probe)); |
164 | server->probe.rtt = UINT_MAX; |
165 | |
166 | for (ac.index = 0; ac.index < ac.alist->nr_addrs; ac.index++) { |
167 | call = afs_vl_get_capabilities(net, &ac, key, server, |
168 | server_index); |
169 | if (!IS_ERR(ptr: call)) { |
170 | afs_put_call(call); |
171 | in_progress = true; |
172 | } else { |
173 | afs_prioritise_error(_e, PTR_ERR(ptr: call), ac.abort_code); |
174 | afs_done_one_vl_probe(server, wake_up: false); |
175 | } |
176 | } |
177 | |
178 | return in_progress; |
179 | } |
180 | |
181 | /* |
182 | * Send off probes to all unprobed servers. |
183 | */ |
184 | int afs_send_vl_probes(struct afs_net *net, struct key *key, |
185 | struct afs_vlserver_list *vllist) |
186 | { |
187 | struct afs_vlserver *server; |
188 | struct afs_error e; |
189 | bool in_progress = false; |
190 | int i; |
191 | |
192 | e.error = 0; |
193 | e.responded = false; |
194 | for (i = 0; i < vllist->nr_servers; i++) { |
195 | server = vllist->servers[i].server; |
196 | if (test_bit(AFS_VLSERVER_FL_PROBED, &server->flags)) |
197 | continue; |
198 | |
199 | if (!test_and_set_bit_lock(AFS_VLSERVER_FL_PROBING, addr: &server->flags) && |
200 | afs_do_probe_vlserver(net, server, key, server_index: i, e: &e)) |
201 | in_progress = true; |
202 | } |
203 | |
204 | return in_progress ? 0 : e.error; |
205 | } |
206 | |
207 | /* |
208 | * Wait for the first as-yet untried server to respond. |
209 | */ |
210 | int afs_wait_for_vl_probes(struct afs_vlserver_list *vllist, |
211 | unsigned long untried) |
212 | { |
213 | struct wait_queue_entry *waits; |
214 | struct afs_vlserver *server; |
215 | unsigned int rtt = UINT_MAX, rtt_s; |
216 | bool have_responders = false; |
217 | int pref = -1, i; |
218 | |
219 | _enter("%u,%lx" , vllist->nr_servers, untried); |
220 | |
221 | /* Only wait for servers that have a probe outstanding. */ |
222 | for (i = 0; i < vllist->nr_servers; i++) { |
223 | if (test_bit(i, &untried)) { |
224 | server = vllist->servers[i].server; |
225 | if (!test_bit(AFS_VLSERVER_FL_PROBING, &server->flags)) |
226 | __clear_bit(i, &untried); |
227 | if (server->probe.flags & AFS_VLSERVER_PROBE_RESPONDED) |
228 | have_responders = true; |
229 | } |
230 | } |
231 | if (have_responders || !untried) |
232 | return 0; |
233 | |
234 | waits = kmalloc(array_size(vllist->nr_servers, sizeof(*waits)), GFP_KERNEL); |
235 | if (!waits) |
236 | return -ENOMEM; |
237 | |
238 | for (i = 0; i < vllist->nr_servers; i++) { |
239 | if (test_bit(i, &untried)) { |
240 | server = vllist->servers[i].server; |
241 | init_waitqueue_entry(wq_entry: &waits[i], current); |
242 | add_wait_queue(wq_head: &server->probe_wq, wq_entry: &waits[i]); |
243 | } |
244 | } |
245 | |
246 | for (;;) { |
247 | bool still_probing = false; |
248 | |
249 | set_current_state(TASK_INTERRUPTIBLE); |
250 | for (i = 0; i < vllist->nr_servers; i++) { |
251 | if (test_bit(i, &untried)) { |
252 | server = vllist->servers[i].server; |
253 | if (server->probe.flags & AFS_VLSERVER_PROBE_RESPONDED) |
254 | goto stop; |
255 | if (test_bit(AFS_VLSERVER_FL_PROBING, &server->flags)) |
256 | still_probing = true; |
257 | } |
258 | } |
259 | |
260 | if (!still_probing || signal_pending(current)) |
261 | goto stop; |
262 | schedule(); |
263 | } |
264 | |
265 | stop: |
266 | set_current_state(TASK_RUNNING); |
267 | |
268 | for (i = 0; i < vllist->nr_servers; i++) { |
269 | if (test_bit(i, &untried)) { |
270 | server = vllist->servers[i].server; |
271 | rtt_s = READ_ONCE(server->rtt); |
272 | if (test_bit(AFS_VLSERVER_FL_RESPONDING, &server->flags) && |
273 | rtt_s < rtt) { |
274 | pref = i; |
275 | rtt = rtt_s; |
276 | } |
277 | |
278 | remove_wait_queue(wq_head: &server->probe_wq, wq_entry: &waits[i]); |
279 | } |
280 | } |
281 | |
282 | kfree(objp: waits); |
283 | |
284 | if (pref == -1 && signal_pending(current)) |
285 | return -ERESTARTSYS; |
286 | |
287 | if (pref >= 0) |
288 | vllist->preferred = pref; |
289 | |
290 | _leave(" = 0 [%u]" , pref); |
291 | return 0; |
292 | } |
293 | |