18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* Handle vlserver selection and rotation. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2018 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/sched.h> 108c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 118c2ecf20Sopenharmony_ci#include "internal.h" 128c2ecf20Sopenharmony_ci#include "afs_vl.h" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci/* 158c2ecf20Sopenharmony_ci * Begin an operation on a volume location server. 168c2ecf20Sopenharmony_ci */ 178c2ecf20Sopenharmony_cibool afs_begin_vlserver_operation(struct afs_vl_cursor *vc, struct afs_cell *cell, 188c2ecf20Sopenharmony_ci struct key *key) 198c2ecf20Sopenharmony_ci{ 208c2ecf20Sopenharmony_ci memset(vc, 0, sizeof(*vc)); 218c2ecf20Sopenharmony_ci vc->cell = cell; 228c2ecf20Sopenharmony_ci vc->key = key; 238c2ecf20Sopenharmony_ci vc->error = -EDESTADDRREQ; 248c2ecf20Sopenharmony_ci vc->ac.error = SHRT_MAX; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci if (signal_pending(current)) { 278c2ecf20Sopenharmony_ci vc->error = -EINTR; 288c2ecf20Sopenharmony_ci vc->flags |= AFS_VL_CURSOR_STOP; 298c2ecf20Sopenharmony_ci return false; 308c2ecf20Sopenharmony_ci } 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci return true; 338c2ecf20Sopenharmony_ci} 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* 368c2ecf20Sopenharmony_ci * Begin iteration through a server list, starting with the last used server if 378c2ecf20Sopenharmony_ci * possible, or the last recorded good server if not. 388c2ecf20Sopenharmony_ci */ 398c2ecf20Sopenharmony_cistatic bool afs_start_vl_iteration(struct afs_vl_cursor *vc) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci struct afs_cell *cell = vc->cell; 428c2ecf20Sopenharmony_ci unsigned int dns_lookup_count; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci if (cell->dns_source == DNS_RECORD_UNAVAILABLE || 458c2ecf20Sopenharmony_ci cell->dns_expiry <= ktime_get_real_seconds()) { 468c2ecf20Sopenharmony_ci dns_lookup_count = smp_load_acquire(&cell->dns_lookup_count); 478c2ecf20Sopenharmony_ci set_bit(AFS_CELL_FL_DO_LOOKUP, &cell->flags); 488c2ecf20Sopenharmony_ci afs_queue_cell(cell, afs_cell_trace_get_queue_dns); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci if (cell->dns_source == DNS_RECORD_UNAVAILABLE) { 518c2ecf20Sopenharmony_ci if (wait_var_event_interruptible( 528c2ecf20Sopenharmony_ci &cell->dns_lookup_count, 538c2ecf20Sopenharmony_ci smp_load_acquire(&cell->dns_lookup_count) 548c2ecf20Sopenharmony_ci != dns_lookup_count) < 0) { 558c2ecf20Sopenharmony_ci vc->error = -ERESTARTSYS; 568c2ecf20Sopenharmony_ci return false; 578c2ecf20Sopenharmony_ci } 588c2ecf20Sopenharmony_ci } 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci /* Status load is ordered after lookup counter load */ 618c2ecf20Sopenharmony_ci if (cell->dns_status == DNS_LOOKUP_GOT_NOT_FOUND) { 628c2ecf20Sopenharmony_ci pr_warn("No record of cell %s\n", cell->name); 638c2ecf20Sopenharmony_ci vc->error = -ENOENT; 648c2ecf20Sopenharmony_ci return false; 658c2ecf20Sopenharmony_ci } 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci if (cell->dns_source == DNS_RECORD_UNAVAILABLE) { 688c2ecf20Sopenharmony_ci vc->error = -EDESTADDRREQ; 698c2ecf20Sopenharmony_ci return false; 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci read_lock(&cell->vl_servers_lock); 748c2ecf20Sopenharmony_ci vc->server_list = afs_get_vlserverlist( 758c2ecf20Sopenharmony_ci rcu_dereference_protected(cell->vl_servers, 768c2ecf20Sopenharmony_ci lockdep_is_held(&cell->vl_servers_lock))); 778c2ecf20Sopenharmony_ci read_unlock(&cell->vl_servers_lock); 788c2ecf20Sopenharmony_ci if (!vc->server_list->nr_servers) 798c2ecf20Sopenharmony_ci return false; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci vc->untried = (1UL << vc->server_list->nr_servers) - 1; 828c2ecf20Sopenharmony_ci vc->index = -1; 838c2ecf20Sopenharmony_ci return true; 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci/* 878c2ecf20Sopenharmony_ci * Select the vlserver to use. May be called multiple times to rotate 888c2ecf20Sopenharmony_ci * through the vlservers. 898c2ecf20Sopenharmony_ci */ 908c2ecf20Sopenharmony_cibool afs_select_vlserver(struct afs_vl_cursor *vc) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci struct afs_addr_list *alist; 938c2ecf20Sopenharmony_ci struct afs_vlserver *vlserver; 948c2ecf20Sopenharmony_ci struct afs_error e; 958c2ecf20Sopenharmony_ci u32 rtt; 968c2ecf20Sopenharmony_ci int error = vc->ac.error, i; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci _enter("%lx[%d],%lx[%d],%d,%d", 998c2ecf20Sopenharmony_ci vc->untried, vc->index, 1008c2ecf20Sopenharmony_ci vc->ac.tried, vc->ac.index, 1018c2ecf20Sopenharmony_ci error, vc->ac.abort_code); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci if (vc->flags & AFS_VL_CURSOR_STOP) { 1048c2ecf20Sopenharmony_ci _leave(" = f [stopped]"); 1058c2ecf20Sopenharmony_ci return false; 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci vc->nr_iterations++; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci /* Evaluate the result of the previous operation, if there was one. */ 1118c2ecf20Sopenharmony_ci switch (error) { 1128c2ecf20Sopenharmony_ci case SHRT_MAX: 1138c2ecf20Sopenharmony_ci goto start; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci default: 1168c2ecf20Sopenharmony_ci case 0: 1178c2ecf20Sopenharmony_ci /* Success or local failure. Stop. */ 1188c2ecf20Sopenharmony_ci vc->error = error; 1198c2ecf20Sopenharmony_ci vc->flags |= AFS_VL_CURSOR_STOP; 1208c2ecf20Sopenharmony_ci _leave(" = f [okay/local %d]", vc->ac.error); 1218c2ecf20Sopenharmony_ci return false; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci case -ECONNABORTED: 1248c2ecf20Sopenharmony_ci /* The far side rejected the operation on some grounds. This 1258c2ecf20Sopenharmony_ci * might involve the server being busy or the volume having been moved. 1268c2ecf20Sopenharmony_ci */ 1278c2ecf20Sopenharmony_ci switch (vc->ac.abort_code) { 1288c2ecf20Sopenharmony_ci case AFSVL_IO: 1298c2ecf20Sopenharmony_ci case AFSVL_BADVOLOPER: 1308c2ecf20Sopenharmony_ci case AFSVL_NOMEM: 1318c2ecf20Sopenharmony_ci /* The server went weird. */ 1328c2ecf20Sopenharmony_ci vc->error = -EREMOTEIO; 1338c2ecf20Sopenharmony_ci //write_lock(&vc->cell->vl_servers_lock); 1348c2ecf20Sopenharmony_ci //vc->server_list->weird_mask |= 1 << vc->index; 1358c2ecf20Sopenharmony_ci //write_unlock(&vc->cell->vl_servers_lock); 1368c2ecf20Sopenharmony_ci goto next_server; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci default: 1398c2ecf20Sopenharmony_ci vc->error = afs_abort_to_error(vc->ac.abort_code); 1408c2ecf20Sopenharmony_ci goto failed; 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci case -ERFKILL: 1448c2ecf20Sopenharmony_ci case -EADDRNOTAVAIL: 1458c2ecf20Sopenharmony_ci case -ENETUNREACH: 1468c2ecf20Sopenharmony_ci case -EHOSTUNREACH: 1478c2ecf20Sopenharmony_ci case -EHOSTDOWN: 1488c2ecf20Sopenharmony_ci case -ECONNREFUSED: 1498c2ecf20Sopenharmony_ci case -ETIMEDOUT: 1508c2ecf20Sopenharmony_ci case -ETIME: 1518c2ecf20Sopenharmony_ci _debug("no conn %d", error); 1528c2ecf20Sopenharmony_ci vc->error = error; 1538c2ecf20Sopenharmony_ci goto iterate_address; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci case -ECONNRESET: 1568c2ecf20Sopenharmony_ci _debug("call reset"); 1578c2ecf20Sopenharmony_ci vc->error = error; 1588c2ecf20Sopenharmony_ci vc->flags |= AFS_VL_CURSOR_RETRY; 1598c2ecf20Sopenharmony_ci goto next_server; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci case -EOPNOTSUPP: 1628c2ecf20Sopenharmony_ci _debug("notsupp"); 1638c2ecf20Sopenharmony_ci goto next_server; 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cirestart_from_beginning: 1678c2ecf20Sopenharmony_ci _debug("restart"); 1688c2ecf20Sopenharmony_ci afs_end_cursor(&vc->ac); 1698c2ecf20Sopenharmony_ci afs_put_vlserverlist(vc->cell->net, vc->server_list); 1708c2ecf20Sopenharmony_ci vc->server_list = NULL; 1718c2ecf20Sopenharmony_ci if (vc->flags & AFS_VL_CURSOR_RETRIED) 1728c2ecf20Sopenharmony_ci goto failed; 1738c2ecf20Sopenharmony_ci vc->flags |= AFS_VL_CURSOR_RETRIED; 1748c2ecf20Sopenharmony_cistart: 1758c2ecf20Sopenharmony_ci _debug("start"); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci if (!afs_start_vl_iteration(vc)) 1788c2ecf20Sopenharmony_ci goto failed; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci error = afs_send_vl_probes(vc->cell->net, vc->key, vc->server_list); 1818c2ecf20Sopenharmony_ci if (error < 0) 1828c2ecf20Sopenharmony_ci goto failed_set_error; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cipick_server: 1858c2ecf20Sopenharmony_ci _debug("pick [%lx]", vc->untried); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci error = afs_wait_for_vl_probes(vc->server_list, vc->untried); 1888c2ecf20Sopenharmony_ci if (error < 0) 1898c2ecf20Sopenharmony_ci goto failed_set_error; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci /* Pick the untried server with the lowest RTT. */ 1928c2ecf20Sopenharmony_ci vc->index = vc->server_list->preferred; 1938c2ecf20Sopenharmony_ci if (test_bit(vc->index, &vc->untried)) 1948c2ecf20Sopenharmony_ci goto selected_server; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci vc->index = -1; 1978c2ecf20Sopenharmony_ci rtt = U32_MAX; 1988c2ecf20Sopenharmony_ci for (i = 0; i < vc->server_list->nr_servers; i++) { 1998c2ecf20Sopenharmony_ci struct afs_vlserver *s = vc->server_list->servers[i].server; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci if (!test_bit(i, &vc->untried) || 2028c2ecf20Sopenharmony_ci !test_bit(AFS_VLSERVER_FL_RESPONDING, &s->flags)) 2038c2ecf20Sopenharmony_ci continue; 2048c2ecf20Sopenharmony_ci if (s->probe.rtt < rtt) { 2058c2ecf20Sopenharmony_ci vc->index = i; 2068c2ecf20Sopenharmony_ci rtt = s->probe.rtt; 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci if (vc->index == -1) 2118c2ecf20Sopenharmony_ci goto no_more_servers; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ciselected_server: 2148c2ecf20Sopenharmony_ci _debug("use %d", vc->index); 2158c2ecf20Sopenharmony_ci __clear_bit(vc->index, &vc->untried); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci /* We're starting on a different vlserver from the list. We need to 2188c2ecf20Sopenharmony_ci * check it, find its address list and probe its capabilities before we 2198c2ecf20Sopenharmony_ci * use it. 2208c2ecf20Sopenharmony_ci */ 2218c2ecf20Sopenharmony_ci ASSERTCMP(vc->ac.alist, ==, NULL); 2228c2ecf20Sopenharmony_ci vlserver = vc->server_list->servers[vc->index].server; 2238c2ecf20Sopenharmony_ci vc->server = vlserver; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci _debug("USING VLSERVER: %s", vlserver->name); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci read_lock(&vlserver->lock); 2288c2ecf20Sopenharmony_ci alist = rcu_dereference_protected(vlserver->addresses, 2298c2ecf20Sopenharmony_ci lockdep_is_held(&vlserver->lock)); 2308c2ecf20Sopenharmony_ci afs_get_addrlist(alist); 2318c2ecf20Sopenharmony_ci read_unlock(&vlserver->lock); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci memset(&vc->ac, 0, sizeof(vc->ac)); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci if (!vc->ac.alist) 2368c2ecf20Sopenharmony_ci vc->ac.alist = alist; 2378c2ecf20Sopenharmony_ci else 2388c2ecf20Sopenharmony_ci afs_put_addrlist(alist); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci vc->ac.index = -1; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ciiterate_address: 2438c2ecf20Sopenharmony_ci ASSERT(vc->ac.alist); 2448c2ecf20Sopenharmony_ci /* Iterate over the current server's address list to try and find an 2458c2ecf20Sopenharmony_ci * address on which it will respond to us. 2468c2ecf20Sopenharmony_ci */ 2478c2ecf20Sopenharmony_ci if (!afs_iterate_addresses(&vc->ac)) 2488c2ecf20Sopenharmony_ci goto next_server; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci _debug("VL address %d/%d", vc->ac.index, vc->ac.alist->nr_addrs); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci _leave(" = t %pISpc", &vc->ac.alist->addrs[vc->ac.index].transport); 2538c2ecf20Sopenharmony_ci return true; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_cinext_server: 2568c2ecf20Sopenharmony_ci _debug("next"); 2578c2ecf20Sopenharmony_ci afs_end_cursor(&vc->ac); 2588c2ecf20Sopenharmony_ci goto pick_server; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cino_more_servers: 2618c2ecf20Sopenharmony_ci /* That's all the servers poked to no good effect. Try again if some 2628c2ecf20Sopenharmony_ci * of them were busy. 2638c2ecf20Sopenharmony_ci */ 2648c2ecf20Sopenharmony_ci if (vc->flags & AFS_VL_CURSOR_RETRY) 2658c2ecf20Sopenharmony_ci goto restart_from_beginning; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci e.error = -EDESTADDRREQ; 2688c2ecf20Sopenharmony_ci e.responded = false; 2698c2ecf20Sopenharmony_ci for (i = 0; i < vc->server_list->nr_servers; i++) { 2708c2ecf20Sopenharmony_ci struct afs_vlserver *s = vc->server_list->servers[i].server; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci if (test_bit(AFS_VLSERVER_FL_RESPONDING, &s->flags)) 2738c2ecf20Sopenharmony_ci e.responded = true; 2748c2ecf20Sopenharmony_ci afs_prioritise_error(&e, READ_ONCE(s->probe.error), 2758c2ecf20Sopenharmony_ci s->probe.abort_code); 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci error = e.error; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_cifailed_set_error: 2818c2ecf20Sopenharmony_ci vc->error = error; 2828c2ecf20Sopenharmony_cifailed: 2838c2ecf20Sopenharmony_ci vc->flags |= AFS_VL_CURSOR_STOP; 2848c2ecf20Sopenharmony_ci afs_end_cursor(&vc->ac); 2858c2ecf20Sopenharmony_ci _leave(" = f [failed %d]", vc->error); 2868c2ecf20Sopenharmony_ci return false; 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci/* 2908c2ecf20Sopenharmony_ci * Dump cursor state in the case of the error being EDESTADDRREQ. 2918c2ecf20Sopenharmony_ci */ 2928c2ecf20Sopenharmony_cistatic void afs_vl_dump_edestaddrreq(const struct afs_vl_cursor *vc) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci struct afs_cell *cell = vc->cell; 2958c2ecf20Sopenharmony_ci static int count; 2968c2ecf20Sopenharmony_ci int i; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci if (!IS_ENABLED(CONFIG_AFS_DEBUG_CURSOR) || count > 3) 2998c2ecf20Sopenharmony_ci return; 3008c2ecf20Sopenharmony_ci count++; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci rcu_read_lock(); 3038c2ecf20Sopenharmony_ci pr_notice("EDESTADDR occurred\n"); 3048c2ecf20Sopenharmony_ci pr_notice("CELL: %s err=%d\n", cell->name, cell->error); 3058c2ecf20Sopenharmony_ci pr_notice("DNS: src=%u st=%u lc=%x\n", 3068c2ecf20Sopenharmony_ci cell->dns_source, cell->dns_status, cell->dns_lookup_count); 3078c2ecf20Sopenharmony_ci pr_notice("VC: ut=%lx ix=%u ni=%hu fl=%hx err=%hd\n", 3088c2ecf20Sopenharmony_ci vc->untried, vc->index, vc->nr_iterations, vc->flags, vc->error); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci if (vc->server_list) { 3118c2ecf20Sopenharmony_ci const struct afs_vlserver_list *sl = vc->server_list; 3128c2ecf20Sopenharmony_ci pr_notice("VC: SL nr=%u ix=%u\n", 3138c2ecf20Sopenharmony_ci sl->nr_servers, sl->index); 3148c2ecf20Sopenharmony_ci for (i = 0; i < sl->nr_servers; i++) { 3158c2ecf20Sopenharmony_ci const struct afs_vlserver *s = sl->servers[i].server; 3168c2ecf20Sopenharmony_ci pr_notice("VC: server %s+%hu fl=%lx E=%hd\n", 3178c2ecf20Sopenharmony_ci s->name, s->port, s->flags, s->probe.error); 3188c2ecf20Sopenharmony_ci if (s->addresses) { 3198c2ecf20Sopenharmony_ci const struct afs_addr_list *a = 3208c2ecf20Sopenharmony_ci rcu_dereference(s->addresses); 3218c2ecf20Sopenharmony_ci pr_notice("VC: - nr=%u/%u/%u pf=%u\n", 3228c2ecf20Sopenharmony_ci a->nr_ipv4, a->nr_addrs, a->max_addrs, 3238c2ecf20Sopenharmony_ci a->preferred); 3248c2ecf20Sopenharmony_ci pr_notice("VC: - R=%lx F=%lx\n", 3258c2ecf20Sopenharmony_ci a->responded, a->failed); 3268c2ecf20Sopenharmony_ci if (a == vc->ac.alist) 3278c2ecf20Sopenharmony_ci pr_notice("VC: - current\n"); 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci pr_notice("AC: t=%lx ax=%u ac=%d er=%d r=%u ni=%u\n", 3338c2ecf20Sopenharmony_ci vc->ac.tried, vc->ac.index, vc->ac.abort_code, vc->ac.error, 3348c2ecf20Sopenharmony_ci vc->ac.responded, vc->ac.nr_iterations); 3358c2ecf20Sopenharmony_ci rcu_read_unlock(); 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci/* 3398c2ecf20Sopenharmony_ci * Tidy up a volume location server cursor and unlock the vnode. 3408c2ecf20Sopenharmony_ci */ 3418c2ecf20Sopenharmony_ciint afs_end_vlserver_operation(struct afs_vl_cursor *vc) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci struct afs_net *net = vc->cell->net; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci if (vc->error == -EDESTADDRREQ || 3468c2ecf20Sopenharmony_ci vc->error == -EADDRNOTAVAIL || 3478c2ecf20Sopenharmony_ci vc->error == -ENETUNREACH || 3488c2ecf20Sopenharmony_ci vc->error == -EHOSTUNREACH) 3498c2ecf20Sopenharmony_ci afs_vl_dump_edestaddrreq(vc); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci afs_end_cursor(&vc->ac); 3528c2ecf20Sopenharmony_ci afs_put_vlserverlist(net, vc->server_list); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci if (vc->error == -ECONNABORTED) 3558c2ecf20Sopenharmony_ci vc->error = afs_abort_to_error(vc->ac.abort_code); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci return vc->error; 3588c2ecf20Sopenharmony_ci} 359