blob: 442b5e7944ff28320f63bf4497c15a97603f42ea [file] [log] [blame]
Thomas Gleixnerb4d0d232019-05-20 19:08:01 +02001// SPDX-License-Identifier: GPL-2.0-or-later
David Howells3bf0fb62018-10-20 00:57:59 +01002/* AFS fileserver probing
3 *
David Howellsf6cbb362020-04-24 15:10:00 +01004 * Copyright (C) 2018, 2020 Red Hat, Inc. All Rights Reserved.
David Howells3bf0fb62018-10-20 00:57:59 +01005 * Written by David Howells (dhowells@redhat.com)
David Howells3bf0fb62018-10-20 00:57:59 +01006 */
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
David Howellsf6cbb362020-04-24 15:10:00 +010014static unsigned int afs_fs_probe_fast_poll_interval = 30 * HZ;
15static unsigned int afs_fs_probe_slow_poll_interval = 5 * 60 * HZ;
David Howells3bf0fb62018-10-20 00:57:59 +010016
David Howellsf6cbb362020-04-24 15:10:00 +010017/*
18 * Start the probe polling timer. We have to supply it with an inc on the
19 * outstanding server count.
20 */
21static void afs_schedule_fs_probe(struct afs_net *net,
22 struct afs_server *server, bool fast)
23{
24 unsigned long atj;
25
26 if (!net->live)
27 return;
28
29 atj = server->probed_at;
30 atj += fast ? afs_fs_probe_fast_poll_interval : afs_fs_probe_slow_poll_interval;
31
32 afs_inc_servers_outstanding(net);
33 if (timer_reduce(&net->fs_probe_timer, atj))
34 afs_dec_servers_outstanding(net);
35}
36
37/*
38 * Handle the completion of a set of probes.
39 */
40static void afs_finished_fs_probe(struct afs_net *net, struct afs_server *server)
41{
42 bool responded = server->probe.responded;
43
44 write_seqlock(&net->fs_lock);
45 if (responded)
46 list_add_tail(&server->probe_link, &net->fs_probe_slow);
47 else
48 list_add_tail(&server->probe_link, &net->fs_probe_fast);
49 write_sequnlock(&net->fs_lock);
50
51 afs_schedule_fs_probe(net, server, !responded);
52}
53
54/*
55 * Handle the completion of a probe.
56 */
57static void afs_done_one_fs_probe(struct afs_net *net, struct afs_server *server)
58{
59 _enter("");
60
61 if (atomic_dec_and_test(&server->probe_outstanding))
62 afs_finished_fs_probe(net, server);
63
64 wake_up_all(&server->probe_wq);
65}
66
67/*
68 * Handle inability to send a probe due to ENOMEM when trying to allocate a
69 * call struct.
70 */
71static void afs_fs_probe_not_done(struct afs_net *net,
72 struct afs_server *server,
73 struct afs_addr_cursor *ac)
74{
75 struct afs_addr_list *alist = ac->alist;
76 unsigned int index = ac->index;
77
78 _enter("");
79
80 trace_afs_io_error(0, -ENOMEM, afs_io_error_fs_probe_fail);
81 spin_lock(&server->probe_lock);
82
83 server->probe.local_failure = true;
84 if (server->probe.error == 0)
85 server->probe.error = -ENOMEM;
86
87 set_bit(index, &alist->failed);
88
89 spin_unlock(&server->probe_lock);
90 return afs_done_one_fs_probe(net, server);
David Howells3bf0fb62018-10-20 00:57:59 +010091}
92
93/*
94 * Process the result of probing a fileserver. This is called after successful
95 * or failed delivery of an FS.GetCapabilities operation.
96 */
97void afs_fileserver_probe_result(struct afs_call *call)
98{
99 struct afs_addr_list *alist = call->alist;
David Howellsffba7182019-05-09 22:22:50 +0100100 struct afs_server *server = call->server;
David Howells3bf0fb62018-10-20 00:57:59 +0100101 unsigned int index = call->addr_ix;
David Howells8a1d24e2020-05-22 23:58:28 +0100102 unsigned int rtt_us = 0;
David Howells3bf0fb62018-10-20 00:57:59 +0100103 int ret = call->error;
104
105 _enter("%pU,%u", &server->uuid, index);
106
107 spin_lock(&server->probe_lock);
108
109 switch (ret) {
110 case 0:
111 server->probe.error = 0;
112 goto responded;
113 case -ECONNABORTED:
114 if (!server->probe.responded) {
115 server->probe.abort_code = call->abort_code;
116 server->probe.error = ret;
117 }
118 goto responded;
119 case -ENOMEM:
120 case -ENONET:
David Howellsf6cbb362020-04-24 15:10:00 +0100121 clear_bit(index, &alist->responded);
David Howells3bf0fb62018-10-20 00:57:59 +0100122 server->probe.local_failure = true;
David Howellsf6cbb362020-04-24 15:10:00 +0100123 trace_afs_io_error(call->debug_id, ret, afs_io_error_fs_probe_fail);
David Howells3bf0fb62018-10-20 00:57:59 +0100124 goto out;
125 case -ECONNRESET: /* Responded, but call expired. */
David Howells4584ae92018-11-13 23:20:28 +0000126 case -ERFKILL:
127 case -EADDRNOTAVAIL:
David Howells3bf0fb62018-10-20 00:57:59 +0100128 case -ENETUNREACH:
129 case -EHOSTUNREACH:
David Howells4584ae92018-11-13 23:20:28 +0000130 case -EHOSTDOWN:
David Howells3bf0fb62018-10-20 00:57:59 +0100131 case -ECONNREFUSED:
132 case -ETIMEDOUT:
133 case -ETIME:
134 default:
135 clear_bit(index, &alist->responded);
136 set_bit(index, &alist->failed);
137 if (!server->probe.responded &&
138 (server->probe.error == 0 ||
139 server->probe.error == -ETIMEDOUT ||
140 server->probe.error == -ETIME))
141 server->probe.error = ret;
David Howellsf6cbb362020-04-24 15:10:00 +0100142 trace_afs_io_error(call->debug_id, ret, afs_io_error_fs_probe_fail);
David Howells3bf0fb62018-10-20 00:57:59 +0100143 goto out;
144 }
145
146responded:
David Howells3bf0fb62018-10-20 00:57:59 +0100147 clear_bit(index, &alist->failed);
148
149 if (call->service_id == YFS_FS_SERVICE) {
150 server->probe.is_yfs = true;
151 set_bit(AFS_SERVER_FL_IS_YFS, &server->flags);
152 alist->addrs[index].srx_service = call->service_id;
153 } else {
154 server->probe.not_yfs = true;
155 if (!server->probe.is_yfs) {
156 clear_bit(AFS_SERVER_FL_IS_YFS, &server->flags);
157 alist->addrs[index].srx_service = call->service_id;
158 }
159 }
160
David Howellsc410bf012020-05-11 14:54:34 +0100161 rtt_us = rxrpc_kernel_get_srtt(call->net->socket, call->rxcall);
162 if (rtt_us < server->probe.rtt) {
163 server->probe.rtt = rtt_us;
David Howells3bf0fb62018-10-20 00:57:59 +0100164 alist->preferred = index;
David Howells3bf0fb62018-10-20 00:57:59 +0100165 }
166
167 smp_wmb(); /* Set rtt before responded. */
168 server->probe.responded = true;
David Howellsf6cbb362020-04-24 15:10:00 +0100169 set_bit(index, &alist->responded);
David Howells3bf0fb62018-10-20 00:57:59 +0100170out:
171 spin_unlock(&server->probe_lock);
172
David Howellsf6cbb362020-04-24 15:10:00 +0100173 _debug("probe %pU [%u] %pISpc rtt=%u ret=%d",
174 &server->uuid, index, &alist->addrs[index].transport,
175 rtt_us, ret);
David Howells3bf0fb62018-10-20 00:57:59 +0100176
David Howellsf6cbb362020-04-24 15:10:00 +0100177 return afs_done_one_fs_probe(call->net, server);
David Howells3bf0fb62018-10-20 00:57:59 +0100178}
179
180/*
David Howellsf6cbb362020-04-24 15:10:00 +0100181 * Probe one or all of a fileserver's addresses to find out the best route and
182 * to query its capabilities.
David Howells3bf0fb62018-10-20 00:57:59 +0100183 */
David Howellsf6cbb362020-04-24 15:10:00 +0100184void afs_fs_probe_fileserver(struct afs_net *net, struct afs_server *server,
185 struct key *key, bool all)
David Howells3bf0fb62018-10-20 00:57:59 +0100186{
187 struct afs_addr_cursor ac = {
188 .index = 0,
189 };
David Howells3bf0fb62018-10-20 00:57:59 +0100190
191 _enter("%pU", &server->uuid);
192
193 read_lock(&server->fs_lock);
194 ac.alist = rcu_dereference_protected(server->addresses,
195 lockdep_is_held(&server->fs_lock));
David Howells9efcc4a12020-03-26 15:24:07 +0000196 afs_get_addrlist(ac.alist);
David Howells3bf0fb62018-10-20 00:57:59 +0100197 read_unlock(&server->fs_lock);
198
David Howellsf6cbb362020-04-24 15:10:00 +0100199 server->probed_at = jiffies;
200 atomic_set(&server->probe_outstanding, all ? ac.alist->nr_addrs : 1);
David Howells3bf0fb62018-10-20 00:57:59 +0100201 memset(&server->probe, 0, sizeof(server->probe));
202 server->probe.rtt = UINT_MAX;
203
David Howellsf6cbb362020-04-24 15:10:00 +0100204 ac.index = ac.alist->preferred;
205 if (ac.index < 0 || ac.index >= ac.alist->nr_addrs)
206 all = true;
207
208 if (all) {
209 for (ac.index = 0; ac.index < ac.alist->nr_addrs; ac.index++)
210 if (!afs_fs_get_capabilities(net, server, &ac, key))
211 afs_fs_probe_not_done(net, server, &ac);
212 } else {
213 if (!afs_fs_get_capabilities(net, server, &ac, key))
214 afs_fs_probe_not_done(net, server, &ac);
David Howells3bf0fb62018-10-20 00:57:59 +0100215 }
216
David Howells9efcc4a12020-03-26 15:24:07 +0000217 afs_put_addrlist(ac.alist);
David Howells3bf0fb62018-10-20 00:57:59 +0100218}
219
220/*
221 * Wait for the first as-yet untried fileserver to respond.
222 */
223int afs_wait_for_fs_probes(struct afs_server_list *slist, unsigned long untried)
224{
225 struct wait_queue_entry *waits;
226 struct afs_server *server;
227 unsigned int rtt = UINT_MAX;
228 bool have_responders = false;
229 int pref = -1, i;
230
231 _enter("%u,%lx", slist->nr_servers, untried);
232
233 /* Only wait for servers that have a probe outstanding. */
234 for (i = 0; i < slist->nr_servers; i++) {
235 if (test_bit(i, &untried)) {
236 server = slist->servers[i].server;
David Howellsf6cbb362020-04-24 15:10:00 +0100237 if (!atomic_read(&server->probe_outstanding))
David Howells3bf0fb62018-10-20 00:57:59 +0100238 __clear_bit(i, &untried);
239 if (server->probe.responded)
240 have_responders = true;
241 }
242 }
243 if (have_responders || !untried)
244 return 0;
245
246 waits = kmalloc(array_size(slist->nr_servers, sizeof(*waits)), GFP_KERNEL);
247 if (!waits)
248 return -ENOMEM;
249
250 for (i = 0; i < slist->nr_servers; i++) {
251 if (test_bit(i, &untried)) {
252 server = slist->servers[i].server;
253 init_waitqueue_entry(&waits[i], current);
254 add_wait_queue(&server->probe_wq, &waits[i]);
255 }
256 }
257
258 for (;;) {
259 bool still_probing = false;
260
261 set_current_state(TASK_INTERRUPTIBLE);
262 for (i = 0; i < slist->nr_servers; i++) {
263 if (test_bit(i, &untried)) {
264 server = slist->servers[i].server;
265 if (server->probe.responded)
266 goto stop;
David Howellsf6cbb362020-04-24 15:10:00 +0100267 if (atomic_read(&server->probe_outstanding))
David Howells3bf0fb62018-10-20 00:57:59 +0100268 still_probing = true;
269 }
270 }
271
Davidlohr Bueso08d405c2019-01-03 15:28:58 -0800272 if (!still_probing || signal_pending(current))
David Howells3bf0fb62018-10-20 00:57:59 +0100273 goto stop;
274 schedule();
275 }
276
277stop:
278 set_current_state(TASK_RUNNING);
279
280 for (i = 0; i < slist->nr_servers; i++) {
281 if (test_bit(i, &untried)) {
282 server = slist->servers[i].server;
283 if (server->probe.responded &&
284 server->probe.rtt < rtt) {
285 pref = i;
286 rtt = server->probe.rtt;
287 }
288
289 remove_wait_queue(&server->probe_wq, &waits[i]);
290 }
291 }
292
293 kfree(waits);
294
295 if (pref == -1 && signal_pending(current))
296 return -ERESTARTSYS;
297
298 if (pref >= 0)
299 slist->preferred = pref;
300 return 0;
301}
David Howellsf6cbb362020-04-24 15:10:00 +0100302
303/*
304 * Probe timer. We have an increment on fs_outstanding that we need to pass
305 * along to the work item.
306 */
307void afs_fs_probe_timer(struct timer_list *timer)
308{
309 struct afs_net *net = container_of(timer, struct afs_net, fs_probe_timer);
310
311 if (!queue_work(afs_wq, &net->fs_prober))
312 afs_dec_servers_outstanding(net);
313}
314
315/*
316 * Dispatch a probe to a server.
317 */
318static void afs_dispatch_fs_probe(struct afs_net *net, struct afs_server *server, bool all)
319 __releases(&net->fs_lock)
320{
321 struct key *key = NULL;
322
323 /* We remove it from the queues here - it will be added back to
324 * one of the queues on the completion of the probe.
325 */
326 list_del_init(&server->probe_link);
327
328 afs_get_server(server, afs_server_trace_get_probe);
329 write_sequnlock(&net->fs_lock);
330
331 afs_fs_probe_fileserver(net, server, key, all);
332 afs_put_server(net, server, afs_server_trace_put_probe);
333}
334
335/*
336 * Probe dispatcher to regularly dispatch probes to keep NAT alive.
337 */
338void afs_fs_probe_dispatcher(struct work_struct *work)
339{
340 struct afs_net *net = container_of(work, struct afs_net, fs_prober);
341 struct afs_server *fast, *slow, *server;
342 unsigned long nowj, timer_at, poll_at;
343 bool first_pass = true, set_timer = false;
344
345 if (!net->live)
346 return;
347
348 _enter("");
349
350 if (list_empty(&net->fs_probe_fast) && list_empty(&net->fs_probe_slow)) {
351 _leave(" [none]");
352 return;
353 }
354
355again:
356 write_seqlock(&net->fs_lock);
357
358 fast = slow = server = NULL;
359 nowj = jiffies;
360 timer_at = nowj + MAX_JIFFY_OFFSET;
361
362 if (!list_empty(&net->fs_probe_fast)) {
363 fast = list_first_entry(&net->fs_probe_fast, struct afs_server, probe_link);
364 poll_at = fast->probed_at + afs_fs_probe_fast_poll_interval;
365 if (time_before(nowj, poll_at)) {
366 timer_at = poll_at;
367 set_timer = true;
368 fast = NULL;
369 }
370 }
371
372 if (!list_empty(&net->fs_probe_slow)) {
373 slow = list_first_entry(&net->fs_probe_slow, struct afs_server, probe_link);
374 poll_at = slow->probed_at + afs_fs_probe_slow_poll_interval;
375 if (time_before(nowj, poll_at)) {
376 if (time_before(poll_at, timer_at))
377 timer_at = poll_at;
378 set_timer = true;
379 slow = NULL;
380 }
381 }
382
383 server = fast ?: slow;
384 if (server)
385 _debug("probe %pU", &server->uuid);
386
387 if (server && (first_pass || !need_resched())) {
388 afs_dispatch_fs_probe(net, server, server == fast);
389 first_pass = false;
390 goto again;
391 }
392
393 write_sequnlock(&net->fs_lock);
394
395 if (server) {
396 if (!queue_work(afs_wq, &net->fs_prober))
397 afs_dec_servers_outstanding(net);
398 _leave(" [requeue]");
399 } else if (set_timer) {
400 if (timer_reduce(&net->fs_probe_timer, timer_at))
401 afs_dec_servers_outstanding(net);
402 _leave(" [timer]");
403 } else {
404 afs_dec_servers_outstanding(net);
405 _leave(" [quiesce]");
406 }
407}