1 /* AFS fileserver probing
3 * Copyright (C) 2018 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
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.
12 #include <linux/sched.h>
13 #include <linux/slab.h>
16 #include "protocol_yfs.h"
18 static bool afs_fs_probe_done(struct afs_server
*server
)
20 if (!atomic_dec_and_test(&server
->probe_outstanding
))
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
);
30 * Process the result of probing a fileserver. This is called after successful
31 * or failed delivery of an FS.GetCapabilities operation.
33 void afs_fileserver_probe_result(struct afs_call
*call
)
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;
42 int ret
= call
->error
;
44 _enter("%pU,%u", &server
->uuid
, index
);
46 spin_lock(&server
->probe_lock
);
50 server
->probe
.error
= 0;
53 if (!server
->probe
.responded
) {
54 server
->probe
.abort_code
= call
->abort_code
;
55 server
->probe
.error
= ret
;
60 server
->probe
.local_failure
= true;
61 afs_io_error(call
, afs_io_error_fs_probe_fail
);
63 case -ECONNRESET
: /* Responded, but call expired. */
70 clear_bit(index
, &alist
->responded
);
71 set_bit(index
, &alist
->failed
);
72 if (!server
->probe
.responded
&&
73 (server
->probe
.error
== 0 ||
74 server
->probe
.error
== -ETIMEDOUT
||
75 server
->probe
.error
== -ETIME
))
76 server
->probe
.error
= ret
;
77 afs_io_error(call
, afs_io_error_fs_probe_fail
);
82 set_bit(index
, &alist
->responded
);
83 clear_bit(index
, &alist
->failed
);
85 if (call
->service_id
== YFS_FS_SERVICE
) {
86 server
->probe
.is_yfs
= true;
87 set_bit(AFS_SERVER_FL_IS_YFS
, &server
->flags
);
88 alist
->addrs
[index
].srx_service
= call
->service_id
;
90 server
->probe
.not_yfs
= true;
91 if (!server
->probe
.is_yfs
) {
92 clear_bit(AFS_SERVER_FL_IS_YFS
, &server
->flags
);
93 alist
->addrs
[index
].srx_service
= call
->service_id
;
97 /* Get the RTT and scale it to fit into a 32-bit value that represents
98 * over a minute of time so that we can access it with one instruction
101 _rtt
= rxrpc_kernel_get_rtt(call
->net
->socket
, call
->rxcall
);
103 rtt
= (_rtt
> UINT_MAX
) ? UINT_MAX
: _rtt
;
104 if (rtt
< server
->probe
.rtt
) {
105 server
->probe
.rtt
= rtt
;
106 alist
->preferred
= index
;
110 smp_wmb(); /* Set rtt before responded. */
111 server
->probe
.responded
= true;
112 set_bit(AFS_SERVER_FL_PROBED
, &server
->flags
);
114 spin_unlock(&server
->probe_lock
);
116 _debug("probe [%u][%u] %pISpc rtt=%u ret=%d",
117 server_index
, index
, &alist
->addrs
[index
].transport
,
118 (unsigned int)rtt
, ret
);
120 have_result
|= afs_fs_probe_done(server
);
122 server
->probe
.have_result
= true;
123 wake_up_var(&server
->probe
.have_result
);
124 wake_up_all(&server
->probe_wq
);
129 * Probe all of a fileserver's addresses to find out the best route and to
130 * query its capabilities.
132 static int afs_do_probe_fileserver(struct afs_net
*net
,
133 struct afs_server
*server
,
135 unsigned int server_index
)
137 struct afs_addr_cursor ac
= {
142 _enter("%pU", &server
->uuid
);
144 read_lock(&server
->fs_lock
);
145 ac
.alist
= rcu_dereference_protected(server
->addresses
,
146 lockdep_is_held(&server
->fs_lock
));
147 read_unlock(&server
->fs_lock
);
149 atomic_set(&server
->probe_outstanding
, ac
.alist
->nr_addrs
);
150 memset(&server
->probe
, 0, sizeof(server
->probe
));
151 server
->probe
.rtt
= UINT_MAX
;
153 for (ac
.index
= 0; ac
.index
< ac
.alist
->nr_addrs
; ac
.index
++) {
154 ret
= afs_fs_get_capabilities(net
, server
, &ac
, key
, server_index
,
156 if (ret
!= -EINPROGRESS
) {
157 afs_fs_probe_done(server
);
166 * Send off probes to all unprobed servers.
168 int afs_probe_fileservers(struct afs_net
*net
, struct key
*key
,
169 struct afs_server_list
*list
)
171 struct afs_server
*server
;
174 for (i
= 0; i
< list
->nr_servers
; i
++) {
175 server
= list
->servers
[i
].server
;
176 if (test_bit(AFS_SERVER_FL_PROBED
, &server
->flags
))
179 if (!test_and_set_bit_lock(AFS_SERVER_FL_PROBING
, &server
->flags
)) {
180 ret
= afs_do_probe_fileserver(net
, server
, key
, i
);
190 * Wait for the first as-yet untried fileserver to respond.
192 int afs_wait_for_fs_probes(struct afs_server_list
*slist
, unsigned long untried
)
194 struct wait_queue_entry
*waits
;
195 struct afs_server
*server
;
196 unsigned int rtt
= UINT_MAX
;
197 bool have_responders
= false;
200 _enter("%u,%lx", slist
->nr_servers
, untried
);
202 /* Only wait for servers that have a probe outstanding. */
203 for (i
= 0; i
< slist
->nr_servers
; i
++) {
204 if (test_bit(i
, &untried
)) {
205 server
= slist
->servers
[i
].server
;
206 if (!test_bit(AFS_SERVER_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(slist
->nr_servers
, sizeof(*waits
)), GFP_KERNEL
);
219 for (i
= 0; i
< slist
->nr_servers
; i
++) {
220 if (test_bit(i
, &untried
)) {
221 server
= slist
->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
< slist
->nr_servers
; i
++) {
232 if (test_bit(i
, &untried
)) {
233 server
= slist
->servers
[i
].server
;
234 if (server
->probe
.responded
)
236 if (test_bit(AFS_SERVER_FL_PROBING
, &server
->flags
))
237 still_probing
= true;
241 if (!still_probing
|| unlikely(signal_pending(current
)))
247 set_current_state(TASK_RUNNING
);
249 for (i
= 0; i
< slist
->nr_servers
; i
++) {
250 if (test_bit(i
, &untried
)) {
251 server
= slist
->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 slist
->preferred
= pref
;