162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* Handle fileserver selection and rotation. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved. 562306a36Sopenharmony_ci * Written by David Howells (dhowells@redhat.com) 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/kernel.h> 962306a36Sopenharmony_ci#include <linux/slab.h> 1062306a36Sopenharmony_ci#include <linux/fs.h> 1162306a36Sopenharmony_ci#include <linux/sched.h> 1262306a36Sopenharmony_ci#include <linux/delay.h> 1362306a36Sopenharmony_ci#include <linux/sched/signal.h> 1462306a36Sopenharmony_ci#include "internal.h" 1562306a36Sopenharmony_ci#include "afs_fs.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci/* 1862306a36Sopenharmony_ci * Begin iteration through a server list, starting with the vnode's last used 1962306a36Sopenharmony_ci * server if possible, or the last recorded good server if not. 2062306a36Sopenharmony_ci */ 2162306a36Sopenharmony_cistatic bool afs_start_fs_iteration(struct afs_operation *op, 2262306a36Sopenharmony_ci struct afs_vnode *vnode) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci struct afs_server *server; 2562306a36Sopenharmony_ci void *cb_server; 2662306a36Sopenharmony_ci int i; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci read_lock(&op->volume->servers_lock); 2962306a36Sopenharmony_ci op->server_list = afs_get_serverlist( 3062306a36Sopenharmony_ci rcu_dereference_protected(op->volume->servers, 3162306a36Sopenharmony_ci lockdep_is_held(&op->volume->servers_lock))); 3262306a36Sopenharmony_ci read_unlock(&op->volume->servers_lock); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci op->untried = (1UL << op->server_list->nr_servers) - 1; 3562306a36Sopenharmony_ci op->index = READ_ONCE(op->server_list->preferred); 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci cb_server = vnode->cb_server; 3862306a36Sopenharmony_ci if (cb_server) { 3962306a36Sopenharmony_ci /* See if the vnode's preferred record is still available */ 4062306a36Sopenharmony_ci for (i = 0; i < op->server_list->nr_servers; i++) { 4162306a36Sopenharmony_ci server = op->server_list->servers[i].server; 4262306a36Sopenharmony_ci if (server == cb_server) { 4362306a36Sopenharmony_ci op->index = i; 4462306a36Sopenharmony_ci goto found_interest; 4562306a36Sopenharmony_ci } 4662306a36Sopenharmony_ci } 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci /* If we have a lock outstanding on a server that's no longer 4962306a36Sopenharmony_ci * serving this vnode, then we can't switch to another server 5062306a36Sopenharmony_ci * and have to return an error. 5162306a36Sopenharmony_ci */ 5262306a36Sopenharmony_ci if (op->flags & AFS_OPERATION_CUR_ONLY) { 5362306a36Sopenharmony_ci op->error = -ESTALE; 5462306a36Sopenharmony_ci return false; 5562306a36Sopenharmony_ci } 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci /* Note that the callback promise is effectively broken */ 5862306a36Sopenharmony_ci write_seqlock(&vnode->cb_lock); 5962306a36Sopenharmony_ci ASSERTCMP(cb_server, ==, vnode->cb_server); 6062306a36Sopenharmony_ci vnode->cb_server = NULL; 6162306a36Sopenharmony_ci if (test_and_clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) 6262306a36Sopenharmony_ci vnode->cb_break++; 6362306a36Sopenharmony_ci write_sequnlock(&vnode->cb_lock); 6462306a36Sopenharmony_ci } 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cifound_interest: 6762306a36Sopenharmony_ci return true; 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci/* 7162306a36Sopenharmony_ci * Post volume busy note. 7262306a36Sopenharmony_ci */ 7362306a36Sopenharmony_cistatic void afs_busy(struct afs_volume *volume, u32 abort_code) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci const char *m; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci switch (abort_code) { 7862306a36Sopenharmony_ci case VOFFLINE: m = "offline"; break; 7962306a36Sopenharmony_ci case VRESTARTING: m = "restarting"; break; 8062306a36Sopenharmony_ci case VSALVAGING: m = "being salvaged"; break; 8162306a36Sopenharmony_ci default: m = "busy"; break; 8262306a36Sopenharmony_ci } 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci pr_notice("kAFS: Volume %llu '%s' is %s\n", volume->vid, volume->name, m); 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci/* 8862306a36Sopenharmony_ci * Sleep and retry the operation to the same fileserver. 8962306a36Sopenharmony_ci */ 9062306a36Sopenharmony_cistatic bool afs_sleep_and_retry(struct afs_operation *op) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci if (!(op->flags & AFS_OPERATION_UNINTR)) { 9362306a36Sopenharmony_ci msleep_interruptible(1000); 9462306a36Sopenharmony_ci if (signal_pending(current)) { 9562306a36Sopenharmony_ci op->error = -ERESTARTSYS; 9662306a36Sopenharmony_ci return false; 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci } else { 9962306a36Sopenharmony_ci msleep(1000); 10062306a36Sopenharmony_ci } 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci return true; 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci/* 10662306a36Sopenharmony_ci * Select the fileserver to use. May be called multiple times to rotate 10762306a36Sopenharmony_ci * through the fileservers. 10862306a36Sopenharmony_ci */ 10962306a36Sopenharmony_cibool afs_select_fileserver(struct afs_operation *op) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci struct afs_addr_list *alist; 11262306a36Sopenharmony_ci struct afs_server *server; 11362306a36Sopenharmony_ci struct afs_vnode *vnode = op->file[0].vnode; 11462306a36Sopenharmony_ci struct afs_error e; 11562306a36Sopenharmony_ci u32 rtt; 11662306a36Sopenharmony_ci int error = op->ac.error, i; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci _enter("%lx[%d],%lx[%d],%d,%d", 11962306a36Sopenharmony_ci op->untried, op->index, 12062306a36Sopenharmony_ci op->ac.tried, op->ac.index, 12162306a36Sopenharmony_ci error, op->ac.abort_code); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci if (op->flags & AFS_OPERATION_STOP) { 12462306a36Sopenharmony_ci _leave(" = f [stopped]"); 12562306a36Sopenharmony_ci return false; 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci op->nr_iterations++; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci /* Evaluate the result of the previous operation, if there was one. */ 13162306a36Sopenharmony_ci switch (error) { 13262306a36Sopenharmony_ci case SHRT_MAX: 13362306a36Sopenharmony_ci goto start; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci case 0: 13662306a36Sopenharmony_ci default: 13762306a36Sopenharmony_ci /* Success or local failure. Stop. */ 13862306a36Sopenharmony_ci op->error = error; 13962306a36Sopenharmony_ci op->flags |= AFS_OPERATION_STOP; 14062306a36Sopenharmony_ci _leave(" = f [okay/local %d]", error); 14162306a36Sopenharmony_ci return false; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci case -ECONNABORTED: 14462306a36Sopenharmony_ci /* The far side rejected the operation on some grounds. This 14562306a36Sopenharmony_ci * might involve the server being busy or the volume having been moved. 14662306a36Sopenharmony_ci */ 14762306a36Sopenharmony_ci switch (op->ac.abort_code) { 14862306a36Sopenharmony_ci case VNOVOL: 14962306a36Sopenharmony_ci /* This fileserver doesn't know about the volume. 15062306a36Sopenharmony_ci * - May indicate that the VL is wrong - retry once and compare 15162306a36Sopenharmony_ci * the results. 15262306a36Sopenharmony_ci * - May indicate that the fileserver couldn't attach to the vol. 15362306a36Sopenharmony_ci */ 15462306a36Sopenharmony_ci if (op->flags & AFS_OPERATION_VNOVOL) { 15562306a36Sopenharmony_ci op->error = -EREMOTEIO; 15662306a36Sopenharmony_ci goto next_server; 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci write_lock(&op->volume->servers_lock); 16062306a36Sopenharmony_ci op->server_list->vnovol_mask |= 1 << op->index; 16162306a36Sopenharmony_ci write_unlock(&op->volume->servers_lock); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci set_bit(AFS_VOLUME_NEEDS_UPDATE, &op->volume->flags); 16462306a36Sopenharmony_ci error = afs_check_volume_status(op->volume, op); 16562306a36Sopenharmony_ci if (error < 0) 16662306a36Sopenharmony_ci goto failed_set_error; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci if (test_bit(AFS_VOLUME_DELETED, &op->volume->flags)) { 16962306a36Sopenharmony_ci op->error = -ENOMEDIUM; 17062306a36Sopenharmony_ci goto failed; 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci /* If the server list didn't change, then assume that 17462306a36Sopenharmony_ci * it's the fileserver having trouble. 17562306a36Sopenharmony_ci */ 17662306a36Sopenharmony_ci if (rcu_access_pointer(op->volume->servers) == op->server_list) { 17762306a36Sopenharmony_ci op->error = -EREMOTEIO; 17862306a36Sopenharmony_ci goto next_server; 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci /* Try again */ 18262306a36Sopenharmony_ci op->flags |= AFS_OPERATION_VNOVOL; 18362306a36Sopenharmony_ci _leave(" = t [vnovol]"); 18462306a36Sopenharmony_ci return true; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci case VSALVAGE: /* TODO: Should this return an error or iterate? */ 18762306a36Sopenharmony_ci case VVOLEXISTS: 18862306a36Sopenharmony_ci case VNOSERVICE: 18962306a36Sopenharmony_ci case VONLINE: 19062306a36Sopenharmony_ci case VDISKFULL: 19162306a36Sopenharmony_ci case VOVERQUOTA: 19262306a36Sopenharmony_ci op->error = afs_abort_to_error(op->ac.abort_code); 19362306a36Sopenharmony_ci goto next_server; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci case VOFFLINE: 19662306a36Sopenharmony_ci if (!test_and_set_bit(AFS_VOLUME_OFFLINE, &op->volume->flags)) { 19762306a36Sopenharmony_ci afs_busy(op->volume, op->ac.abort_code); 19862306a36Sopenharmony_ci clear_bit(AFS_VOLUME_BUSY, &op->volume->flags); 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci if (op->flags & AFS_OPERATION_NO_VSLEEP) { 20162306a36Sopenharmony_ci op->error = -EADV; 20262306a36Sopenharmony_ci goto failed; 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci if (op->flags & AFS_OPERATION_CUR_ONLY) { 20562306a36Sopenharmony_ci op->error = -ESTALE; 20662306a36Sopenharmony_ci goto failed; 20762306a36Sopenharmony_ci } 20862306a36Sopenharmony_ci goto busy; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci case VSALVAGING: 21162306a36Sopenharmony_ci case VRESTARTING: 21262306a36Sopenharmony_ci case VBUSY: 21362306a36Sopenharmony_ci /* Retry after going round all the servers unless we 21462306a36Sopenharmony_ci * have a file lock we need to maintain. 21562306a36Sopenharmony_ci */ 21662306a36Sopenharmony_ci if (op->flags & AFS_OPERATION_NO_VSLEEP) { 21762306a36Sopenharmony_ci op->error = -EBUSY; 21862306a36Sopenharmony_ci goto failed; 21962306a36Sopenharmony_ci } 22062306a36Sopenharmony_ci if (!test_and_set_bit(AFS_VOLUME_BUSY, &op->volume->flags)) { 22162306a36Sopenharmony_ci afs_busy(op->volume, op->ac.abort_code); 22262306a36Sopenharmony_ci clear_bit(AFS_VOLUME_OFFLINE, &op->volume->flags); 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci busy: 22562306a36Sopenharmony_ci if (op->flags & AFS_OPERATION_CUR_ONLY) { 22662306a36Sopenharmony_ci if (!afs_sleep_and_retry(op)) 22762306a36Sopenharmony_ci goto failed; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci /* Retry with same server & address */ 23062306a36Sopenharmony_ci _leave(" = t [vbusy]"); 23162306a36Sopenharmony_ci return true; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci op->flags |= AFS_OPERATION_VBUSY; 23562306a36Sopenharmony_ci goto next_server; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci case VMOVED: 23862306a36Sopenharmony_ci /* The volume migrated to another server. We consider 23962306a36Sopenharmony_ci * consider all locks and callbacks broken and request 24062306a36Sopenharmony_ci * an update from the VLDB. 24162306a36Sopenharmony_ci * 24262306a36Sopenharmony_ci * We also limit the number of VMOVED hops we will 24362306a36Sopenharmony_ci * honour, just in case someone sets up a loop. 24462306a36Sopenharmony_ci */ 24562306a36Sopenharmony_ci if (op->flags & AFS_OPERATION_VMOVED) { 24662306a36Sopenharmony_ci op->error = -EREMOTEIO; 24762306a36Sopenharmony_ci goto failed; 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci op->flags |= AFS_OPERATION_VMOVED; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci set_bit(AFS_VOLUME_WAIT, &op->volume->flags); 25262306a36Sopenharmony_ci set_bit(AFS_VOLUME_NEEDS_UPDATE, &op->volume->flags); 25362306a36Sopenharmony_ci error = afs_check_volume_status(op->volume, op); 25462306a36Sopenharmony_ci if (error < 0) 25562306a36Sopenharmony_ci goto failed_set_error; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci /* If the server list didn't change, then the VLDB is 25862306a36Sopenharmony_ci * out of sync with the fileservers. This is hopefully 25962306a36Sopenharmony_ci * a temporary condition, however, so we don't want to 26062306a36Sopenharmony_ci * permanently block access to the file. 26162306a36Sopenharmony_ci * 26262306a36Sopenharmony_ci * TODO: Try other fileservers if we can. 26362306a36Sopenharmony_ci * 26462306a36Sopenharmony_ci * TODO: Retry a few times with sleeps. 26562306a36Sopenharmony_ci */ 26662306a36Sopenharmony_ci if (rcu_access_pointer(op->volume->servers) == op->server_list) { 26762306a36Sopenharmony_ci op->error = -ENOMEDIUM; 26862306a36Sopenharmony_ci goto failed; 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci goto restart_from_beginning; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci default: 27462306a36Sopenharmony_ci clear_bit(AFS_VOLUME_OFFLINE, &op->volume->flags); 27562306a36Sopenharmony_ci clear_bit(AFS_VOLUME_BUSY, &op->volume->flags); 27662306a36Sopenharmony_ci op->error = afs_abort_to_error(op->ac.abort_code); 27762306a36Sopenharmony_ci goto failed; 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci case -ETIMEDOUT: 28162306a36Sopenharmony_ci case -ETIME: 28262306a36Sopenharmony_ci if (op->error != -EDESTADDRREQ) 28362306a36Sopenharmony_ci goto iterate_address; 28462306a36Sopenharmony_ci fallthrough; 28562306a36Sopenharmony_ci case -ERFKILL: 28662306a36Sopenharmony_ci case -EADDRNOTAVAIL: 28762306a36Sopenharmony_ci case -ENETUNREACH: 28862306a36Sopenharmony_ci case -EHOSTUNREACH: 28962306a36Sopenharmony_ci case -EHOSTDOWN: 29062306a36Sopenharmony_ci case -ECONNREFUSED: 29162306a36Sopenharmony_ci _debug("no conn"); 29262306a36Sopenharmony_ci op->error = error; 29362306a36Sopenharmony_ci goto iterate_address; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci case -ENETRESET: 29662306a36Sopenharmony_ci pr_warn("kAFS: Peer reset %s (op=%x)\n", 29762306a36Sopenharmony_ci op->type ? op->type->name : "???", op->debug_id); 29862306a36Sopenharmony_ci fallthrough; 29962306a36Sopenharmony_ci case -ECONNRESET: 30062306a36Sopenharmony_ci _debug("call reset"); 30162306a36Sopenharmony_ci op->error = error; 30262306a36Sopenharmony_ci goto failed; 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_cirestart_from_beginning: 30662306a36Sopenharmony_ci _debug("restart"); 30762306a36Sopenharmony_ci afs_end_cursor(&op->ac); 30862306a36Sopenharmony_ci op->server = NULL; 30962306a36Sopenharmony_ci afs_put_serverlist(op->net, op->server_list); 31062306a36Sopenharmony_ci op->server_list = NULL; 31162306a36Sopenharmony_cistart: 31262306a36Sopenharmony_ci _debug("start"); 31362306a36Sopenharmony_ci /* See if we need to do an update of the volume record. Note that the 31462306a36Sopenharmony_ci * volume may have moved or even have been deleted. 31562306a36Sopenharmony_ci */ 31662306a36Sopenharmony_ci error = afs_check_volume_status(op->volume, op); 31762306a36Sopenharmony_ci if (error < 0) 31862306a36Sopenharmony_ci goto failed_set_error; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci if (!afs_start_fs_iteration(op, vnode)) 32162306a36Sopenharmony_ci goto failed; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci _debug("__ VOL %llx __", op->volume->vid); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_cipick_server: 32662306a36Sopenharmony_ci _debug("pick [%lx]", op->untried); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci error = afs_wait_for_fs_probes(op->server_list, op->untried); 32962306a36Sopenharmony_ci if (error < 0) 33062306a36Sopenharmony_ci goto failed_set_error; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci /* Pick the untried server with the lowest RTT. If we have outstanding 33362306a36Sopenharmony_ci * callbacks, we stick with the server we're already using if we can. 33462306a36Sopenharmony_ci */ 33562306a36Sopenharmony_ci if (op->server) { 33662306a36Sopenharmony_ci _debug("server %u", op->index); 33762306a36Sopenharmony_ci if (test_bit(op->index, &op->untried)) 33862306a36Sopenharmony_ci goto selected_server; 33962306a36Sopenharmony_ci op->server = NULL; 34062306a36Sopenharmony_ci _debug("no server"); 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci op->index = -1; 34462306a36Sopenharmony_ci rtt = U32_MAX; 34562306a36Sopenharmony_ci for (i = 0; i < op->server_list->nr_servers; i++) { 34662306a36Sopenharmony_ci struct afs_server *s = op->server_list->servers[i].server; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci if (!test_bit(i, &op->untried) || 34962306a36Sopenharmony_ci !test_bit(AFS_SERVER_FL_RESPONDING, &s->flags)) 35062306a36Sopenharmony_ci continue; 35162306a36Sopenharmony_ci if (s->probe.rtt < rtt) { 35262306a36Sopenharmony_ci op->index = i; 35362306a36Sopenharmony_ci rtt = s->probe.rtt; 35462306a36Sopenharmony_ci } 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci if (op->index == -1) 35862306a36Sopenharmony_ci goto no_more_servers; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ciselected_server: 36162306a36Sopenharmony_ci _debug("use %d", op->index); 36262306a36Sopenharmony_ci __clear_bit(op->index, &op->untried); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci /* We're starting on a different fileserver from the list. We need to 36562306a36Sopenharmony_ci * check it, create a callback intercept, find its address list and 36662306a36Sopenharmony_ci * probe its capabilities before we use it. 36762306a36Sopenharmony_ci */ 36862306a36Sopenharmony_ci ASSERTCMP(op->ac.alist, ==, NULL); 36962306a36Sopenharmony_ci server = op->server_list->servers[op->index].server; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci if (!afs_check_server_record(op, server)) 37262306a36Sopenharmony_ci goto failed; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci _debug("USING SERVER: %pU", &server->uuid); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci op->flags |= AFS_OPERATION_RETRY_SERVER; 37762306a36Sopenharmony_ci op->server = server; 37862306a36Sopenharmony_ci if (vnode->cb_server != server) { 37962306a36Sopenharmony_ci vnode->cb_server = server; 38062306a36Sopenharmony_ci vnode->cb_s_break = server->cb_s_break; 38162306a36Sopenharmony_ci vnode->cb_fs_s_break = atomic_read(&server->cell->fs_s_break); 38262306a36Sopenharmony_ci vnode->cb_v_break = vnode->volume->cb_v_break; 38362306a36Sopenharmony_ci clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci read_lock(&server->fs_lock); 38762306a36Sopenharmony_ci alist = rcu_dereference_protected(server->addresses, 38862306a36Sopenharmony_ci lockdep_is_held(&server->fs_lock)); 38962306a36Sopenharmony_ci afs_get_addrlist(alist); 39062306a36Sopenharmony_ci read_unlock(&server->fs_lock); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ciretry_server: 39362306a36Sopenharmony_ci memset(&op->ac, 0, sizeof(op->ac)); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci if (!op->ac.alist) 39662306a36Sopenharmony_ci op->ac.alist = alist; 39762306a36Sopenharmony_ci else 39862306a36Sopenharmony_ci afs_put_addrlist(alist); 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci op->ac.index = -1; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ciiterate_address: 40362306a36Sopenharmony_ci ASSERT(op->ac.alist); 40462306a36Sopenharmony_ci /* Iterate over the current server's address list to try and find an 40562306a36Sopenharmony_ci * address on which it will respond to us. 40662306a36Sopenharmony_ci */ 40762306a36Sopenharmony_ci if (!afs_iterate_addresses(&op->ac)) 40862306a36Sopenharmony_ci goto out_of_addresses; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci _debug("address [%u] %u/%u %pISp", 41162306a36Sopenharmony_ci op->index, op->ac.index, op->ac.alist->nr_addrs, 41262306a36Sopenharmony_ci &op->ac.alist->addrs[op->ac.index].transport); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci _leave(" = t"); 41562306a36Sopenharmony_ci return true; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ciout_of_addresses: 41862306a36Sopenharmony_ci /* We've now had a failure to respond on all of a server's addresses - 41962306a36Sopenharmony_ci * immediately probe them again and consider retrying the server. 42062306a36Sopenharmony_ci */ 42162306a36Sopenharmony_ci afs_probe_fileserver(op->net, op->server); 42262306a36Sopenharmony_ci if (op->flags & AFS_OPERATION_RETRY_SERVER) { 42362306a36Sopenharmony_ci alist = op->ac.alist; 42462306a36Sopenharmony_ci error = afs_wait_for_one_fs_probe( 42562306a36Sopenharmony_ci op->server, !(op->flags & AFS_OPERATION_UNINTR)); 42662306a36Sopenharmony_ci switch (error) { 42762306a36Sopenharmony_ci case 0: 42862306a36Sopenharmony_ci op->flags &= ~AFS_OPERATION_RETRY_SERVER; 42962306a36Sopenharmony_ci goto retry_server; 43062306a36Sopenharmony_ci case -ERESTARTSYS: 43162306a36Sopenharmony_ci goto failed_set_error; 43262306a36Sopenharmony_ci case -ETIME: 43362306a36Sopenharmony_ci case -EDESTADDRREQ: 43462306a36Sopenharmony_ci goto next_server; 43562306a36Sopenharmony_ci } 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_cinext_server: 43962306a36Sopenharmony_ci _debug("next"); 44062306a36Sopenharmony_ci afs_end_cursor(&op->ac); 44162306a36Sopenharmony_ci goto pick_server; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_cino_more_servers: 44462306a36Sopenharmony_ci /* That's all the servers poked to no good effect. Try again if some 44562306a36Sopenharmony_ci * of them were busy. 44662306a36Sopenharmony_ci */ 44762306a36Sopenharmony_ci if (op->flags & AFS_OPERATION_VBUSY) 44862306a36Sopenharmony_ci goto restart_from_beginning; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci e.error = -EDESTADDRREQ; 45162306a36Sopenharmony_ci e.responded = false; 45262306a36Sopenharmony_ci for (i = 0; i < op->server_list->nr_servers; i++) { 45362306a36Sopenharmony_ci struct afs_server *s = op->server_list->servers[i].server; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci afs_prioritise_error(&e, READ_ONCE(s->probe.error), 45662306a36Sopenharmony_ci s->probe.abort_code); 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci error = e.error; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_cifailed_set_error: 46262306a36Sopenharmony_ci op->error = error; 46362306a36Sopenharmony_cifailed: 46462306a36Sopenharmony_ci op->flags |= AFS_OPERATION_STOP; 46562306a36Sopenharmony_ci afs_end_cursor(&op->ac); 46662306a36Sopenharmony_ci _leave(" = f [failed %d]", op->error); 46762306a36Sopenharmony_ci return false; 46862306a36Sopenharmony_ci} 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci/* 47162306a36Sopenharmony_ci * Dump cursor state in the case of the error being EDESTADDRREQ. 47262306a36Sopenharmony_ci */ 47362306a36Sopenharmony_civoid afs_dump_edestaddrreq(const struct afs_operation *op) 47462306a36Sopenharmony_ci{ 47562306a36Sopenharmony_ci static int count; 47662306a36Sopenharmony_ci int i; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_AFS_DEBUG_CURSOR) || count > 3) 47962306a36Sopenharmony_ci return; 48062306a36Sopenharmony_ci count++; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci rcu_read_lock(); 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci pr_notice("EDESTADDR occurred\n"); 48562306a36Sopenharmony_ci pr_notice("FC: cbb=%x cbb2=%x fl=%x err=%hd\n", 48662306a36Sopenharmony_ci op->file[0].cb_break_before, 48762306a36Sopenharmony_ci op->file[1].cb_break_before, op->flags, op->error); 48862306a36Sopenharmony_ci pr_notice("FC: ut=%lx ix=%d ni=%u\n", 48962306a36Sopenharmony_ci op->untried, op->index, op->nr_iterations); 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci if (op->server_list) { 49262306a36Sopenharmony_ci const struct afs_server_list *sl = op->server_list; 49362306a36Sopenharmony_ci pr_notice("FC: SL nr=%u pr=%u vnov=%hx\n", 49462306a36Sopenharmony_ci sl->nr_servers, sl->preferred, sl->vnovol_mask); 49562306a36Sopenharmony_ci for (i = 0; i < sl->nr_servers; i++) { 49662306a36Sopenharmony_ci const struct afs_server *s = sl->servers[i].server; 49762306a36Sopenharmony_ci pr_notice("FC: server fl=%lx av=%u %pU\n", 49862306a36Sopenharmony_ci s->flags, s->addr_version, &s->uuid); 49962306a36Sopenharmony_ci if (s->addresses) { 50062306a36Sopenharmony_ci const struct afs_addr_list *a = 50162306a36Sopenharmony_ci rcu_dereference(s->addresses); 50262306a36Sopenharmony_ci pr_notice("FC: - av=%u nr=%u/%u/%u pr=%u\n", 50362306a36Sopenharmony_ci a->version, 50462306a36Sopenharmony_ci a->nr_ipv4, a->nr_addrs, a->max_addrs, 50562306a36Sopenharmony_ci a->preferred); 50662306a36Sopenharmony_ci pr_notice("FC: - R=%lx F=%lx\n", 50762306a36Sopenharmony_ci a->responded, a->failed); 50862306a36Sopenharmony_ci if (a == op->ac.alist) 50962306a36Sopenharmony_ci pr_notice("FC: - current\n"); 51062306a36Sopenharmony_ci } 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci } 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci pr_notice("AC: t=%lx ax=%u ac=%d er=%d r=%u ni=%u\n", 51562306a36Sopenharmony_ci op->ac.tried, op->ac.index, op->ac.abort_code, op->ac.error, 51662306a36Sopenharmony_ci op->ac.responded, op->ac.nr_iterations); 51762306a36Sopenharmony_ci rcu_read_unlock(); 51862306a36Sopenharmony_ci} 519