18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/* Handle fileserver selection and rotation.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved.
58c2ecf20Sopenharmony_ci * Written by David Howells (dhowells@redhat.com)
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/kernel.h>
98c2ecf20Sopenharmony_ci#include <linux/slab.h>
108c2ecf20Sopenharmony_ci#include <linux/fs.h>
118c2ecf20Sopenharmony_ci#include <linux/sched.h>
128c2ecf20Sopenharmony_ci#include <linux/delay.h>
138c2ecf20Sopenharmony_ci#include <linux/sched/signal.h>
148c2ecf20Sopenharmony_ci#include "internal.h"
158c2ecf20Sopenharmony_ci#include "afs_fs.h"
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci/*
188c2ecf20Sopenharmony_ci * Begin iteration through a server list, starting with the vnode's last used
198c2ecf20Sopenharmony_ci * server if possible, or the last recorded good server if not.
208c2ecf20Sopenharmony_ci */
218c2ecf20Sopenharmony_cistatic bool afs_start_fs_iteration(struct afs_operation *op,
228c2ecf20Sopenharmony_ci				   struct afs_vnode *vnode)
238c2ecf20Sopenharmony_ci{
248c2ecf20Sopenharmony_ci	struct afs_server *server;
258c2ecf20Sopenharmony_ci	void *cb_server;
268c2ecf20Sopenharmony_ci	int i;
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci	read_lock(&op->volume->servers_lock);
298c2ecf20Sopenharmony_ci	op->server_list = afs_get_serverlist(
308c2ecf20Sopenharmony_ci		rcu_dereference_protected(op->volume->servers,
318c2ecf20Sopenharmony_ci					  lockdep_is_held(&op->volume->servers_lock)));
328c2ecf20Sopenharmony_ci	read_unlock(&op->volume->servers_lock);
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	op->untried = (1UL << op->server_list->nr_servers) - 1;
358c2ecf20Sopenharmony_ci	op->index = READ_ONCE(op->server_list->preferred);
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	cb_server = vnode->cb_server;
388c2ecf20Sopenharmony_ci	if (cb_server) {
398c2ecf20Sopenharmony_ci		/* See if the vnode's preferred record is still available */
408c2ecf20Sopenharmony_ci		for (i = 0; i < op->server_list->nr_servers; i++) {
418c2ecf20Sopenharmony_ci			server = op->server_list->servers[i].server;
428c2ecf20Sopenharmony_ci			if (server == cb_server) {
438c2ecf20Sopenharmony_ci				op->index = i;
448c2ecf20Sopenharmony_ci				goto found_interest;
458c2ecf20Sopenharmony_ci			}
468c2ecf20Sopenharmony_ci		}
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci		/* If we have a lock outstanding on a server that's no longer
498c2ecf20Sopenharmony_ci		 * serving this vnode, then we can't switch to another server
508c2ecf20Sopenharmony_ci		 * and have to return an error.
518c2ecf20Sopenharmony_ci		 */
528c2ecf20Sopenharmony_ci		if (op->flags & AFS_OPERATION_CUR_ONLY) {
538c2ecf20Sopenharmony_ci			op->error = -ESTALE;
548c2ecf20Sopenharmony_ci			return false;
558c2ecf20Sopenharmony_ci		}
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci		/* Note that the callback promise is effectively broken */
588c2ecf20Sopenharmony_ci		write_seqlock(&vnode->cb_lock);
598c2ecf20Sopenharmony_ci		ASSERTCMP(cb_server, ==, vnode->cb_server);
608c2ecf20Sopenharmony_ci		vnode->cb_server = NULL;
618c2ecf20Sopenharmony_ci		if (test_and_clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags))
628c2ecf20Sopenharmony_ci			vnode->cb_break++;
638c2ecf20Sopenharmony_ci		write_sequnlock(&vnode->cb_lock);
648c2ecf20Sopenharmony_ci	}
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cifound_interest:
678c2ecf20Sopenharmony_ci	return true;
688c2ecf20Sopenharmony_ci}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci/*
718c2ecf20Sopenharmony_ci * Post volume busy note.
728c2ecf20Sopenharmony_ci */
738c2ecf20Sopenharmony_cistatic void afs_busy(struct afs_volume *volume, u32 abort_code)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	const char *m;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	switch (abort_code) {
788c2ecf20Sopenharmony_ci	case VOFFLINE:		m = "offline";		break;
798c2ecf20Sopenharmony_ci	case VRESTARTING:	m = "restarting";	break;
808c2ecf20Sopenharmony_ci	case VSALVAGING:	m = "being salvaged";	break;
818c2ecf20Sopenharmony_ci	default:		m = "busy";		break;
828c2ecf20Sopenharmony_ci	}
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	pr_notice("kAFS: Volume %llu '%s' is %s\n", volume->vid, volume->name, m);
858c2ecf20Sopenharmony_ci}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci/*
888c2ecf20Sopenharmony_ci * Sleep and retry the operation to the same fileserver.
898c2ecf20Sopenharmony_ci */
908c2ecf20Sopenharmony_cistatic bool afs_sleep_and_retry(struct afs_operation *op)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	if (!(op->flags & AFS_OPERATION_UNINTR)) {
938c2ecf20Sopenharmony_ci		msleep_interruptible(1000);
948c2ecf20Sopenharmony_ci		if (signal_pending(current)) {
958c2ecf20Sopenharmony_ci			op->error = -ERESTARTSYS;
968c2ecf20Sopenharmony_ci			return false;
978c2ecf20Sopenharmony_ci		}
988c2ecf20Sopenharmony_ci	} else {
998c2ecf20Sopenharmony_ci		msleep(1000);
1008c2ecf20Sopenharmony_ci	}
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	return true;
1038c2ecf20Sopenharmony_ci}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci/*
1068c2ecf20Sopenharmony_ci * Select the fileserver to use.  May be called multiple times to rotate
1078c2ecf20Sopenharmony_ci * through the fileservers.
1088c2ecf20Sopenharmony_ci */
1098c2ecf20Sopenharmony_cibool afs_select_fileserver(struct afs_operation *op)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	struct afs_addr_list *alist;
1128c2ecf20Sopenharmony_ci	struct afs_server *server;
1138c2ecf20Sopenharmony_ci	struct afs_vnode *vnode = op->file[0].vnode;
1148c2ecf20Sopenharmony_ci	struct afs_error e;
1158c2ecf20Sopenharmony_ci	u32 rtt;
1168c2ecf20Sopenharmony_ci	int error = op->ac.error, i;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	_enter("%lx[%d],%lx[%d],%d,%d",
1198c2ecf20Sopenharmony_ci	       op->untried, op->index,
1208c2ecf20Sopenharmony_ci	       op->ac.tried, op->ac.index,
1218c2ecf20Sopenharmony_ci	       error, op->ac.abort_code);
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	if (op->flags & AFS_OPERATION_STOP) {
1248c2ecf20Sopenharmony_ci		_leave(" = f [stopped]");
1258c2ecf20Sopenharmony_ci		return false;
1268c2ecf20Sopenharmony_ci	}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	op->nr_iterations++;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	/* Evaluate the result of the previous operation, if there was one. */
1318c2ecf20Sopenharmony_ci	switch (error) {
1328c2ecf20Sopenharmony_ci	case SHRT_MAX:
1338c2ecf20Sopenharmony_ci		goto start;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	case 0:
1368c2ecf20Sopenharmony_ci	default:
1378c2ecf20Sopenharmony_ci		/* Success or local failure.  Stop. */
1388c2ecf20Sopenharmony_ci		op->error = error;
1398c2ecf20Sopenharmony_ci		op->flags |= AFS_OPERATION_STOP;
1408c2ecf20Sopenharmony_ci		_leave(" = f [okay/local %d]", error);
1418c2ecf20Sopenharmony_ci		return false;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	case -ECONNABORTED:
1448c2ecf20Sopenharmony_ci		/* The far side rejected the operation on some grounds.  This
1458c2ecf20Sopenharmony_ci		 * might involve the server being busy or the volume having been moved.
1468c2ecf20Sopenharmony_ci		 */
1478c2ecf20Sopenharmony_ci		switch (op->ac.abort_code) {
1488c2ecf20Sopenharmony_ci		case VNOVOL:
1498c2ecf20Sopenharmony_ci			/* This fileserver doesn't know about the volume.
1508c2ecf20Sopenharmony_ci			 * - May indicate that the VL is wrong - retry once and compare
1518c2ecf20Sopenharmony_ci			 *   the results.
1528c2ecf20Sopenharmony_ci			 * - May indicate that the fileserver couldn't attach to the vol.
1538c2ecf20Sopenharmony_ci			 */
1548c2ecf20Sopenharmony_ci			if (op->flags & AFS_OPERATION_VNOVOL) {
1558c2ecf20Sopenharmony_ci				op->error = -EREMOTEIO;
1568c2ecf20Sopenharmony_ci				goto next_server;
1578c2ecf20Sopenharmony_ci			}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci			write_lock(&op->volume->servers_lock);
1608c2ecf20Sopenharmony_ci			op->server_list->vnovol_mask |= 1 << op->index;
1618c2ecf20Sopenharmony_ci			write_unlock(&op->volume->servers_lock);
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci			set_bit(AFS_VOLUME_NEEDS_UPDATE, &op->volume->flags);
1648c2ecf20Sopenharmony_ci			error = afs_check_volume_status(op->volume, op);
1658c2ecf20Sopenharmony_ci			if (error < 0)
1668c2ecf20Sopenharmony_ci				goto failed_set_error;
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci			if (test_bit(AFS_VOLUME_DELETED, &op->volume->flags)) {
1698c2ecf20Sopenharmony_ci				op->error = -ENOMEDIUM;
1708c2ecf20Sopenharmony_ci				goto failed;
1718c2ecf20Sopenharmony_ci			}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci			/* If the server list didn't change, then assume that
1748c2ecf20Sopenharmony_ci			 * it's the fileserver having trouble.
1758c2ecf20Sopenharmony_ci			 */
1768c2ecf20Sopenharmony_ci			if (rcu_access_pointer(op->volume->servers) == op->server_list) {
1778c2ecf20Sopenharmony_ci				op->error = -EREMOTEIO;
1788c2ecf20Sopenharmony_ci				goto next_server;
1798c2ecf20Sopenharmony_ci			}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci			/* Try again */
1828c2ecf20Sopenharmony_ci			op->flags |= AFS_OPERATION_VNOVOL;
1838c2ecf20Sopenharmony_ci			_leave(" = t [vnovol]");
1848c2ecf20Sopenharmony_ci			return true;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci		case VSALVAGE: /* TODO: Should this return an error or iterate? */
1878c2ecf20Sopenharmony_ci		case VVOLEXISTS:
1888c2ecf20Sopenharmony_ci		case VNOSERVICE:
1898c2ecf20Sopenharmony_ci		case VONLINE:
1908c2ecf20Sopenharmony_ci		case VDISKFULL:
1918c2ecf20Sopenharmony_ci		case VOVERQUOTA:
1928c2ecf20Sopenharmony_ci			op->error = afs_abort_to_error(op->ac.abort_code);
1938c2ecf20Sopenharmony_ci			goto next_server;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci		case VOFFLINE:
1968c2ecf20Sopenharmony_ci			if (!test_and_set_bit(AFS_VOLUME_OFFLINE, &op->volume->flags)) {
1978c2ecf20Sopenharmony_ci				afs_busy(op->volume, op->ac.abort_code);
1988c2ecf20Sopenharmony_ci				clear_bit(AFS_VOLUME_BUSY, &op->volume->flags);
1998c2ecf20Sopenharmony_ci			}
2008c2ecf20Sopenharmony_ci			if (op->flags & AFS_OPERATION_NO_VSLEEP) {
2018c2ecf20Sopenharmony_ci				op->error = -EADV;
2028c2ecf20Sopenharmony_ci				goto failed;
2038c2ecf20Sopenharmony_ci			}
2048c2ecf20Sopenharmony_ci			if (op->flags & AFS_OPERATION_CUR_ONLY) {
2058c2ecf20Sopenharmony_ci				op->error = -ESTALE;
2068c2ecf20Sopenharmony_ci				goto failed;
2078c2ecf20Sopenharmony_ci			}
2088c2ecf20Sopenharmony_ci			goto busy;
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci		case VSALVAGING:
2118c2ecf20Sopenharmony_ci		case VRESTARTING:
2128c2ecf20Sopenharmony_ci		case VBUSY:
2138c2ecf20Sopenharmony_ci			/* Retry after going round all the servers unless we
2148c2ecf20Sopenharmony_ci			 * have a file lock we need to maintain.
2158c2ecf20Sopenharmony_ci			 */
2168c2ecf20Sopenharmony_ci			if (op->flags & AFS_OPERATION_NO_VSLEEP) {
2178c2ecf20Sopenharmony_ci				op->error = -EBUSY;
2188c2ecf20Sopenharmony_ci				goto failed;
2198c2ecf20Sopenharmony_ci			}
2208c2ecf20Sopenharmony_ci			if (!test_and_set_bit(AFS_VOLUME_BUSY, &op->volume->flags)) {
2218c2ecf20Sopenharmony_ci				afs_busy(op->volume, op->ac.abort_code);
2228c2ecf20Sopenharmony_ci				clear_bit(AFS_VOLUME_OFFLINE, &op->volume->flags);
2238c2ecf20Sopenharmony_ci			}
2248c2ecf20Sopenharmony_ci		busy:
2258c2ecf20Sopenharmony_ci			if (op->flags & AFS_OPERATION_CUR_ONLY) {
2268c2ecf20Sopenharmony_ci				if (!afs_sleep_and_retry(op))
2278c2ecf20Sopenharmony_ci					goto failed;
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci				 /* Retry with same server & address */
2308c2ecf20Sopenharmony_ci				_leave(" = t [vbusy]");
2318c2ecf20Sopenharmony_ci				return true;
2328c2ecf20Sopenharmony_ci			}
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci			op->flags |= AFS_OPERATION_VBUSY;
2358c2ecf20Sopenharmony_ci			goto next_server;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci		case VMOVED:
2388c2ecf20Sopenharmony_ci			/* The volume migrated to another server.  We consider
2398c2ecf20Sopenharmony_ci			 * consider all locks and callbacks broken and request
2408c2ecf20Sopenharmony_ci			 * an update from the VLDB.
2418c2ecf20Sopenharmony_ci			 *
2428c2ecf20Sopenharmony_ci			 * We also limit the number of VMOVED hops we will
2438c2ecf20Sopenharmony_ci			 * honour, just in case someone sets up a loop.
2448c2ecf20Sopenharmony_ci			 */
2458c2ecf20Sopenharmony_ci			if (op->flags & AFS_OPERATION_VMOVED) {
2468c2ecf20Sopenharmony_ci				op->error = -EREMOTEIO;
2478c2ecf20Sopenharmony_ci				goto failed;
2488c2ecf20Sopenharmony_ci			}
2498c2ecf20Sopenharmony_ci			op->flags |= AFS_OPERATION_VMOVED;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci			set_bit(AFS_VOLUME_WAIT, &op->volume->flags);
2528c2ecf20Sopenharmony_ci			set_bit(AFS_VOLUME_NEEDS_UPDATE, &op->volume->flags);
2538c2ecf20Sopenharmony_ci			error = afs_check_volume_status(op->volume, op);
2548c2ecf20Sopenharmony_ci			if (error < 0)
2558c2ecf20Sopenharmony_ci				goto failed_set_error;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci			/* If the server list didn't change, then the VLDB is
2588c2ecf20Sopenharmony_ci			 * out of sync with the fileservers.  This is hopefully
2598c2ecf20Sopenharmony_ci			 * a temporary condition, however, so we don't want to
2608c2ecf20Sopenharmony_ci			 * permanently block access to the file.
2618c2ecf20Sopenharmony_ci			 *
2628c2ecf20Sopenharmony_ci			 * TODO: Try other fileservers if we can.
2638c2ecf20Sopenharmony_ci			 *
2648c2ecf20Sopenharmony_ci			 * TODO: Retry a few times with sleeps.
2658c2ecf20Sopenharmony_ci			 */
2668c2ecf20Sopenharmony_ci			if (rcu_access_pointer(op->volume->servers) == op->server_list) {
2678c2ecf20Sopenharmony_ci				op->error = -ENOMEDIUM;
2688c2ecf20Sopenharmony_ci				goto failed;
2698c2ecf20Sopenharmony_ci			}
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci			goto restart_from_beginning;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci		default:
2748c2ecf20Sopenharmony_ci			clear_bit(AFS_VOLUME_OFFLINE, &op->volume->flags);
2758c2ecf20Sopenharmony_ci			clear_bit(AFS_VOLUME_BUSY, &op->volume->flags);
2768c2ecf20Sopenharmony_ci			op->error = afs_abort_to_error(op->ac.abort_code);
2778c2ecf20Sopenharmony_ci			goto failed;
2788c2ecf20Sopenharmony_ci		}
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	case -ETIMEDOUT:
2818c2ecf20Sopenharmony_ci	case -ETIME:
2828c2ecf20Sopenharmony_ci		if (op->error != -EDESTADDRREQ)
2838c2ecf20Sopenharmony_ci			goto iterate_address;
2848c2ecf20Sopenharmony_ci		fallthrough;
2858c2ecf20Sopenharmony_ci	case -ERFKILL:
2868c2ecf20Sopenharmony_ci	case -EADDRNOTAVAIL:
2878c2ecf20Sopenharmony_ci	case -ENETUNREACH:
2888c2ecf20Sopenharmony_ci	case -EHOSTUNREACH:
2898c2ecf20Sopenharmony_ci	case -EHOSTDOWN:
2908c2ecf20Sopenharmony_ci	case -ECONNREFUSED:
2918c2ecf20Sopenharmony_ci		_debug("no conn");
2928c2ecf20Sopenharmony_ci		op->error = error;
2938c2ecf20Sopenharmony_ci		goto iterate_address;
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	case -ECONNRESET:
2968c2ecf20Sopenharmony_ci		_debug("call reset");
2978c2ecf20Sopenharmony_ci		op->error = error;
2988c2ecf20Sopenharmony_ci		goto failed;
2998c2ecf20Sopenharmony_ci	}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_cirestart_from_beginning:
3028c2ecf20Sopenharmony_ci	_debug("restart");
3038c2ecf20Sopenharmony_ci	afs_end_cursor(&op->ac);
3048c2ecf20Sopenharmony_ci	op->server = NULL;
3058c2ecf20Sopenharmony_ci	afs_put_serverlist(op->net, op->server_list);
3068c2ecf20Sopenharmony_ci	op->server_list = NULL;
3078c2ecf20Sopenharmony_cistart:
3088c2ecf20Sopenharmony_ci	_debug("start");
3098c2ecf20Sopenharmony_ci	/* See if we need to do an update of the volume record.  Note that the
3108c2ecf20Sopenharmony_ci	 * volume may have moved or even have been deleted.
3118c2ecf20Sopenharmony_ci	 */
3128c2ecf20Sopenharmony_ci	error = afs_check_volume_status(op->volume, op);
3138c2ecf20Sopenharmony_ci	if (error < 0)
3148c2ecf20Sopenharmony_ci		goto failed_set_error;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	if (!afs_start_fs_iteration(op, vnode))
3178c2ecf20Sopenharmony_ci		goto failed;
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	_debug("__ VOL %llx __", op->volume->vid);
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_cipick_server:
3228c2ecf20Sopenharmony_ci	_debug("pick [%lx]", op->untried);
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	error = afs_wait_for_fs_probes(op->server_list, op->untried);
3258c2ecf20Sopenharmony_ci	if (error < 0)
3268c2ecf20Sopenharmony_ci		goto failed_set_error;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	/* Pick the untried server with the lowest RTT.  If we have outstanding
3298c2ecf20Sopenharmony_ci	 * callbacks, we stick with the server we're already using if we can.
3308c2ecf20Sopenharmony_ci	 */
3318c2ecf20Sopenharmony_ci	if (op->server) {
3328c2ecf20Sopenharmony_ci		_debug("server %u", op->index);
3338c2ecf20Sopenharmony_ci		if (test_bit(op->index, &op->untried))
3348c2ecf20Sopenharmony_ci			goto selected_server;
3358c2ecf20Sopenharmony_ci		op->server = NULL;
3368c2ecf20Sopenharmony_ci		_debug("no server");
3378c2ecf20Sopenharmony_ci	}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	op->index = -1;
3408c2ecf20Sopenharmony_ci	rtt = U32_MAX;
3418c2ecf20Sopenharmony_ci	for (i = 0; i < op->server_list->nr_servers; i++) {
3428c2ecf20Sopenharmony_ci		struct afs_server *s = op->server_list->servers[i].server;
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci		if (!test_bit(i, &op->untried) ||
3458c2ecf20Sopenharmony_ci		    !test_bit(AFS_SERVER_FL_RESPONDING, &s->flags))
3468c2ecf20Sopenharmony_ci			continue;
3478c2ecf20Sopenharmony_ci		if (s->probe.rtt < rtt) {
3488c2ecf20Sopenharmony_ci			op->index = i;
3498c2ecf20Sopenharmony_ci			rtt = s->probe.rtt;
3508c2ecf20Sopenharmony_ci		}
3518c2ecf20Sopenharmony_ci	}
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	if (op->index == -1)
3548c2ecf20Sopenharmony_ci		goto no_more_servers;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ciselected_server:
3578c2ecf20Sopenharmony_ci	_debug("use %d", op->index);
3588c2ecf20Sopenharmony_ci	__clear_bit(op->index, &op->untried);
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	/* We're starting on a different fileserver from the list.  We need to
3618c2ecf20Sopenharmony_ci	 * check it, create a callback intercept, find its address list and
3628c2ecf20Sopenharmony_ci	 * probe its capabilities before we use it.
3638c2ecf20Sopenharmony_ci	 */
3648c2ecf20Sopenharmony_ci	ASSERTCMP(op->ac.alist, ==, NULL);
3658c2ecf20Sopenharmony_ci	server = op->server_list->servers[op->index].server;
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	if (!afs_check_server_record(op, server))
3688c2ecf20Sopenharmony_ci		goto failed;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	_debug("USING SERVER: %pU", &server->uuid);
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	op->flags |= AFS_OPERATION_RETRY_SERVER;
3738c2ecf20Sopenharmony_ci	op->server = server;
3748c2ecf20Sopenharmony_ci	if (vnode->cb_server != server) {
3758c2ecf20Sopenharmony_ci		vnode->cb_server = server;
3768c2ecf20Sopenharmony_ci		vnode->cb_s_break = server->cb_s_break;
3778c2ecf20Sopenharmony_ci		vnode->cb_v_break = vnode->volume->cb_v_break;
3788c2ecf20Sopenharmony_ci		clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);
3798c2ecf20Sopenharmony_ci	}
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	read_lock(&server->fs_lock);
3828c2ecf20Sopenharmony_ci	alist = rcu_dereference_protected(server->addresses,
3838c2ecf20Sopenharmony_ci					  lockdep_is_held(&server->fs_lock));
3848c2ecf20Sopenharmony_ci	afs_get_addrlist(alist);
3858c2ecf20Sopenharmony_ci	read_unlock(&server->fs_lock);
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ciretry_server:
3888c2ecf20Sopenharmony_ci	memset(&op->ac, 0, sizeof(op->ac));
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	if (!op->ac.alist)
3918c2ecf20Sopenharmony_ci		op->ac.alist = alist;
3928c2ecf20Sopenharmony_ci	else
3938c2ecf20Sopenharmony_ci		afs_put_addrlist(alist);
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	op->ac.index = -1;
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ciiterate_address:
3988c2ecf20Sopenharmony_ci	ASSERT(op->ac.alist);
3998c2ecf20Sopenharmony_ci	/* Iterate over the current server's address list to try and find an
4008c2ecf20Sopenharmony_ci	 * address on which it will respond to us.
4018c2ecf20Sopenharmony_ci	 */
4028c2ecf20Sopenharmony_ci	if (!afs_iterate_addresses(&op->ac))
4038c2ecf20Sopenharmony_ci		goto out_of_addresses;
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	_debug("address [%u] %u/%u %pISp",
4068c2ecf20Sopenharmony_ci	       op->index, op->ac.index, op->ac.alist->nr_addrs,
4078c2ecf20Sopenharmony_ci	       &op->ac.alist->addrs[op->ac.index].transport);
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	_leave(" = t");
4108c2ecf20Sopenharmony_ci	return true;
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ciout_of_addresses:
4138c2ecf20Sopenharmony_ci	/* We've now had a failure to respond on all of a server's addresses -
4148c2ecf20Sopenharmony_ci	 * immediately probe them again and consider retrying the server.
4158c2ecf20Sopenharmony_ci	 */
4168c2ecf20Sopenharmony_ci	afs_probe_fileserver(op->net, op->server);
4178c2ecf20Sopenharmony_ci	if (op->flags & AFS_OPERATION_RETRY_SERVER) {
4188c2ecf20Sopenharmony_ci		alist = op->ac.alist;
4198c2ecf20Sopenharmony_ci		error = afs_wait_for_one_fs_probe(
4208c2ecf20Sopenharmony_ci			op->server, !(op->flags & AFS_OPERATION_UNINTR));
4218c2ecf20Sopenharmony_ci		switch (error) {
4228c2ecf20Sopenharmony_ci		case 0:
4238c2ecf20Sopenharmony_ci			op->flags &= ~AFS_OPERATION_RETRY_SERVER;
4248c2ecf20Sopenharmony_ci			goto retry_server;
4258c2ecf20Sopenharmony_ci		case -ERESTARTSYS:
4268c2ecf20Sopenharmony_ci			goto failed_set_error;
4278c2ecf20Sopenharmony_ci		case -ETIME:
4288c2ecf20Sopenharmony_ci		case -EDESTADDRREQ:
4298c2ecf20Sopenharmony_ci			goto next_server;
4308c2ecf20Sopenharmony_ci		}
4318c2ecf20Sopenharmony_ci	}
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_cinext_server:
4348c2ecf20Sopenharmony_ci	_debug("next");
4358c2ecf20Sopenharmony_ci	afs_end_cursor(&op->ac);
4368c2ecf20Sopenharmony_ci	goto pick_server;
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_cino_more_servers:
4398c2ecf20Sopenharmony_ci	/* That's all the servers poked to no good effect.  Try again if some
4408c2ecf20Sopenharmony_ci	 * of them were busy.
4418c2ecf20Sopenharmony_ci	 */
4428c2ecf20Sopenharmony_ci	if (op->flags & AFS_OPERATION_VBUSY)
4438c2ecf20Sopenharmony_ci		goto restart_from_beginning;
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	e.error = -EDESTADDRREQ;
4468c2ecf20Sopenharmony_ci	e.responded = false;
4478c2ecf20Sopenharmony_ci	for (i = 0; i < op->server_list->nr_servers; i++) {
4488c2ecf20Sopenharmony_ci		struct afs_server *s = op->server_list->servers[i].server;
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci		afs_prioritise_error(&e, READ_ONCE(s->probe.error),
4518c2ecf20Sopenharmony_ci				     s->probe.abort_code);
4528c2ecf20Sopenharmony_ci	}
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	error = e.error;
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_cifailed_set_error:
4578c2ecf20Sopenharmony_ci	op->error = error;
4588c2ecf20Sopenharmony_cifailed:
4598c2ecf20Sopenharmony_ci	op->flags |= AFS_OPERATION_STOP;
4608c2ecf20Sopenharmony_ci	afs_end_cursor(&op->ac);
4618c2ecf20Sopenharmony_ci	_leave(" = f [failed %d]", op->error);
4628c2ecf20Sopenharmony_ci	return false;
4638c2ecf20Sopenharmony_ci}
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci/*
4668c2ecf20Sopenharmony_ci * Dump cursor state in the case of the error being EDESTADDRREQ.
4678c2ecf20Sopenharmony_ci */
4688c2ecf20Sopenharmony_civoid afs_dump_edestaddrreq(const struct afs_operation *op)
4698c2ecf20Sopenharmony_ci{
4708c2ecf20Sopenharmony_ci	static int count;
4718c2ecf20Sopenharmony_ci	int i;
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	if (!IS_ENABLED(CONFIG_AFS_DEBUG_CURSOR) || count > 3)
4748c2ecf20Sopenharmony_ci		return;
4758c2ecf20Sopenharmony_ci	count++;
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	rcu_read_lock();
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	pr_notice("EDESTADDR occurred\n");
4808c2ecf20Sopenharmony_ci	pr_notice("FC: cbb=%x cbb2=%x fl=%x err=%hd\n",
4818c2ecf20Sopenharmony_ci		  op->file[0].cb_break_before,
4828c2ecf20Sopenharmony_ci		  op->file[1].cb_break_before, op->flags, op->error);
4838c2ecf20Sopenharmony_ci	pr_notice("FC: ut=%lx ix=%d ni=%u\n",
4848c2ecf20Sopenharmony_ci		  op->untried, op->index, op->nr_iterations);
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	if (op->server_list) {
4878c2ecf20Sopenharmony_ci		const struct afs_server_list *sl = op->server_list;
4888c2ecf20Sopenharmony_ci		pr_notice("FC: SL nr=%u pr=%u vnov=%hx\n",
4898c2ecf20Sopenharmony_ci			  sl->nr_servers, sl->preferred, sl->vnovol_mask);
4908c2ecf20Sopenharmony_ci		for (i = 0; i < sl->nr_servers; i++) {
4918c2ecf20Sopenharmony_ci			const struct afs_server *s = sl->servers[i].server;
4928c2ecf20Sopenharmony_ci			pr_notice("FC: server fl=%lx av=%u %pU\n",
4938c2ecf20Sopenharmony_ci				  s->flags, s->addr_version, &s->uuid);
4948c2ecf20Sopenharmony_ci			if (s->addresses) {
4958c2ecf20Sopenharmony_ci				const struct afs_addr_list *a =
4968c2ecf20Sopenharmony_ci					rcu_dereference(s->addresses);
4978c2ecf20Sopenharmony_ci				pr_notice("FC:  - av=%u nr=%u/%u/%u pr=%u\n",
4988c2ecf20Sopenharmony_ci					  a->version,
4998c2ecf20Sopenharmony_ci					  a->nr_ipv4, a->nr_addrs, a->max_addrs,
5008c2ecf20Sopenharmony_ci					  a->preferred);
5018c2ecf20Sopenharmony_ci				pr_notice("FC:  - R=%lx F=%lx\n",
5028c2ecf20Sopenharmony_ci					  a->responded, a->failed);
5038c2ecf20Sopenharmony_ci				if (a == op->ac.alist)
5048c2ecf20Sopenharmony_ci					pr_notice("FC:  - current\n");
5058c2ecf20Sopenharmony_ci			}
5068c2ecf20Sopenharmony_ci		}
5078c2ecf20Sopenharmony_ci	}
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	pr_notice("AC: t=%lx ax=%u ac=%d er=%d r=%u ni=%u\n",
5108c2ecf20Sopenharmony_ci		  op->ac.tried, op->ac.index, op->ac.abort_code, op->ac.error,
5118c2ecf20Sopenharmony_ci		  op->ac.responded, op->ac.nr_iterations);
5128c2ecf20Sopenharmony_ci	rcu_read_unlock();
5138c2ecf20Sopenharmony_ci}
514