brintos

brintos / linux-shallow public Read only

0
0
Text · 22.3 KiB · d612983 Raw
753 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/* Handle fileserver selection and rotation.3 *4 * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved.5 * Written by David Howells (dhowells@redhat.com)6 */7 8#include <linux/kernel.h>9#include <linux/slab.h>10#include <linux/fs.h>11#include <linux/sched.h>12#include <linux/delay.h>13#include <linux/sched/signal.h>14#include "internal.h"15#include "afs_fs.h"16#include "protocol_uae.h"17 18void afs_clear_server_states(struct afs_operation *op)19{20	unsigned int i;21 22	if (op->server_states) {23		for (i = 0; i < op->server_list->nr_servers; i++)24			afs_put_endpoint_state(op->server_states[i].endpoint_state,25					       afs_estate_trace_put_server_state);26		kfree(op->server_states);27	}28}29 30/*31 * Begin iteration through a server list, starting with the vnode's last used32 * server if possible, or the last recorded good server if not.33 */34static bool afs_start_fs_iteration(struct afs_operation *op,35				   struct afs_vnode *vnode)36{37	struct afs_server *server;38	void *cb_server;39	int i;40 41	trace_afs_rotate(op, afs_rotate_trace_start, 0);42 43	read_lock(&op->volume->servers_lock);44	op->server_list = afs_get_serverlist(45		rcu_dereference_protected(op->volume->servers,46					  lockdep_is_held(&op->volume->servers_lock)));47	read_unlock(&op->volume->servers_lock);48 49	op->server_states = kcalloc(op->server_list->nr_servers, sizeof(op->server_states[0]),50				    GFP_KERNEL);51	if (!op->server_states) {52		afs_op_nomem(op);53		trace_afs_rotate(op, afs_rotate_trace_nomem, 0);54		return false;55	}56 57	rcu_read_lock();58	for (i = 0; i < op->server_list->nr_servers; i++) {59		struct afs_endpoint_state *estate;60		struct afs_server_state *s = &op->server_states[i];61 62		server = op->server_list->servers[i].server;63		estate = rcu_dereference(server->endpoint_state);64		s->endpoint_state = afs_get_endpoint_state(estate,65							   afs_estate_trace_get_server_state);66		s->probe_seq = estate->probe_seq;67		s->untried_addrs = (1UL << estate->addresses->nr_addrs) - 1;68		init_waitqueue_entry(&s->probe_waiter, current);69		afs_get_address_preferences(op->net, estate->addresses);70	}71	rcu_read_unlock();72 73 74	op->untried_servers = (1UL << op->server_list->nr_servers) - 1;75	op->server_index = -1;76 77	cb_server = vnode->cb_server;78	if (cb_server) {79		/* See if the vnode's preferred record is still available */80		for (i = 0; i < op->server_list->nr_servers; i++) {81			server = op->server_list->servers[i].server;82			if (server == cb_server) {83				op->server_index = i;84				goto found_interest;85			}86		}87 88		/* If we have a lock outstanding on a server that's no longer89		 * serving this vnode, then we can't switch to another server90		 * and have to return an error.91		 */92		if (op->flags & AFS_OPERATION_CUR_ONLY) {93			afs_op_set_error(op, -ESTALE);94			trace_afs_rotate(op, afs_rotate_trace_stale_lock, 0);95			return false;96		}97 98		/* Note that the callback promise is effectively broken */99		write_seqlock(&vnode->cb_lock);100		ASSERTCMP(cb_server, ==, vnode->cb_server);101		vnode->cb_server = NULL;102		if (atomic64_xchg(&vnode->cb_expires_at, AFS_NO_CB_PROMISE) != AFS_NO_CB_PROMISE)103			vnode->cb_break++;104		write_sequnlock(&vnode->cb_lock);105	}106 107found_interest:108	return true;109}110 111/*112 * Post volume busy note.113 */114static void afs_busy(struct afs_operation *op, u32 abort_code)115{116	const char *m;117 118	switch (abort_code) {119	case VOFFLINE:		m = "offline";		break;120	case VRESTARTING:	m = "restarting";	break;121	case VSALVAGING:	m = "being salvaged";	break;122	default:		m = "busy";		break;123	}124 125	pr_notice("kAFS: Volume %llu '%s' on server %pU is %s\n",126		  op->volume->vid, op->volume->name, &op->server->uuid, m);127}128 129/*130 * Sleep and retry the operation to the same fileserver.131 */132static bool afs_sleep_and_retry(struct afs_operation *op)133{134	trace_afs_rotate(op, afs_rotate_trace_busy_sleep, 0);135	if (!(op->flags & AFS_OPERATION_UNINTR)) {136		msleep_interruptible(1000);137		if (signal_pending(current)) {138			afs_op_set_error(op, -ERESTARTSYS);139			return false;140		}141	} else {142		msleep(1000);143	}144 145	return true;146}147 148/*149 * Select the fileserver to use.  May be called multiple times to rotate150 * through the fileservers.151 */152bool afs_select_fileserver(struct afs_operation *op)153{154	struct afs_addr_list *alist;155	struct afs_server *server;156	struct afs_vnode *vnode = op->file[0].vnode;157	unsigned long set, failed;158	s32 abort_code = op->call_abort_code;159	int best_prio = 0;160	int error = op->call_error, addr_index, i, j;161 162	op->nr_iterations++;163 164	_enter("OP=%x+%x,%llx,%u{%lx},%u{%lx},%d,%d",165	       op->debug_id, op->nr_iterations, op->volume->vid,166	       op->server_index, op->untried_servers,167	       op->addr_index, op->addr_tried,168	       error, abort_code);169 170	if (op->flags & AFS_OPERATION_STOP) {171		trace_afs_rotate(op, afs_rotate_trace_stopped, 0);172		_leave(" = f [stopped]");173		return false;174	}175 176	if (op->nr_iterations == 0)177		goto start;178 179	WRITE_ONCE(op->estate->addresses->addrs[op->addr_index].last_error, error);180	trace_afs_rotate(op, afs_rotate_trace_iter, op->call_error);181 182	/* Evaluate the result of the previous operation, if there was one. */183	switch (op->call_error) {184	case 0:185		clear_bit(AFS_SE_VOLUME_OFFLINE,186			  &op->server_list->servers[op->server_index].flags);187		clear_bit(AFS_SE_VOLUME_BUSY,188			  &op->server_list->servers[op->server_index].flags);189		op->cumul_error.responded = true;190 191		/* We succeeded, but we may need to redo the op from another192		 * server if we're looking at a set of RO volumes where some of193		 * the servers have not yet been brought up to date lest we194		 * regress the data.  We only switch to the new version once195		 * >=50% of the servers are updated.196		 */197		error = afs_update_volume_state(op);198		if (error != 0) {199			if (error == 1) {200				afs_sleep_and_retry(op);201				goto restart_from_beginning;202			}203			afs_op_set_error(op, error);204			goto failed;205		}206		fallthrough;207	default:208		/* Success or local failure.  Stop. */209		afs_op_set_error(op, error);210		op->flags |= AFS_OPERATION_STOP;211		trace_afs_rotate(op, afs_rotate_trace_stop, error);212		_leave(" = f [okay/local %d]", error);213		return false;214 215	case -ECONNABORTED:216		/* The far side rejected the operation on some grounds.  This217		 * might involve the server being busy or the volume having been moved.218		 *219		 * Note that various V* errors should not be sent to a cache manager220		 * by a fileserver as they should be translated to more modern UAE*221		 * errors instead.  IBM AFS and OpenAFS fileservers, however, do leak222		 * these abort codes.223		 */224		trace_afs_rotate(op, afs_rotate_trace_aborted, abort_code);225		op->cumul_error.responded = true;226		switch (abort_code) {227		case VNOVOL:228			/* This fileserver doesn't know about the volume.229			 * - May indicate that the VL is wrong - retry once and compare230			 *   the results.231			 * - May indicate that the fileserver couldn't attach to the vol.232			 * - The volume might have been temporarily removed so that it can233			 *   be replaced by a volume restore.  "vos" might have ended one234			 *   transaction and has yet to create the next.235			 * - The volume might not be blessed or might not be in-service236			 *   (administrative action).237			 */238			if (op->flags & AFS_OPERATION_VNOVOL) {239				afs_op_accumulate_error(op, -EREMOTEIO, abort_code);240				goto next_server;241			}242 243			write_lock(&op->volume->servers_lock);244			op->server_list->vnovol_mask |= 1 << op->server_index;245			write_unlock(&op->volume->servers_lock);246 247			set_bit(AFS_VOLUME_NEEDS_UPDATE, &op->volume->flags);248			error = afs_check_volume_status(op->volume, op);249			if (error < 0) {250				afs_op_set_error(op, error);251				goto failed;252			}253 254			if (test_bit(AFS_VOLUME_DELETED, &op->volume->flags)) {255				afs_op_set_error(op, -ENOMEDIUM);256				goto failed;257			}258 259			/* If the server list didn't change, then assume that260			 * it's the fileserver having trouble.261			 */262			if (rcu_access_pointer(op->volume->servers) == op->server_list) {263				afs_op_accumulate_error(op, -EREMOTEIO, abort_code);264				goto next_server;265			}266 267			/* Try again */268			op->flags |= AFS_OPERATION_VNOVOL;269			_leave(" = t [vnovol]");270			return true;271 272		case VVOLEXISTS:273		case VONLINE:274			/* These should not be returned from the fileserver. */275			pr_warn("Fileserver returned unexpected abort %d\n",276				abort_code);277			afs_op_accumulate_error(op, -EREMOTEIO, abort_code);278			goto next_server;279 280		case VNOSERVICE:281			/* Prior to AFS 3.2 VNOSERVICE was returned from the fileserver282			 * if the volume was neither in-service nor administratively283			 * blessed.  All usage was replaced by VNOVOL because AFS 3.1 and284			 * earlier cache managers did not handle VNOSERVICE and assumed285			 * it was the client OSes errno 105.286			 *287			 * Starting with OpenAFS 1.4.8 VNOSERVICE was repurposed as the288			 * fileserver idle dead time error which was sent in place of289			 * RX_CALL_TIMEOUT (-3).  The error was intended to be sent if the290			 * fileserver took too long to send a reply to the client.291			 * RX_CALL_TIMEOUT would have caused the cache manager to mark the292			 * server down whereas VNOSERVICE since AFS 3.2 would cause cache293			 * manager to temporarily (up to 15 minutes) mark the volume294			 * instance as unusable.295			 *296			 * The idle dead logic resulted in cache inconsistency since a297			 * state changing call that the cache manager assumed was dead298			 * could still be processed to completion by the fileserver.  This299			 * logic was removed in OpenAFS 1.8.0 and VNOSERVICE is no longer300			 * returned.  However, many 1.4.8 through 1.6.24 fileservers are301			 * still in existence.302			 *303			 * AuriStorFS fileservers have never returned VNOSERVICE.304			 *305			 * VNOSERVICE should be treated as an alias for RX_CALL_TIMEOUT.306			 */307		case RX_CALL_TIMEOUT:308			afs_op_accumulate_error(op, -ETIMEDOUT, abort_code);309			goto next_server;310 311		case VSALVAGING: /* This error should not be leaked to cache managers312				  * but is from OpenAFS demand attach fileservers.313				  * It should be treated as an alias for VOFFLINE.314				  */315		case VSALVAGE: /* VSALVAGE should be treated as a synonym of VOFFLINE */316		case VOFFLINE:317			/* The volume is in use by the volserver or another volume utility318			 * for an operation that might alter the contents.  The volume is319			 * expected to come back but it might take a long time (could be320			 * days).321			 */322			if (!test_and_set_bit(AFS_SE_VOLUME_OFFLINE,323					      &op->server_list->servers[op->server_index].flags)) {324				afs_busy(op, abort_code);325				clear_bit(AFS_SE_VOLUME_BUSY,326					  &op->server_list->servers[op->server_index].flags);327			}328			if (op->flags & AFS_OPERATION_NO_VSLEEP) {329				afs_op_set_error(op, -EADV);330				goto failed;331			}332			goto busy;333 334		case VRESTARTING: /* The fileserver is either shutting down or starting up. */335		case VBUSY:336			/* The volume is in use by the volserver or another volume337			 * utility for an operation that is not expected to alter the338			 * contents of the volume.  VBUSY does not need to be returned339			 * for a ROVOL or BACKVOL bound to an ITBusy volserver340			 * transaction.  The fileserver is permitted to continue serving341			 * content from ROVOLs and BACKVOLs during an ITBusy transaction342			 * because the content will not change.  However, many fileserver343			 * releases do return VBUSY for ROVOL and BACKVOL instances under344			 * many circumstances.345			 *346			 * Retry after going round all the servers unless we have a file347			 * lock we need to maintain.348			 */349			if (op->flags & AFS_OPERATION_NO_VSLEEP) {350				afs_op_set_error(op, -EBUSY);351				goto failed;352			}353			if (!test_and_set_bit(AFS_SE_VOLUME_BUSY,354					      &op->server_list->servers[op->server_index].flags)) {355				afs_busy(op, abort_code);356				clear_bit(AFS_SE_VOLUME_OFFLINE,357					  &op->server_list->servers[op->server_index].flags);358			}359		busy:360			if (op->flags & AFS_OPERATION_CUR_ONLY) {361				if (!afs_sleep_and_retry(op))362					goto failed;363 364				/* Retry with same server & address */365				_leave(" = t [vbusy]");366				return true;367			}368 369			op->flags |= AFS_OPERATION_VBUSY;370			goto next_server;371 372		case VMOVED:373			/* The volume migrated to another server.  We consider374			 * consider all locks and callbacks broken and request375			 * an update from the VLDB.376			 *377			 * We also limit the number of VMOVED hops we will378			 * honour, just in case someone sets up a loop.379			 */380			if (op->flags & AFS_OPERATION_VMOVED) {381				afs_op_set_error(op, -EREMOTEIO);382				goto failed;383			}384			op->flags |= AFS_OPERATION_VMOVED;385 386			set_bit(AFS_VOLUME_WAIT, &op->volume->flags);387			set_bit(AFS_VOLUME_NEEDS_UPDATE, &op->volume->flags);388			error = afs_check_volume_status(op->volume, op);389			if (error < 0) {390				afs_op_set_error(op, error);391				goto failed;392			}393 394			/* If the server list didn't change, then the VLDB is395			 * out of sync with the fileservers.  This is hopefully396			 * a temporary condition, however, so we don't want to397			 * permanently block access to the file.398			 *399			 * TODO: Try other fileservers if we can.400			 *401			 * TODO: Retry a few times with sleeps.402			 */403			if (rcu_access_pointer(op->volume->servers) == op->server_list) {404				afs_op_accumulate_error(op, -ENOMEDIUM, abort_code);405				goto failed;406			}407 408			goto restart_from_beginning;409 410		case UAEIO:411		case VIO:412			afs_op_accumulate_error(op, -EREMOTEIO, abort_code);413			if (op->volume->type != AFSVL_RWVOL)414				goto next_server;415			goto failed;416 417		case VDISKFULL:418		case UAENOSPC:419			/* The partition is full.  Only applies to RWVOLs.420			 * Translate locally and return ENOSPC.421			 * No replicas to failover to.422			 */423			afs_op_set_error(op, -ENOSPC);424			goto failed_but_online;425 426		case VOVERQUOTA:427		case UAEDQUOT:428			/* Volume is full.  Only applies to RWVOLs.429			 * Translate locally and return EDQUOT.430			 * No replicas to failover to.431			 */432			afs_op_set_error(op, -EDQUOT);433			goto failed_but_online;434 435		default:436			afs_op_accumulate_error(op, error, abort_code);437		failed_but_online:438			clear_bit(AFS_SE_VOLUME_OFFLINE,439				  &op->server_list->servers[op->server_index].flags);440			clear_bit(AFS_SE_VOLUME_BUSY,441				  &op->server_list->servers[op->server_index].flags);442			goto failed;443		}444 445	case -ETIMEDOUT:446	case -ETIME:447		if (afs_op_error(op) != -EDESTADDRREQ)448			goto iterate_address;449		fallthrough;450	case -ERFKILL:451	case -EADDRNOTAVAIL:452	case -ENETUNREACH:453	case -EHOSTUNREACH:454	case -EHOSTDOWN:455	case -ECONNREFUSED:456		_debug("no conn");457		afs_op_accumulate_error(op, error, 0);458		goto iterate_address;459 460	case -ENETRESET:461		pr_warn("kAFS: Peer reset %s (op=%x)\n",462			op->type ? op->type->name : "???", op->debug_id);463		fallthrough;464	case -ECONNRESET:465		_debug("call reset");466		afs_op_set_error(op, error);467		goto failed;468	}469 470restart_from_beginning:471	trace_afs_rotate(op, afs_rotate_trace_restart, 0);472	_debug("restart");473	op->estate = NULL;474	op->server = NULL;475	afs_clear_server_states(op);476	op->server_states = NULL;477	afs_put_serverlist(op->net, op->server_list);478	op->server_list = NULL;479start:480	_debug("start");481	ASSERTCMP(op->estate, ==, NULL);482	/* See if we need to do an update of the volume record.  Note that the483	 * volume may have moved or even have been deleted.484	 */485	error = afs_check_volume_status(op->volume, op);486	trace_afs_rotate(op, afs_rotate_trace_check_vol_status, error);487	if (error < 0) {488		afs_op_set_error(op, error);489		goto failed;490	}491 492	if (!afs_start_fs_iteration(op, vnode))493		goto failed;494 495	_debug("__ VOL %llx __", op->volume->vid);496 497pick_server:498	_debug("pick [%lx]", op->untried_servers);499	ASSERTCMP(op->estate, ==, NULL);500 501	error = afs_wait_for_fs_probes(op, op->server_states,502				       !(op->flags & AFS_OPERATION_UNINTR));503	switch (error) {504	case 0: /* No untried responsive servers and no outstanding probes */505		trace_afs_rotate(op, afs_rotate_trace_probe_none, 0);506		goto no_more_servers;507	case 1: /* Got a response */508		trace_afs_rotate(op, afs_rotate_trace_probe_response, 0);509		break;510	case 2: /* Probe data superseded */511		trace_afs_rotate(op, afs_rotate_trace_probe_superseded, 0);512		goto restart_from_beginning;513	default:514		trace_afs_rotate(op, afs_rotate_trace_probe_error, error);515		afs_op_set_error(op, error);516		goto failed;517	}518 519	/* Pick the untried server with the highest priority untried endpoint.520	 * If we have outstanding callbacks, we stick with the server we're521	 * already using if we can.522	 */523	if (op->server) {524		_debug("server %u", op->server_index);525		if (test_bit(op->server_index, &op->untried_servers))526			goto selected_server;527		op->server = NULL;528		_debug("no server");529	}530 531	rcu_read_lock();532	op->server_index = -1;533	best_prio = -1;534	for (i = 0; i < op->server_list->nr_servers; i++) {535		struct afs_endpoint_state *es;536		struct afs_server_entry *se = &op->server_list->servers[i];537		struct afs_addr_list *sal;538		struct afs_server *s = se->server;539 540		if (!test_bit(i, &op->untried_servers) ||541		    test_bit(AFS_SE_EXCLUDED, &se->flags) ||542		    !test_bit(AFS_SERVER_FL_RESPONDING, &s->flags))543			continue;544		es = op->server_states[i].endpoint_state;545		sal = es->addresses;546 547		afs_get_address_preferences_rcu(op->net, sal);548		for (j = 0; j < sal->nr_addrs; j++) {549			if (es->failed_set & (1 << j))550				continue;551			if (!sal->addrs[j].peer)552				continue;553			if (sal->addrs[j].prio > best_prio) {554				op->server_index = i;555				best_prio = sal->addrs[j].prio;556			}557		}558	}559	rcu_read_unlock();560 561	if (op->server_index == -1)562		goto no_more_servers;563 564selected_server:565	trace_afs_rotate(op, afs_rotate_trace_selected_server, best_prio);566	_debug("use %d prio %u", op->server_index, best_prio);567	__clear_bit(op->server_index, &op->untried_servers);568 569	/* We're starting on a different fileserver from the list.  We need to570	 * check it, create a callback intercept, find its address list and571	 * probe its capabilities before we use it.572	 */573	ASSERTCMP(op->estate, ==, NULL);574	server = op->server_list->servers[op->server_index].server;575 576	if (!afs_check_server_record(op, server, op->key))577		goto failed;578 579	_debug("USING SERVER: %pU", &server->uuid);580 581	op->flags |= AFS_OPERATION_RETRY_SERVER;582	op->server = server;583	if (vnode->cb_server != server) {584		vnode->cb_server = server;585		vnode->cb_v_check = atomic_read(&vnode->volume->cb_v_break);586		atomic64_set(&vnode->cb_expires_at, AFS_NO_CB_PROMISE);587	}588 589retry_server:590	op->addr_tried = 0;591	op->addr_index = -1;592 593iterate_address:594	/* Iterate over the current server's address list to try and find an595	 * address on which it will respond to us.596	 */597	op->estate = op->server_states[op->server_index].endpoint_state;598	set = READ_ONCE(op->estate->responsive_set);599	failed = READ_ONCE(op->estate->failed_set);600	_debug("iterate ES=%x rs=%lx fs=%lx", op->estate->probe_seq, set, failed);601	set &= ~(failed | op->addr_tried);602	trace_afs_rotate(op, afs_rotate_trace_iterate_addr, set);603	if (!set)604		goto wait_for_more_probe_results;605 606	alist = op->estate->addresses;607	best_prio = -1;608	addr_index = 0;609	for (i = 0; i < alist->nr_addrs; i++) {610		if (!(set & (1 << i)))611			continue;612		if (alist->addrs[i].prio > best_prio) {613			addr_index = i;614			best_prio = alist->addrs[i].prio;615		}616	}617 618	alist->preferred = addr_index;619 620	op->addr_index = addr_index;621	set_bit(addr_index, &op->addr_tried);622 623	op->volsync.creation = TIME64_MIN;624	op->volsync.update = TIME64_MIN;625	op->call_responded = false;626	_debug("address [%u] %u/%u %pISp",627	       op->server_index, addr_index, alist->nr_addrs,628	       rxrpc_kernel_remote_addr(alist->addrs[op->addr_index].peer));629	_leave(" = t");630	return true;631 632wait_for_more_probe_results:633	error = afs_wait_for_one_fs_probe(op->server, op->estate, op->addr_tried,634					  !(op->flags & AFS_OPERATION_UNINTR));635	if (error == 1)636		goto iterate_address;637	if (!error)638		goto restart_from_beginning;639 640	/* We've now had a failure to respond on all of a server's addresses -641	 * immediately probe them again and consider retrying the server.642	 */643	trace_afs_rotate(op, afs_rotate_trace_probe_fileserver, 0);644	afs_probe_fileserver(op->net, op->server);645	if (op->flags & AFS_OPERATION_RETRY_SERVER) {646		error = afs_wait_for_one_fs_probe(op->server, op->estate, op->addr_tried,647						  !(op->flags & AFS_OPERATION_UNINTR));648		switch (error) {649		case 1:650			op->flags &= ~AFS_OPERATION_RETRY_SERVER;651			trace_afs_rotate(op, afs_rotate_trace_retry_server, 1);652			goto retry_server;653		case 0:654			trace_afs_rotate(op, afs_rotate_trace_retry_server, 0);655			goto restart_from_beginning;656		case -ERESTARTSYS:657			afs_op_set_error(op, error);658			goto failed;659		case -ETIME:660		case -EDESTADDRREQ:661			goto next_server;662		}663	}664 665next_server:666	trace_afs_rotate(op, afs_rotate_trace_next_server, 0);667	_debug("next");668	op->estate = NULL;669	goto pick_server;670 671no_more_servers:672	/* That's all the servers poked to no good effect.  Try again if some673	 * of them were busy.674	 */675	trace_afs_rotate(op, afs_rotate_trace_no_more_servers, 0);676	if (op->flags & AFS_OPERATION_VBUSY) {677		afs_sleep_and_retry(op);678		op->flags &= ~AFS_OPERATION_VBUSY;679		goto restart_from_beginning;680	}681 682	rcu_read_lock();683	for (i = 0; i < op->server_list->nr_servers; i++) {684		struct afs_endpoint_state *estate;685 686		estate = op->server_states[i].endpoint_state;687		error = READ_ONCE(estate->error);688		if (error < 0)689			afs_op_accumulate_error(op, error, estate->abort_code);690	}691	rcu_read_unlock();692 693failed:694	trace_afs_rotate(op, afs_rotate_trace_failed, 0);695	op->flags |= AFS_OPERATION_STOP;696	op->estate = NULL;697	_leave(" = f [failed %d]", afs_op_error(op));698	return false;699}700 701/*702 * Dump cursor state in the case of the error being EDESTADDRREQ.703 */704void afs_dump_edestaddrreq(const struct afs_operation *op)705{706	static int count;707	int i;708 709	if (!IS_ENABLED(CONFIG_AFS_DEBUG_CURSOR) || count > 3)710		return;711	count++;712 713	rcu_read_lock();714 715	pr_notice("EDESTADDR occurred\n");716	pr_notice("OP: cbb=%x cbb2=%x fl=%x err=%hd\n",717		  op->file[0].cb_break_before,718		  op->file[1].cb_break_before, op->flags, op->cumul_error.error);719	pr_notice("OP: ut=%lx ix=%d ni=%u\n",720		  op->untried_servers, op->server_index, op->nr_iterations);721	pr_notice("OP: call  er=%d ac=%d r=%u\n",722		  op->call_error, op->call_abort_code, op->call_responded);723 724	if (op->server_list) {725		const struct afs_server_list *sl = op->server_list;726 727		pr_notice("FC: SL nr=%u vnov=%hx\n",728			  sl->nr_servers, sl->vnovol_mask);729		for (i = 0; i < sl->nr_servers; i++) {730			const struct afs_server *s = sl->servers[i].server;731			const struct afs_endpoint_state *e =732				rcu_dereference(s->endpoint_state);733			const struct afs_addr_list *a = e->addresses;734 735			pr_notice("FC: server fl=%lx av=%u %pU\n",736				  s->flags, s->addr_version, &s->uuid);737			pr_notice("FC:  - pq=%x R=%lx F=%lx\n",738				  e->probe_seq, e->responsive_set, e->failed_set);739			if (a) {740				pr_notice("FC:  - av=%u nr=%u/%u/%u pr=%u\n",741					  a->version,742					  a->nr_ipv4, a->nr_addrs, a->max_addrs,743					  a->preferred);744				if (a == e->addresses)745					pr_notice("FC:  - current\n");746			}747		}748	}749 750	pr_notice("AC: t=%lx ax=%d\n", op->addr_tried, op->addr_index);751	rcu_read_unlock();752}753