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. */
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
);
85 set_bit(index
, &alist
->responded
);
86 clear_bit(index
, &alist
->failed
);
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
;
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
;
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.
104 _rtt
= rxrpc_kernel_get_rtt(call
->net
->socket
, call
->rxcall
);
106 rtt
= (_rtt
> UINT_MAX
) ? UINT_MAX
: _rtt
;
107 if (rtt
< server
->probe
.rtt
) {
108 server
->probe
.rtt
= rtt
;
109 alist
->preferred
= index
;
113 smp_wmb(); /* Set rtt before responded. */
114 server
->probe
.responded
= true;
115 set_bit(AFS_SERVER_FL_PROBED
, &server
->flags
);
117 spin_unlock(&server
->probe_lock
);
119 _debug("probe [%u][%u] %pISpc rtt=%u ret=%d",
120 server_index
, index
, &alist
->addrs
[index
].transport
,
121 (unsigned int)rtt
, ret
);
123 have_result
|= afs_fs_probe_done(server
);
125 server
->probe
.have_result
= true;
126 wake_up_var(&server
->probe
.have_result
);
127 wake_up_all(&server
->probe_wq
);
132 * Probe all of a fileserver's addresses to find out the best route and to
133 * query its capabilities.
135 static int afs_do_probe_fileserver(struct afs_net
*net
,
136 struct afs_server
*server
,
138 unsigned int server_index
,
139 struct afs_error
*_e
)
141 struct afs_addr_cursor ac
= {
144 bool in_progress
= false;
147 _enter("%pU", &server
->uuid
);
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
);
154 atomic_set(&server
->probe_outstanding
, ac
.alist
->nr_addrs
);
155 memset(&server
->probe
, 0, sizeof(server
->probe
));
156 server
->probe
.rtt
= UINT_MAX
;
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
,
161 if (err
== -EINPROGRESS
)
164 afs_prioritise_error(_e
, err
, ac
.abort_code
);
168 afs_fs_probe_done(server
);
173 * Send off probes to all unprobed servers.
175 int afs_probe_fileservers(struct afs_net
*net
, struct key
*key
,
176 struct afs_server_list
*list
)
178 struct afs_server
*server
;
180 bool in_progress
= 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
))
190 if (!test_and_set_bit_lock(AFS_SERVER_FL_PROBING
, &server
->flags
) &&
191 afs_do_probe_fileserver(net
, server
, key
, i
, &e
))
195 return in_progress
? 0 : e
.error
;
199 * Wait for the first as-yet untried fileserver to respond.
201 int afs_wait_for_fs_probes(struct afs_server_list
*slist
, unsigned long untried
)
203 struct wait_queue_entry
*waits
;
204 struct afs_server
*server
;
205 unsigned int rtt
= UINT_MAX
;
206 bool have_responders
= false;
209 _enter("%u,%lx", slist
->nr_servers
, untried
);
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;
221 if (have_responders
|| !untried
)
224 waits
= kmalloc(array_size(slist
->nr_servers
, sizeof(*waits
)), GFP_KERNEL
);
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
]);
237 bool still_probing
= false;
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
)
245 if (test_bit(AFS_SERVER_FL_PROBING
, &server
->flags
))
246 still_probing
= true;
250 if (!still_probing
|| signal_pending(current
))
256 set_current_state(TASK_RUNNING
);
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
) {
264 rtt
= server
->probe
.rtt
;
267 remove_wait_queue(&server
->probe_wq
, &waits
[i
]);
273 if (pref
== -1 && signal_pending(current
))
277 slist
->preferred
= pref
;