1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* AFS vlserver probing
4 * Copyright (C) 2018 Red Hat, Inc. All Rights Reserved.
5 * Written by David Howells (dhowells@redhat.com)
8 #include <linux/sched.h>
9 #include <linux/slab.h>
12 #include "protocol_yfs.h"
14 static bool afs_vl_probe_done(struct afs_vlserver
*server
)
16 if (!atomic_dec_and_test(&server
->probe_outstanding
))
19 wake_up_var(&server
->probe_outstanding
);
20 clear_bit_unlock(AFS_VLSERVER_FL_PROBING
, &server
->flags
);
21 wake_up_bit(&server
->flags
, AFS_VLSERVER_FL_PROBING
);
26 * Process the result of probing a vlserver. This is called after successful
27 * or failed delivery of an VL.GetCapabilities operation.
29 void afs_vlserver_probe_result(struct afs_call
*call
)
31 struct afs_addr_list
*alist
= call
->alist
;
32 struct afs_vlserver
*server
= call
->vlserver
;
33 unsigned int server_index
= call
->server_index
;
34 unsigned int rtt_us
= 0;
35 unsigned int index
= call
->addr_ix
;
36 bool have_result
= false;
37 int ret
= call
->error
;
39 _enter("%s,%u,%u,%d,%d", server
->name
, server_index
, index
, ret
, call
->abort_code
);
41 spin_lock(&server
->probe_lock
);
45 server
->probe
.error
= 0;
48 if (!server
->probe
.responded
) {
49 server
->probe
.abort_code
= call
->abort_code
;
50 server
->probe
.error
= ret
;
55 server
->probe
.local_failure
= true;
56 afs_io_error(call
, afs_io_error_vl_probe_fail
);
58 case -ECONNRESET
: /* Responded, but call expired. */
68 clear_bit(index
, &alist
->responded
);
69 set_bit(index
, &alist
->failed
);
70 if (!server
->probe
.responded
&&
71 (server
->probe
.error
== 0 ||
72 server
->probe
.error
== -ETIMEDOUT
||
73 server
->probe
.error
== -ETIME
))
74 server
->probe
.error
= ret
;
75 afs_io_error(call
, afs_io_error_vl_probe_fail
);
80 set_bit(index
, &alist
->responded
);
81 clear_bit(index
, &alist
->failed
);
83 if (call
->service_id
== YFS_VL_SERVICE
) {
84 server
->probe
.is_yfs
= true;
85 set_bit(AFS_VLSERVER_FL_IS_YFS
, &server
->flags
);
86 alist
->addrs
[index
].srx_service
= call
->service_id
;
88 server
->probe
.not_yfs
= true;
89 if (!server
->probe
.is_yfs
) {
90 clear_bit(AFS_VLSERVER_FL_IS_YFS
, &server
->flags
);
91 alist
->addrs
[index
].srx_service
= call
->service_id
;
95 rtt_us
= rxrpc_kernel_get_srtt(call
->net
->socket
, call
->rxcall
);
96 if (rtt_us
< server
->probe
.rtt
) {
97 server
->probe
.rtt
= rtt_us
;
98 alist
->preferred
= index
;
102 smp_wmb(); /* Set rtt before responded. */
103 server
->probe
.responded
= true;
104 set_bit(AFS_VLSERVER_FL_PROBED
, &server
->flags
);
106 spin_unlock(&server
->probe_lock
);
108 _debug("probe [%u][%u] %pISpc rtt=%u ret=%d",
109 server_index
, index
, &alist
->addrs
[index
].transport
, rtt_us
, ret
);
111 have_result
|= afs_vl_probe_done(server
);
113 server
->probe
.have_result
= true;
114 wake_up_var(&server
->probe
.have_result
);
115 wake_up_all(&server
->probe_wq
);
120 * Probe all of a vlserver's addresses to find out the best route and to
121 * query its capabilities.
123 static bool afs_do_probe_vlserver(struct afs_net
*net
,
124 struct afs_vlserver
*server
,
126 unsigned int server_index
,
127 struct afs_error
*_e
)
129 struct afs_addr_cursor ac
= {
132 struct afs_call
*call
;
133 bool in_progress
= false;
135 _enter("%s", server
->name
);
137 read_lock(&server
->lock
);
138 ac
.alist
= rcu_dereference_protected(server
->addresses
,
139 lockdep_is_held(&server
->lock
));
140 read_unlock(&server
->lock
);
142 atomic_set(&server
->probe_outstanding
, ac
.alist
->nr_addrs
);
143 memset(&server
->probe
, 0, sizeof(server
->probe
));
144 server
->probe
.rtt
= UINT_MAX
;
146 for (ac
.index
= 0; ac
.index
< ac
.alist
->nr_addrs
; ac
.index
++) {
147 call
= afs_vl_get_capabilities(net
, &ac
, key
, server
,
153 afs_prioritise_error(_e
, PTR_ERR(call
), ac
.abort_code
);
158 afs_vl_probe_done(server
);
163 * Send off probes to all unprobed servers.
165 int afs_send_vl_probes(struct afs_net
*net
, struct key
*key
,
166 struct afs_vlserver_list
*vllist
)
168 struct afs_vlserver
*server
;
170 bool in_progress
= false;
175 for (i
= 0; i
< vllist
->nr_servers
; i
++) {
176 server
= vllist
->servers
[i
].server
;
177 if (test_bit(AFS_VLSERVER_FL_PROBED
, &server
->flags
))
180 if (!test_and_set_bit_lock(AFS_VLSERVER_FL_PROBING
, &server
->flags
) &&
181 afs_do_probe_vlserver(net
, server
, key
, i
, &e
))
185 return in_progress
? 0 : e
.error
;
189 * Wait for the first as-yet untried server to respond.
191 int afs_wait_for_vl_probes(struct afs_vlserver_list
*vllist
,
192 unsigned long untried
)
194 struct wait_queue_entry
*waits
;
195 struct afs_vlserver
*server
;
196 unsigned int rtt
= UINT_MAX
;
197 bool have_responders
= false;
200 _enter("%u,%lx", vllist
->nr_servers
, untried
);
202 /* Only wait for servers that have a probe outstanding. */
203 for (i
= 0; i
< vllist
->nr_servers
; i
++) {
204 if (test_bit(i
, &untried
)) {
205 server
= vllist
->servers
[i
].server
;
206 if (!test_bit(AFS_VLSERVER_FL_PROBING
, &server
->flags
))
207 __clear_bit(i
, &untried
);
208 if (server
->probe
.responded
)
209 have_responders
= true;
212 if (have_responders
|| !untried
)
215 waits
= kmalloc(array_size(vllist
->nr_servers
, sizeof(*waits
)), GFP_KERNEL
);
219 for (i
= 0; i
< vllist
->nr_servers
; i
++) {
220 if (test_bit(i
, &untried
)) {
221 server
= vllist
->servers
[i
].server
;
222 init_waitqueue_entry(&waits
[i
], current
);
223 add_wait_queue(&server
->probe_wq
, &waits
[i
]);
228 bool still_probing
= false;
230 set_current_state(TASK_INTERRUPTIBLE
);
231 for (i
= 0; i
< vllist
->nr_servers
; i
++) {
232 if (test_bit(i
, &untried
)) {
233 server
= vllist
->servers
[i
].server
;
234 if (server
->probe
.responded
)
236 if (test_bit(AFS_VLSERVER_FL_PROBING
, &server
->flags
))
237 still_probing
= true;
241 if (!still_probing
|| signal_pending(current
))
247 set_current_state(TASK_RUNNING
);
249 for (i
= 0; i
< vllist
->nr_servers
; i
++) {
250 if (test_bit(i
, &untried
)) {
251 server
= vllist
->servers
[i
].server
;
252 if (server
->probe
.responded
&&
253 server
->probe
.rtt
< rtt
) {
255 rtt
= server
->probe
.rtt
;
258 remove_wait_queue(&server
->probe_wq
, &waits
[i
]);
264 if (pref
== -1 && signal_pending(current
))
268 vllist
->preferred
= pref
;
270 _leave(" = 0 [%u]", pref
);