1b4d0d230SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
29cc6fc50SDavid Howells /* Handle fileserver selection and rotation.
39cc6fc50SDavid Howells *
49cc6fc50SDavid Howells * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved.
59cc6fc50SDavid Howells * Written by David Howells (dhowells@redhat.com)
69cc6fc50SDavid Howells */
79cc6fc50SDavid Howells
89cc6fc50SDavid Howells #include <linux/kernel.h>
99cc6fc50SDavid Howells #include <linux/slab.h>
10d2ddc776SDavid Howells #include <linux/fs.h>
11d2ddc776SDavid Howells #include <linux/sched.h>
12d2ddc776SDavid Howells #include <linux/delay.h>
13d2ddc776SDavid Howells #include <linux/sched/signal.h>
149cc6fc50SDavid Howells #include "internal.h"
15d2ddc776SDavid Howells #include "afs_fs.h"
169cc6fc50SDavid Howells
179cc6fc50SDavid Howells /*
18d2ddc776SDavid Howells * Begin iteration through a server list, starting with the vnode's last used
19d2ddc776SDavid Howells * server if possible, or the last recorded good server if not.
20d2ddc776SDavid Howells */
afs_start_fs_iteration(struct afs_operation * op,struct afs_vnode * vnode)21a310082fSDavid Howells static bool afs_start_fs_iteration(struct afs_operation *op,
22d2ddc776SDavid Howells struct afs_vnode *vnode)
23d2ddc776SDavid Howells {
2420325960SDavid Howells struct afs_server *server;
2520325960SDavid Howells void *cb_server;
26d2ddc776SDavid Howells int i;
27d2ddc776SDavid Howells
28e49c7b2fSDavid Howells read_lock(&op->volume->servers_lock);
298a070a96SDavid Howells op->server_list = afs_get_serverlist(
308a070a96SDavid Howells rcu_dereference_protected(op->volume->servers,
318a070a96SDavid Howells lockdep_is_held(&op->volume->servers_lock)));
32e49c7b2fSDavid Howells read_unlock(&op->volume->servers_lock);
33d2ddc776SDavid Howells
34a310082fSDavid Howells op->untried = (1UL << op->server_list->nr_servers) - 1;
35a310082fSDavid Howells op->index = READ_ONCE(op->server_list->preferred);
363bf0fb6fSDavid Howells
3720325960SDavid Howells cb_server = vnode->cb_server;
3820325960SDavid Howells if (cb_server) {
39d2ddc776SDavid Howells /* See if the vnode's preferred record is still available */
40a310082fSDavid Howells for (i = 0; i < op->server_list->nr_servers; i++) {
4120325960SDavid Howells server = op->server_list->servers[i].server;
4220325960SDavid Howells if (server == cb_server) {
43a310082fSDavid Howells op->index = i;
44d2ddc776SDavid Howells goto found_interest;
45d2ddc776SDavid Howells }
46d2ddc776SDavid Howells }
47d2ddc776SDavid Howells
48d2ddc776SDavid Howells /* If we have a lock outstanding on a server that's no longer
49d2ddc776SDavid Howells * serving this vnode, then we can't switch to another server
50d2ddc776SDavid Howells * and have to return an error.
51d2ddc776SDavid Howells */
52a310082fSDavid Howells if (op->flags & AFS_OPERATION_CUR_ONLY) {
53a310082fSDavid Howells op->error = -ESTALE;
54d2ddc776SDavid Howells return false;
55d2ddc776SDavid Howells }
56d2ddc776SDavid Howells
57d2ddc776SDavid Howells /* Note that the callback promise is effectively broken */
58d2ddc776SDavid Howells write_seqlock(&vnode->cb_lock);
5920325960SDavid Howells ASSERTCMP(cb_server, ==, vnode->cb_server);
6020325960SDavid Howells vnode->cb_server = NULL;
61d2ddc776SDavid Howells if (test_and_clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags))
62d2ddc776SDavid Howells vnode->cb_break++;
63d2ddc776SDavid Howells write_sequnlock(&vnode->cb_lock);
64d2ddc776SDavid Howells }
65d2ddc776SDavid Howells
66d2ddc776SDavid Howells found_interest:
67d2ddc776SDavid Howells return true;
68d2ddc776SDavid Howells }
69d2ddc776SDavid Howells
70d2ddc776SDavid Howells /*
71d2ddc776SDavid Howells * Post volume busy note.
72d2ddc776SDavid Howells */
afs_busy(struct afs_volume * volume,u32 abort_code)73d2ddc776SDavid Howells static void afs_busy(struct afs_volume *volume, u32 abort_code)
74d2ddc776SDavid Howells {
75d2ddc776SDavid Howells const char *m;
76d2ddc776SDavid Howells
77d2ddc776SDavid Howells switch (abort_code) {
78d2ddc776SDavid Howells case VOFFLINE: m = "offline"; break;
79d2ddc776SDavid Howells case VRESTARTING: m = "restarting"; break;
80d2ddc776SDavid Howells case VSALVAGING: m = "being salvaged"; break;
81d2ddc776SDavid Howells default: m = "busy"; break;
82d2ddc776SDavid Howells }
83d2ddc776SDavid Howells
843b6492dfSDavid Howells pr_notice("kAFS: Volume %llu '%s' is %s\n", volume->vid, volume->name, m);
85d2ddc776SDavid Howells }
86d2ddc776SDavid Howells
87d2ddc776SDavid Howells /*
88d2ddc776SDavid Howells * Sleep and retry the operation to the same fileserver.
89d2ddc776SDavid Howells */
afs_sleep_and_retry(struct afs_operation * op)90a310082fSDavid Howells static bool afs_sleep_and_retry(struct afs_operation *op)
91d2ddc776SDavid Howells {
92e49c7b2fSDavid Howells if (!(op->flags & AFS_OPERATION_UNINTR)) {
93d2ddc776SDavid Howells msleep_interruptible(1000);
94d2ddc776SDavid Howells if (signal_pending(current)) {
95a310082fSDavid Howells op->error = -ERESTARTSYS;
96d2ddc776SDavid Howells return false;
97d2ddc776SDavid Howells }
9820b8391fSDavid Howells } else {
9920b8391fSDavid Howells msleep(1000);
10020b8391fSDavid Howells }
101d2ddc776SDavid Howells
102d2ddc776SDavid Howells return true;
103d2ddc776SDavid Howells }
104d2ddc776SDavid Howells
105d2ddc776SDavid Howells /*
106d2ddc776SDavid Howells * Select the fileserver to use. May be called multiple times to rotate
107d2ddc776SDavid Howells * through the fileservers.
108d2ddc776SDavid Howells */
afs_select_fileserver(struct afs_operation * op)109a310082fSDavid Howells bool afs_select_fileserver(struct afs_operation *op)
110d2ddc776SDavid Howells {
111d2ddc776SDavid Howells struct afs_addr_list *alist;
112d2ddc776SDavid Howells struct afs_server *server;
113e49c7b2fSDavid Howells struct afs_vnode *vnode = op->file[0].vnode;
1144584ae96SDavid Howells struct afs_error e;
1154584ae96SDavid Howells u32 rtt;
116a310082fSDavid Howells int error = op->ac.error, i;
117d2ddc776SDavid Howells
1183bf0fb6fSDavid Howells _enter("%lx[%d],%lx[%d],%d,%d",
119a310082fSDavid Howells op->untried, op->index,
120a310082fSDavid Howells op->ac.tried, op->ac.index,
121a310082fSDavid Howells error, op->ac.abort_code);
122d2ddc776SDavid Howells
123a310082fSDavid Howells if (op->flags & AFS_OPERATION_STOP) {
124d2ddc776SDavid Howells _leave(" = f [stopped]");
125d2ddc776SDavid Howells return false;
126d2ddc776SDavid Howells }
127d2ddc776SDavid Howells
128a310082fSDavid Howells op->nr_iterations++;
129744bcd71SDavid Howells
130d2ddc776SDavid Howells /* Evaluate the result of the previous operation, if there was one. */
131e7f680f4SDavid Howells switch (error) {
132d2ddc776SDavid Howells case SHRT_MAX:
133d2ddc776SDavid Howells goto start;
134d2ddc776SDavid Howells
135d2ddc776SDavid Howells case 0:
136d2ddc776SDavid Howells default:
137d2ddc776SDavid Howells /* Success or local failure. Stop. */
138a310082fSDavid Howells op->error = error;
139a310082fSDavid Howells op->flags |= AFS_OPERATION_STOP;
140e7f680f4SDavid Howells _leave(" = f [okay/local %d]", error);
141d2ddc776SDavid Howells return false;
142d2ddc776SDavid Howells
143d2ddc776SDavid Howells case -ECONNABORTED:
144d2ddc776SDavid Howells /* The far side rejected the operation on some grounds. This
145d2ddc776SDavid Howells * might involve the server being busy or the volume having been moved.
146d2ddc776SDavid Howells */
147a310082fSDavid Howells switch (op->ac.abort_code) {
148d2ddc776SDavid Howells case VNOVOL:
149d2ddc776SDavid Howells /* This fileserver doesn't know about the volume.
150d2ddc776SDavid Howells * - May indicate that the VL is wrong - retry once and compare
151d2ddc776SDavid Howells * the results.
152d2ddc776SDavid Howells * - May indicate that the fileserver couldn't attach to the vol.
153d2ddc776SDavid Howells */
154a310082fSDavid Howells if (op->flags & AFS_OPERATION_VNOVOL) {
155a310082fSDavid Howells op->error = -EREMOTEIO;
1563d9fa911SDavid Howells goto next_server;
157d2ddc776SDavid Howells }
158d2ddc776SDavid Howells
159e49c7b2fSDavid Howells write_lock(&op->volume->servers_lock);
160a310082fSDavid Howells op->server_list->vnovol_mask |= 1 << op->index;
161e49c7b2fSDavid Howells write_unlock(&op->volume->servers_lock);
162d2ddc776SDavid Howells
163e49c7b2fSDavid Howells set_bit(AFS_VOLUME_NEEDS_UPDATE, &op->volume->flags);
164e49c7b2fSDavid Howells error = afs_check_volume_status(op->volume, op);
165e7f680f4SDavid Howells if (error < 0)
166e7f680f4SDavid Howells goto failed_set_error;
167d2ddc776SDavid Howells
168e49c7b2fSDavid Howells if (test_bit(AFS_VOLUME_DELETED, &op->volume->flags)) {
169a310082fSDavid Howells op->error = -ENOMEDIUM;
170d2ddc776SDavid Howells goto failed;
171d2ddc776SDavid Howells }
172d2ddc776SDavid Howells
173d2ddc776SDavid Howells /* If the server list didn't change, then assume that
174d2ddc776SDavid Howells * it's the fileserver having trouble.
175d2ddc776SDavid Howells */
1768a070a96SDavid Howells if (rcu_access_pointer(op->volume->servers) == op->server_list) {
177a310082fSDavid Howells op->error = -EREMOTEIO;
1783d9fa911SDavid Howells goto next_server;
179d2ddc776SDavid Howells }
180d2ddc776SDavid Howells
181d2ddc776SDavid Howells /* Try again */
182a310082fSDavid Howells op->flags |= AFS_OPERATION_VNOVOL;
183d2ddc776SDavid Howells _leave(" = t [vnovol]");
184d2ddc776SDavid Howells return true;
185d2ddc776SDavid Howells
186d2ddc776SDavid Howells case VSALVAGE: /* TODO: Should this return an error or iterate? */
187d2ddc776SDavid Howells case VVOLEXISTS:
188d2ddc776SDavid Howells case VNOSERVICE:
189d2ddc776SDavid Howells case VONLINE:
190d2ddc776SDavid Howells case VDISKFULL:
191d2ddc776SDavid Howells case VOVERQUOTA:
192a310082fSDavid Howells op->error = afs_abort_to_error(op->ac.abort_code);
193d2ddc776SDavid Howells goto next_server;
194d2ddc776SDavid Howells
195d2ddc776SDavid Howells case VOFFLINE:
196e49c7b2fSDavid Howells if (!test_and_set_bit(AFS_VOLUME_OFFLINE, &op->volume->flags)) {
197e49c7b2fSDavid Howells afs_busy(op->volume, op->ac.abort_code);
198e49c7b2fSDavid Howells clear_bit(AFS_VOLUME_BUSY, &op->volume->flags);
199d2ddc776SDavid Howells }
200a310082fSDavid Howells if (op->flags & AFS_OPERATION_NO_VSLEEP) {
201a310082fSDavid Howells op->error = -EADV;
202d2ddc776SDavid Howells goto failed;
203d2ddc776SDavid Howells }
204a310082fSDavid Howells if (op->flags & AFS_OPERATION_CUR_ONLY) {
205a310082fSDavid Howells op->error = -ESTALE;
206d2ddc776SDavid Howells goto failed;
207d2ddc776SDavid Howells }
208d2ddc776SDavid Howells goto busy;
209d2ddc776SDavid Howells
210d2ddc776SDavid Howells case VSALVAGING:
211d2ddc776SDavid Howells case VRESTARTING:
212d2ddc776SDavid Howells case VBUSY:
213d2ddc776SDavid Howells /* Retry after going round all the servers unless we
214d2ddc776SDavid Howells * have a file lock we need to maintain.
215d2ddc776SDavid Howells */
216a310082fSDavid Howells if (op->flags & AFS_OPERATION_NO_VSLEEP) {
217a310082fSDavid Howells op->error = -EBUSY;
218d2ddc776SDavid Howells goto failed;
219d2ddc776SDavid Howells }
220e49c7b2fSDavid Howells if (!test_and_set_bit(AFS_VOLUME_BUSY, &op->volume->flags)) {
221e49c7b2fSDavid Howells afs_busy(op->volume, op->ac.abort_code);
222e49c7b2fSDavid Howells clear_bit(AFS_VOLUME_OFFLINE, &op->volume->flags);
223d2ddc776SDavid Howells }
224d2ddc776SDavid Howells busy:
225a310082fSDavid Howells if (op->flags & AFS_OPERATION_CUR_ONLY) {
226a310082fSDavid Howells if (!afs_sleep_and_retry(op))
227d2ddc776SDavid Howells goto failed;
228d2ddc776SDavid Howells
229d2ddc776SDavid Howells /* Retry with same server & address */
230d2ddc776SDavid Howells _leave(" = t [vbusy]");
231d2ddc776SDavid Howells return true;
232d2ddc776SDavid Howells }
233d2ddc776SDavid Howells
234a310082fSDavid Howells op->flags |= AFS_OPERATION_VBUSY;
235d2ddc776SDavid Howells goto next_server;
236d2ddc776SDavid Howells
237d2ddc776SDavid Howells case VMOVED:
238d2ddc776SDavid Howells /* The volume migrated to another server. We consider
239d2ddc776SDavid Howells * consider all locks and callbacks broken and request
240d2ddc776SDavid Howells * an update from the VLDB.
241d2ddc776SDavid Howells *
242d2ddc776SDavid Howells * We also limit the number of VMOVED hops we will
243d2ddc776SDavid Howells * honour, just in case someone sets up a loop.
244d2ddc776SDavid Howells */
245a310082fSDavid Howells if (op->flags & AFS_OPERATION_VMOVED) {
246a310082fSDavid Howells op->error = -EREMOTEIO;
247d2ddc776SDavid Howells goto failed;
248d2ddc776SDavid Howells }
249a310082fSDavid Howells op->flags |= AFS_OPERATION_VMOVED;
250d2ddc776SDavid Howells
251e49c7b2fSDavid Howells set_bit(AFS_VOLUME_WAIT, &op->volume->flags);
252e49c7b2fSDavid Howells set_bit(AFS_VOLUME_NEEDS_UPDATE, &op->volume->flags);
253e49c7b2fSDavid Howells error = afs_check_volume_status(op->volume, op);
254e7f680f4SDavid Howells if (error < 0)
255e7f680f4SDavid Howells goto failed_set_error;
256d2ddc776SDavid Howells
257d2ddc776SDavid Howells /* If the server list didn't change, then the VLDB is
258d2ddc776SDavid Howells * out of sync with the fileservers. This is hopefully
259d2ddc776SDavid Howells * a temporary condition, however, so we don't want to
260d2ddc776SDavid Howells * permanently block access to the file.
261d2ddc776SDavid Howells *
262d2ddc776SDavid Howells * TODO: Try other fileservers if we can.
263d2ddc776SDavid Howells *
264d2ddc776SDavid Howells * TODO: Retry a few times with sleeps.
265d2ddc776SDavid Howells */
2668a070a96SDavid Howells if (rcu_access_pointer(op->volume->servers) == op->server_list) {
267a310082fSDavid Howells op->error = -ENOMEDIUM;
268d2ddc776SDavid Howells goto failed;
269d2ddc776SDavid Howells }
270d2ddc776SDavid Howells
271d2ddc776SDavid Howells goto restart_from_beginning;
272d2ddc776SDavid Howells
273d2ddc776SDavid Howells default:
274e49c7b2fSDavid Howells clear_bit(AFS_VOLUME_OFFLINE, &op->volume->flags);
275e49c7b2fSDavid Howells clear_bit(AFS_VOLUME_BUSY, &op->volume->flags);
276a310082fSDavid Howells op->error = afs_abort_to_error(op->ac.abort_code);
277d2ddc776SDavid Howells goto failed;
278d2ddc776SDavid Howells }
279d2ddc776SDavid Howells
280e7f680f4SDavid Howells case -ETIMEDOUT:
281e7f680f4SDavid Howells case -ETIME:
282a310082fSDavid Howells if (op->error != -EDESTADDRREQ)
283e7f680f4SDavid Howells goto iterate_address;
284df561f66SGustavo A. R. Silva fallthrough;
2854584ae96SDavid Howells case -ERFKILL:
2864584ae96SDavid Howells case -EADDRNOTAVAIL:
287d2ddc776SDavid Howells case -ENETUNREACH:
288d2ddc776SDavid Howells case -EHOSTUNREACH:
2894584ae96SDavid Howells case -EHOSTDOWN:
290d2ddc776SDavid Howells case -ECONNREFUSED:
291d2ddc776SDavid Howells _debug("no conn");
292a310082fSDavid Howells op->error = error;
293d2ddc776SDavid Howells goto iterate_address;
2941a025028SDavid Howells
295*adc9613fSDavid Howells case -ENETRESET:
296*adc9613fSDavid Howells pr_warn("kAFS: Peer reset %s (op=%x)\n",
297*adc9613fSDavid Howells op->type ? op->type->name : "???", op->debug_id);
298*adc9613fSDavid Howells fallthrough;
2991a025028SDavid Howells case -ECONNRESET:
3001a025028SDavid Howells _debug("call reset");
301a310082fSDavid Howells op->error = error;
3021a025028SDavid Howells goto failed;
303d2ddc776SDavid Howells }
304d2ddc776SDavid Howells
305d2ddc776SDavid Howells restart_from_beginning:
306d2ddc776SDavid Howells _debug("restart");
307a310082fSDavid Howells afs_end_cursor(&op->ac);
30820325960SDavid Howells op->server = NULL;
309e49c7b2fSDavid Howells afs_put_serverlist(op->net, op->server_list);
310a310082fSDavid Howells op->server_list = NULL;
311d2ddc776SDavid Howells start:
312d2ddc776SDavid Howells _debug("start");
313d2ddc776SDavid Howells /* See if we need to do an update of the volume record. Note that the
314d2ddc776SDavid Howells * volume may have moved or even have been deleted.
315d2ddc776SDavid Howells */
316e49c7b2fSDavid Howells error = afs_check_volume_status(op->volume, op);
317e7f680f4SDavid Howells if (error < 0)
318e7f680f4SDavid Howells goto failed_set_error;
319d2ddc776SDavid Howells
320a310082fSDavid Howells if (!afs_start_fs_iteration(op, vnode))
321d2ddc776SDavid Howells goto failed;
322d2ddc776SDavid Howells
323e49c7b2fSDavid Howells _debug("__ VOL %llx __", op->volume->vid);
3243bf0fb6fSDavid Howells
3253bf0fb6fSDavid Howells pick_server:
326a310082fSDavid Howells _debug("pick [%lx]", op->untried);
3273bf0fb6fSDavid Howells
328a310082fSDavid Howells error = afs_wait_for_fs_probes(op->server_list, op->untried);
3293bf0fb6fSDavid Howells if (error < 0)
3303bf0fb6fSDavid Howells goto failed_set_error;
3313bf0fb6fSDavid Howells
3323bf0fb6fSDavid Howells /* Pick the untried server with the lowest RTT. If we have outstanding
3333bf0fb6fSDavid Howells * callbacks, we stick with the server we're already using if we can.
3343bf0fb6fSDavid Howells */
33520325960SDavid Howells if (op->server) {
33620325960SDavid Howells _debug("server %u", op->index);
337a310082fSDavid Howells if (test_bit(op->index, &op->untried))
3383bf0fb6fSDavid Howells goto selected_server;
33920325960SDavid Howells op->server = NULL;
34020325960SDavid Howells _debug("no server");
3413bf0fb6fSDavid Howells }
3423bf0fb6fSDavid Howells
343a310082fSDavid Howells op->index = -1;
3443bf0fb6fSDavid Howells rtt = U32_MAX;
345a310082fSDavid Howells for (i = 0; i < op->server_list->nr_servers; i++) {
346a310082fSDavid Howells struct afs_server *s = op->server_list->servers[i].server;
3473bf0fb6fSDavid Howells
348f3c130e6SDavid Howells if (!test_bit(i, &op->untried) ||
349f3c130e6SDavid Howells !test_bit(AFS_SERVER_FL_RESPONDING, &s->flags))
3503bf0fb6fSDavid Howells continue;
3513bf0fb6fSDavid Howells if (s->probe.rtt < rtt) {
352a310082fSDavid Howells op->index = i;
3533bf0fb6fSDavid Howells rtt = s->probe.rtt;
3543bf0fb6fSDavid Howells }
3553bf0fb6fSDavid Howells }
3563bf0fb6fSDavid Howells
357a310082fSDavid Howells if (op->index == -1)
3583bf0fb6fSDavid Howells goto no_more_servers;
3593bf0fb6fSDavid Howells
3603bf0fb6fSDavid Howells selected_server:
361a310082fSDavid Howells _debug("use %d", op->index);
362a310082fSDavid Howells __clear_bit(op->index, &op->untried);
3633bf0fb6fSDavid Howells
364d2ddc776SDavid Howells /* We're starting on a different fileserver from the list. We need to
365d2ddc776SDavid Howells * check it, create a callback intercept, find its address list and
366d2ddc776SDavid Howells * probe its capabilities before we use it.
367d2ddc776SDavid Howells */
368a310082fSDavid Howells ASSERTCMP(op->ac.alist, ==, NULL);
369a310082fSDavid Howells server = op->server_list->servers[op->index].server;
370d2ddc776SDavid Howells
371a310082fSDavid Howells if (!afs_check_server_record(op, server))
372d2ddc776SDavid Howells goto failed;
373d2ddc776SDavid Howells
374d2ddc776SDavid Howells _debug("USING SERVER: %pU", &server->uuid);
375d2ddc776SDavid Howells
3768409f67bSDavid Howells op->flags |= AFS_OPERATION_RETRY_SERVER;
37720325960SDavid Howells op->server = server;
37820325960SDavid Howells if (vnode->cb_server != server) {
37920325960SDavid Howells vnode->cb_server = server;
38020325960SDavid Howells vnode->cb_s_break = server->cb_s_break;
3814fe6a946SDavid Howells vnode->cb_fs_s_break = atomic_read(&server->cell->fs_s_break);
38220325960SDavid Howells vnode->cb_v_break = vnode->volume->cb_v_break;
38320325960SDavid Howells clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);
38420325960SDavid Howells }
385d2ddc776SDavid Howells
386d2ddc776SDavid Howells read_lock(&server->fs_lock);
387d2ddc776SDavid Howells alist = rcu_dereference_protected(server->addresses,
388d2ddc776SDavid Howells lockdep_is_held(&server->fs_lock));
389d2ddc776SDavid Howells afs_get_addrlist(alist);
390d2ddc776SDavid Howells read_unlock(&server->fs_lock);
391d2ddc776SDavid Howells
3928409f67bSDavid Howells retry_server:
393a310082fSDavid Howells memset(&op->ac, 0, sizeof(op->ac));
394d2ddc776SDavid Howells
395a310082fSDavid Howells if (!op->ac.alist)
396a310082fSDavid Howells op->ac.alist = alist;
397d2ddc776SDavid Howells else
398d2ddc776SDavid Howells afs_put_addrlist(alist);
399d2ddc776SDavid Howells
400a310082fSDavid Howells op->ac.index = -1;
401d2ddc776SDavid Howells
402d2ddc776SDavid Howells iterate_address:
403a310082fSDavid Howells ASSERT(op->ac.alist);
404d2ddc776SDavid Howells /* Iterate over the current server's address list to try and find an
405d2ddc776SDavid Howells * address on which it will respond to us.
406d2ddc776SDavid Howells */
407a310082fSDavid Howells if (!afs_iterate_addresses(&op->ac))
4088409f67bSDavid Howells goto out_of_addresses;
409fe4d774cSDavid Howells
4108409f67bSDavid Howells _debug("address [%u] %u/%u %pISp",
4118409f67bSDavid Howells op->index, op->ac.index, op->ac.alist->nr_addrs,
4128409f67bSDavid Howells &op->ac.alist->addrs[op->ac.index].transport);
4133bf0fb6fSDavid Howells
414d2ddc776SDavid Howells _leave(" = t");
415d2ddc776SDavid Howells return true;
416d2ddc776SDavid Howells
4178409f67bSDavid Howells out_of_addresses:
4188409f67bSDavid Howells /* We've now had a failure to respond on all of a server's addresses -
4198409f67bSDavid Howells * immediately probe them again and consider retrying the server.
4208409f67bSDavid Howells */
4218409f67bSDavid Howells afs_probe_fileserver(op->net, op->server);
4228409f67bSDavid Howells if (op->flags & AFS_OPERATION_RETRY_SERVER) {
4238409f67bSDavid Howells alist = op->ac.alist;
4248409f67bSDavid Howells error = afs_wait_for_one_fs_probe(
4258409f67bSDavid Howells op->server, !(op->flags & AFS_OPERATION_UNINTR));
4268409f67bSDavid Howells switch (error) {
4278409f67bSDavid Howells case 0:
4288409f67bSDavid Howells op->flags &= ~AFS_OPERATION_RETRY_SERVER;
4298409f67bSDavid Howells goto retry_server;
4308409f67bSDavid Howells case -ERESTARTSYS:
4318409f67bSDavid Howells goto failed_set_error;
4328409f67bSDavid Howells case -ETIME:
4338409f67bSDavid Howells case -EDESTADDRREQ:
4348409f67bSDavid Howells goto next_server;
4358409f67bSDavid Howells }
4368409f67bSDavid Howells }
4378409f67bSDavid Howells
43816280a15SDavid Howells next_server:
43916280a15SDavid Howells _debug("next");
440a310082fSDavid Howells afs_end_cursor(&op->ac);
4413bf0fb6fSDavid Howells goto pick_server;
44216280a15SDavid Howells
4433bf0fb6fSDavid Howells no_more_servers:
44416280a15SDavid Howells /* That's all the servers poked to no good effect. Try again if some
44516280a15SDavid Howells * of them were busy.
44616280a15SDavid Howells */
447a310082fSDavid Howells if (op->flags & AFS_OPERATION_VBUSY)
44816280a15SDavid Howells goto restart_from_beginning;
44916280a15SDavid Howells
4504584ae96SDavid Howells e.error = -EDESTADDRREQ;
4514584ae96SDavid Howells e.responded = false;
452a310082fSDavid Howells for (i = 0; i < op->server_list->nr_servers; i++) {
453a310082fSDavid Howells struct afs_server *s = op->server_list->servers[i].server;
4543bf0fb6fSDavid Howells
4554584ae96SDavid Howells afs_prioritise_error(&e, READ_ONCE(s->probe.error),
4564584ae96SDavid Howells s->probe.abort_code);
4573bf0fb6fSDavid Howells }
45816280a15SDavid Howells
45951eba999SDavid Howells error = e.error;
46051eba999SDavid Howells
461e7f680f4SDavid Howells failed_set_error:
462a310082fSDavid Howells op->error = error;
463d2ddc776SDavid Howells failed:
464a310082fSDavid Howells op->flags |= AFS_OPERATION_STOP;
465a310082fSDavid Howells afs_end_cursor(&op->ac);
466a310082fSDavid Howells _leave(" = f [failed %d]", op->error);
467d2ddc776SDavid Howells return false;
468d2ddc776SDavid Howells }
469d2ddc776SDavid Howells
470d2ddc776SDavid Howells /*
471744bcd71SDavid Howells * Dump cursor state in the case of the error being EDESTADDRREQ.
472744bcd71SDavid Howells */
afs_dump_edestaddrreq(const struct afs_operation * op)473e49c7b2fSDavid Howells void afs_dump_edestaddrreq(const struct afs_operation *op)
474744bcd71SDavid Howells {
475744bcd71SDavid Howells static int count;
476744bcd71SDavid Howells int i;
477744bcd71SDavid Howells
478744bcd71SDavid Howells if (!IS_ENABLED(CONFIG_AFS_DEBUG_CURSOR) || count > 3)
479744bcd71SDavid Howells return;
480744bcd71SDavid Howells count++;
481744bcd71SDavid Howells
482744bcd71SDavid Howells rcu_read_lock();
483744bcd71SDavid Howells
484744bcd71SDavid Howells pr_notice("EDESTADDR occurred\n");
485e49c7b2fSDavid Howells pr_notice("FC: cbb=%x cbb2=%x fl=%x err=%hd\n",
486e49c7b2fSDavid Howells op->file[0].cb_break_before,
487e49c7b2fSDavid Howells op->file[1].cb_break_before, op->flags, op->error);
4883bf0fb6fSDavid Howells pr_notice("FC: ut=%lx ix=%d ni=%u\n",
489a310082fSDavid Howells op->untried, op->index, op->nr_iterations);
490744bcd71SDavid Howells
491a310082fSDavid Howells if (op->server_list) {
492a310082fSDavid Howells const struct afs_server_list *sl = op->server_list;
4933bf0fb6fSDavid Howells pr_notice("FC: SL nr=%u pr=%u vnov=%hx\n",
4943bf0fb6fSDavid Howells sl->nr_servers, sl->preferred, sl->vnovol_mask);
495744bcd71SDavid Howells for (i = 0; i < sl->nr_servers; i++) {
496744bcd71SDavid Howells const struct afs_server *s = sl->servers[i].server;
497744bcd71SDavid Howells pr_notice("FC: server fl=%lx av=%u %pU\n",
498744bcd71SDavid Howells s->flags, s->addr_version, &s->uuid);
499744bcd71SDavid Howells if (s->addresses) {
500744bcd71SDavid Howells const struct afs_addr_list *a =
501744bcd71SDavid Howells rcu_dereference(s->addresses);
5023bf0fb6fSDavid Howells pr_notice("FC: - av=%u nr=%u/%u/%u pr=%u\n",
503744bcd71SDavid Howells a->version,
504744bcd71SDavid Howells a->nr_ipv4, a->nr_addrs, a->max_addrs,
5053bf0fb6fSDavid Howells a->preferred);
506f6cbb368SDavid Howells pr_notice("FC: - R=%lx F=%lx\n",
507f6cbb368SDavid Howells a->responded, a->failed);
508a310082fSDavid Howells if (a == op->ac.alist)
509744bcd71SDavid Howells pr_notice("FC: - current\n");
510744bcd71SDavid Howells }
511744bcd71SDavid Howells }
512744bcd71SDavid Howells }
513744bcd71SDavid Howells
5143bf0fb6fSDavid Howells pr_notice("AC: t=%lx ax=%u ac=%d er=%d r=%u ni=%u\n",
515a310082fSDavid Howells op->ac.tried, op->ac.index, op->ac.abort_code, op->ac.error,
516a310082fSDavid Howells op->ac.responded, op->ac.nr_iterations);
517744bcd71SDavid Howells rcu_read_unlock();
518744bcd71SDavid Howells }
519