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