162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Multipath support for RPC 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2015, 2016, Primary Data, Inc. All rights reserved. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Trond Myklebust <trond.myklebust@primarydata.com> 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci#include <linux/atomic.h> 1162306a36Sopenharmony_ci#include <linux/types.h> 1262306a36Sopenharmony_ci#include <linux/kref.h> 1362306a36Sopenharmony_ci#include <linux/list.h> 1462306a36Sopenharmony_ci#include <linux/rcupdate.h> 1562306a36Sopenharmony_ci#include <linux/rculist.h> 1662306a36Sopenharmony_ci#include <linux/slab.h> 1762306a36Sopenharmony_ci#include <linux/spinlock.h> 1862306a36Sopenharmony_ci#include <linux/sunrpc/xprt.h> 1962306a36Sopenharmony_ci#include <linux/sunrpc/addr.h> 2062306a36Sopenharmony_ci#include <linux/sunrpc/xprtmultipath.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include "sysfs.h" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_citypedef struct rpc_xprt *(*xprt_switch_find_xprt_t)(struct rpc_xprt_switch *xps, 2562306a36Sopenharmony_ci const struct rpc_xprt *cur); 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic const struct rpc_xprt_iter_ops rpc_xprt_iter_singular; 2862306a36Sopenharmony_cistatic const struct rpc_xprt_iter_ops rpc_xprt_iter_roundrobin; 2962306a36Sopenharmony_cistatic const struct rpc_xprt_iter_ops rpc_xprt_iter_listall; 3062306a36Sopenharmony_cistatic const struct rpc_xprt_iter_ops rpc_xprt_iter_listoffline; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic void xprt_switch_add_xprt_locked(struct rpc_xprt_switch *xps, 3362306a36Sopenharmony_ci struct rpc_xprt *xprt) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci if (unlikely(xprt_get(xprt) == NULL)) 3662306a36Sopenharmony_ci return; 3762306a36Sopenharmony_ci list_add_tail_rcu(&xprt->xprt_switch, &xps->xps_xprt_list); 3862306a36Sopenharmony_ci smp_wmb(); 3962306a36Sopenharmony_ci if (xps->xps_nxprts == 0) 4062306a36Sopenharmony_ci xps->xps_net = xprt->xprt_net; 4162306a36Sopenharmony_ci xps->xps_nxprts++; 4262306a36Sopenharmony_ci xps->xps_nactive++; 4362306a36Sopenharmony_ci} 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/** 4662306a36Sopenharmony_ci * rpc_xprt_switch_add_xprt - Add a new rpc_xprt to an rpc_xprt_switch 4762306a36Sopenharmony_ci * @xps: pointer to struct rpc_xprt_switch 4862306a36Sopenharmony_ci * @xprt: pointer to struct rpc_xprt 4962306a36Sopenharmony_ci * 5062306a36Sopenharmony_ci * Adds xprt to the end of the list of struct rpc_xprt in xps. 5162306a36Sopenharmony_ci */ 5262306a36Sopenharmony_civoid rpc_xprt_switch_add_xprt(struct rpc_xprt_switch *xps, 5362306a36Sopenharmony_ci struct rpc_xprt *xprt) 5462306a36Sopenharmony_ci{ 5562306a36Sopenharmony_ci if (xprt == NULL) 5662306a36Sopenharmony_ci return; 5762306a36Sopenharmony_ci spin_lock(&xps->xps_lock); 5862306a36Sopenharmony_ci if (xps->xps_net == xprt->xprt_net || xps->xps_net == NULL) 5962306a36Sopenharmony_ci xprt_switch_add_xprt_locked(xps, xprt); 6062306a36Sopenharmony_ci spin_unlock(&xps->xps_lock); 6162306a36Sopenharmony_ci rpc_sysfs_xprt_setup(xps, xprt, GFP_KERNEL); 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic void xprt_switch_remove_xprt_locked(struct rpc_xprt_switch *xps, 6562306a36Sopenharmony_ci struct rpc_xprt *xprt, bool offline) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci if (unlikely(xprt == NULL)) 6862306a36Sopenharmony_ci return; 6962306a36Sopenharmony_ci if (!test_bit(XPRT_OFFLINE, &xprt->state) && offline) 7062306a36Sopenharmony_ci xps->xps_nactive--; 7162306a36Sopenharmony_ci xps->xps_nxprts--; 7262306a36Sopenharmony_ci if (xps->xps_nxprts == 0) 7362306a36Sopenharmony_ci xps->xps_net = NULL; 7462306a36Sopenharmony_ci smp_wmb(); 7562306a36Sopenharmony_ci list_del_rcu(&xprt->xprt_switch); 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci/** 7962306a36Sopenharmony_ci * rpc_xprt_switch_remove_xprt - Removes an rpc_xprt from a rpc_xprt_switch 8062306a36Sopenharmony_ci * @xps: pointer to struct rpc_xprt_switch 8162306a36Sopenharmony_ci * @xprt: pointer to struct rpc_xprt 8262306a36Sopenharmony_ci * @offline: indicates if the xprt that's being removed is in an offline state 8362306a36Sopenharmony_ci * 8462306a36Sopenharmony_ci * Removes xprt from the list of struct rpc_xprt in xps. 8562306a36Sopenharmony_ci */ 8662306a36Sopenharmony_civoid rpc_xprt_switch_remove_xprt(struct rpc_xprt_switch *xps, 8762306a36Sopenharmony_ci struct rpc_xprt *xprt, bool offline) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci spin_lock(&xps->xps_lock); 9062306a36Sopenharmony_ci xprt_switch_remove_xprt_locked(xps, xprt, offline); 9162306a36Sopenharmony_ci spin_unlock(&xps->xps_lock); 9262306a36Sopenharmony_ci xprt_put(xprt); 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic DEFINE_IDA(rpc_xprtswitch_ids); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_civoid xprt_multipath_cleanup_ids(void) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci ida_destroy(&rpc_xprtswitch_ids); 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic int xprt_switch_alloc_id(struct rpc_xprt_switch *xps, gfp_t gfp_flags) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci int id; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci id = ida_alloc(&rpc_xprtswitch_ids, gfp_flags); 10762306a36Sopenharmony_ci if (id < 0) 10862306a36Sopenharmony_ci return id; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci xps->xps_id = id; 11162306a36Sopenharmony_ci return 0; 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic void xprt_switch_free_id(struct rpc_xprt_switch *xps) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci ida_free(&rpc_xprtswitch_ids, xps->xps_id); 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci/** 12062306a36Sopenharmony_ci * xprt_switch_alloc - Allocate a new struct rpc_xprt_switch 12162306a36Sopenharmony_ci * @xprt: pointer to struct rpc_xprt 12262306a36Sopenharmony_ci * @gfp_flags: allocation flags 12362306a36Sopenharmony_ci * 12462306a36Sopenharmony_ci * On success, returns an initialised struct rpc_xprt_switch, containing 12562306a36Sopenharmony_ci * the entry xprt. Returns NULL on failure. 12662306a36Sopenharmony_ci */ 12762306a36Sopenharmony_cistruct rpc_xprt_switch *xprt_switch_alloc(struct rpc_xprt *xprt, 12862306a36Sopenharmony_ci gfp_t gfp_flags) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci struct rpc_xprt_switch *xps; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci xps = kmalloc(sizeof(*xps), gfp_flags); 13362306a36Sopenharmony_ci if (xps != NULL) { 13462306a36Sopenharmony_ci spin_lock_init(&xps->xps_lock); 13562306a36Sopenharmony_ci kref_init(&xps->xps_kref); 13662306a36Sopenharmony_ci xprt_switch_alloc_id(xps, gfp_flags); 13762306a36Sopenharmony_ci xps->xps_nxprts = xps->xps_nactive = 0; 13862306a36Sopenharmony_ci atomic_long_set(&xps->xps_queuelen, 0); 13962306a36Sopenharmony_ci xps->xps_net = NULL; 14062306a36Sopenharmony_ci INIT_LIST_HEAD(&xps->xps_xprt_list); 14162306a36Sopenharmony_ci xps->xps_iter_ops = &rpc_xprt_iter_singular; 14262306a36Sopenharmony_ci rpc_sysfs_xprt_switch_setup(xps, xprt, gfp_flags); 14362306a36Sopenharmony_ci xprt_switch_add_xprt_locked(xps, xprt); 14462306a36Sopenharmony_ci xps->xps_nunique_destaddr_xprts = 1; 14562306a36Sopenharmony_ci rpc_sysfs_xprt_setup(xps, xprt, gfp_flags); 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci return xps; 14962306a36Sopenharmony_ci} 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_cistatic void xprt_switch_free_entries(struct rpc_xprt_switch *xps) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci spin_lock(&xps->xps_lock); 15462306a36Sopenharmony_ci while (!list_empty(&xps->xps_xprt_list)) { 15562306a36Sopenharmony_ci struct rpc_xprt *xprt; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci xprt = list_first_entry(&xps->xps_xprt_list, 15862306a36Sopenharmony_ci struct rpc_xprt, xprt_switch); 15962306a36Sopenharmony_ci xprt_switch_remove_xprt_locked(xps, xprt, true); 16062306a36Sopenharmony_ci spin_unlock(&xps->xps_lock); 16162306a36Sopenharmony_ci xprt_put(xprt); 16262306a36Sopenharmony_ci spin_lock(&xps->xps_lock); 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci spin_unlock(&xps->xps_lock); 16562306a36Sopenharmony_ci} 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_cistatic void xprt_switch_free(struct kref *kref) 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci struct rpc_xprt_switch *xps = container_of(kref, 17062306a36Sopenharmony_ci struct rpc_xprt_switch, xps_kref); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci xprt_switch_free_entries(xps); 17362306a36Sopenharmony_ci rpc_sysfs_xprt_switch_destroy(xps); 17462306a36Sopenharmony_ci xprt_switch_free_id(xps); 17562306a36Sopenharmony_ci kfree_rcu(xps, xps_rcu); 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci/** 17962306a36Sopenharmony_ci * xprt_switch_get - Return a reference to a rpc_xprt_switch 18062306a36Sopenharmony_ci * @xps: pointer to struct rpc_xprt_switch 18162306a36Sopenharmony_ci * 18262306a36Sopenharmony_ci * Returns a reference to xps unless the refcount is already zero. 18362306a36Sopenharmony_ci */ 18462306a36Sopenharmony_cistruct rpc_xprt_switch *xprt_switch_get(struct rpc_xprt_switch *xps) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci if (xps != NULL && kref_get_unless_zero(&xps->xps_kref)) 18762306a36Sopenharmony_ci return xps; 18862306a36Sopenharmony_ci return NULL; 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci/** 19262306a36Sopenharmony_ci * xprt_switch_put - Release a reference to a rpc_xprt_switch 19362306a36Sopenharmony_ci * @xps: pointer to struct rpc_xprt_switch 19462306a36Sopenharmony_ci * 19562306a36Sopenharmony_ci * Release the reference to xps, and free it once the refcount is zero. 19662306a36Sopenharmony_ci */ 19762306a36Sopenharmony_civoid xprt_switch_put(struct rpc_xprt_switch *xps) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci if (xps != NULL) 20062306a36Sopenharmony_ci kref_put(&xps->xps_kref, xprt_switch_free); 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci/** 20462306a36Sopenharmony_ci * rpc_xprt_switch_set_roundrobin - Set a round-robin policy on rpc_xprt_switch 20562306a36Sopenharmony_ci * @xps: pointer to struct rpc_xprt_switch 20662306a36Sopenharmony_ci * 20762306a36Sopenharmony_ci * Sets a round-robin default policy for iterators acting on xps. 20862306a36Sopenharmony_ci */ 20962306a36Sopenharmony_civoid rpc_xprt_switch_set_roundrobin(struct rpc_xprt_switch *xps) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci if (READ_ONCE(xps->xps_iter_ops) != &rpc_xprt_iter_roundrobin) 21262306a36Sopenharmony_ci WRITE_ONCE(xps->xps_iter_ops, &rpc_xprt_iter_roundrobin); 21362306a36Sopenharmony_ci} 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_cistatic 21662306a36Sopenharmony_ciconst struct rpc_xprt_iter_ops *xprt_iter_ops(const struct rpc_xprt_iter *xpi) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci if (xpi->xpi_ops != NULL) 21962306a36Sopenharmony_ci return xpi->xpi_ops; 22062306a36Sopenharmony_ci return rcu_dereference(xpi->xpi_xpswitch)->xps_iter_ops; 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_cistatic 22462306a36Sopenharmony_civoid xprt_iter_no_rewind(struct rpc_xprt_iter *xpi) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_cistatic 22962306a36Sopenharmony_civoid xprt_iter_default_rewind(struct rpc_xprt_iter *xpi) 23062306a36Sopenharmony_ci{ 23162306a36Sopenharmony_ci WRITE_ONCE(xpi->xpi_cursor, NULL); 23262306a36Sopenharmony_ci} 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_cistatic 23562306a36Sopenharmony_cibool xprt_is_active(const struct rpc_xprt *xprt) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci return (kref_read(&xprt->kref) != 0 && 23862306a36Sopenharmony_ci !test_bit(XPRT_OFFLINE, &xprt->state)); 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistatic 24262306a36Sopenharmony_cistruct rpc_xprt *xprt_switch_find_first_entry(struct list_head *head) 24362306a36Sopenharmony_ci{ 24462306a36Sopenharmony_ci struct rpc_xprt *pos; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci list_for_each_entry_rcu(pos, head, xprt_switch) { 24762306a36Sopenharmony_ci if (xprt_is_active(pos)) 24862306a36Sopenharmony_ci return pos; 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci return NULL; 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cistatic 25462306a36Sopenharmony_cistruct rpc_xprt *xprt_switch_find_first_entry_offline(struct list_head *head) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci struct rpc_xprt *pos; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci list_for_each_entry_rcu(pos, head, xprt_switch) { 25962306a36Sopenharmony_ci if (!xprt_is_active(pos)) 26062306a36Sopenharmony_ci return pos; 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci return NULL; 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_cistatic 26662306a36Sopenharmony_cistruct rpc_xprt *xprt_iter_first_entry(struct rpc_xprt_iter *xpi) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci struct rpc_xprt_switch *xps = rcu_dereference(xpi->xpi_xpswitch); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci if (xps == NULL) 27162306a36Sopenharmony_ci return NULL; 27262306a36Sopenharmony_ci return xprt_switch_find_first_entry(&xps->xps_xprt_list); 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_cistatic 27662306a36Sopenharmony_cistruct rpc_xprt *_xprt_switch_find_current_entry(struct list_head *head, 27762306a36Sopenharmony_ci const struct rpc_xprt *cur, 27862306a36Sopenharmony_ci bool find_active) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci struct rpc_xprt *pos; 28162306a36Sopenharmony_ci bool found = false; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci list_for_each_entry_rcu(pos, head, xprt_switch) { 28462306a36Sopenharmony_ci if (cur == pos) 28562306a36Sopenharmony_ci found = true; 28662306a36Sopenharmony_ci if (found && ((find_active && xprt_is_active(pos)) || 28762306a36Sopenharmony_ci (!find_active && !xprt_is_active(pos)))) 28862306a36Sopenharmony_ci return pos; 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci return NULL; 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cistatic 29462306a36Sopenharmony_cistruct rpc_xprt *xprt_switch_find_current_entry(struct list_head *head, 29562306a36Sopenharmony_ci const struct rpc_xprt *cur) 29662306a36Sopenharmony_ci{ 29762306a36Sopenharmony_ci return _xprt_switch_find_current_entry(head, cur, true); 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_cistatic 30162306a36Sopenharmony_cistruct rpc_xprt * _xprt_iter_current_entry(struct rpc_xprt_iter *xpi, 30262306a36Sopenharmony_ci struct rpc_xprt *first_entry(struct list_head *head), 30362306a36Sopenharmony_ci struct rpc_xprt *current_entry(struct list_head *head, 30462306a36Sopenharmony_ci const struct rpc_xprt *cur)) 30562306a36Sopenharmony_ci{ 30662306a36Sopenharmony_ci struct rpc_xprt_switch *xps = rcu_dereference(xpi->xpi_xpswitch); 30762306a36Sopenharmony_ci struct list_head *head; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci if (xps == NULL) 31062306a36Sopenharmony_ci return NULL; 31162306a36Sopenharmony_ci head = &xps->xps_xprt_list; 31262306a36Sopenharmony_ci if (xpi->xpi_cursor == NULL || xps->xps_nxprts < 2) 31362306a36Sopenharmony_ci return first_entry(head); 31462306a36Sopenharmony_ci return current_entry(head, xpi->xpi_cursor); 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_cistatic 31862306a36Sopenharmony_cistruct rpc_xprt *xprt_iter_current_entry(struct rpc_xprt_iter *xpi) 31962306a36Sopenharmony_ci{ 32062306a36Sopenharmony_ci return _xprt_iter_current_entry(xpi, xprt_switch_find_first_entry, 32162306a36Sopenharmony_ci xprt_switch_find_current_entry); 32262306a36Sopenharmony_ci} 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_cistatic 32562306a36Sopenharmony_cistruct rpc_xprt *xprt_switch_find_current_entry_offline(struct list_head *head, 32662306a36Sopenharmony_ci const struct rpc_xprt *cur) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci return _xprt_switch_find_current_entry(head, cur, false); 32962306a36Sopenharmony_ci} 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_cistatic 33262306a36Sopenharmony_cistruct rpc_xprt *xprt_iter_current_entry_offline(struct rpc_xprt_iter *xpi) 33362306a36Sopenharmony_ci{ 33462306a36Sopenharmony_ci return _xprt_iter_current_entry(xpi, 33562306a36Sopenharmony_ci xprt_switch_find_first_entry_offline, 33662306a36Sopenharmony_ci xprt_switch_find_current_entry_offline); 33762306a36Sopenharmony_ci} 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_cistatic 34062306a36Sopenharmony_cibool __rpc_xprt_switch_has_addr(struct rpc_xprt_switch *xps, 34162306a36Sopenharmony_ci const struct sockaddr *sap) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci struct list_head *head; 34462306a36Sopenharmony_ci struct rpc_xprt *pos; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci if (xps == NULL || sap == NULL) 34762306a36Sopenharmony_ci return false; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci head = &xps->xps_xprt_list; 35062306a36Sopenharmony_ci list_for_each_entry_rcu(pos, head, xprt_switch) { 35162306a36Sopenharmony_ci if (rpc_cmp_addr_port(sap, (struct sockaddr *)&pos->addr)) { 35262306a36Sopenharmony_ci pr_info("RPC: addr %s already in xprt switch\n", 35362306a36Sopenharmony_ci pos->address_strings[RPC_DISPLAY_ADDR]); 35462306a36Sopenharmony_ci return true; 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci return false; 35862306a36Sopenharmony_ci} 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_cibool rpc_xprt_switch_has_addr(struct rpc_xprt_switch *xps, 36162306a36Sopenharmony_ci const struct sockaddr *sap) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci bool res; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci rcu_read_lock(); 36662306a36Sopenharmony_ci res = __rpc_xprt_switch_has_addr(xps, sap); 36762306a36Sopenharmony_ci rcu_read_unlock(); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci return res; 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_cistatic 37362306a36Sopenharmony_cistruct rpc_xprt *xprt_switch_find_next_entry(struct list_head *head, 37462306a36Sopenharmony_ci const struct rpc_xprt *cur, bool check_active) 37562306a36Sopenharmony_ci{ 37662306a36Sopenharmony_ci struct rpc_xprt *pos, *prev = NULL; 37762306a36Sopenharmony_ci bool found = false; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci list_for_each_entry_rcu(pos, head, xprt_switch) { 38062306a36Sopenharmony_ci if (cur == prev) 38162306a36Sopenharmony_ci found = true; 38262306a36Sopenharmony_ci /* for request to return active transports return only 38362306a36Sopenharmony_ci * active, for request to return offline transports 38462306a36Sopenharmony_ci * return only offline 38562306a36Sopenharmony_ci */ 38662306a36Sopenharmony_ci if (found && ((check_active && xprt_is_active(pos)) || 38762306a36Sopenharmony_ci (!check_active && !xprt_is_active(pos)))) 38862306a36Sopenharmony_ci return pos; 38962306a36Sopenharmony_ci prev = pos; 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci return NULL; 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_cistatic 39562306a36Sopenharmony_cistruct rpc_xprt *xprt_switch_set_next_cursor(struct rpc_xprt_switch *xps, 39662306a36Sopenharmony_ci struct rpc_xprt **cursor, 39762306a36Sopenharmony_ci xprt_switch_find_xprt_t find_next) 39862306a36Sopenharmony_ci{ 39962306a36Sopenharmony_ci struct rpc_xprt *pos, *old; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci old = smp_load_acquire(cursor); 40262306a36Sopenharmony_ci pos = find_next(xps, old); 40362306a36Sopenharmony_ci smp_store_release(cursor, pos); 40462306a36Sopenharmony_ci return pos; 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_cistatic 40862306a36Sopenharmony_cistruct rpc_xprt *xprt_iter_next_entry_multiple(struct rpc_xprt_iter *xpi, 40962306a36Sopenharmony_ci xprt_switch_find_xprt_t find_next) 41062306a36Sopenharmony_ci{ 41162306a36Sopenharmony_ci struct rpc_xprt_switch *xps = rcu_dereference(xpi->xpi_xpswitch); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci if (xps == NULL) 41462306a36Sopenharmony_ci return NULL; 41562306a36Sopenharmony_ci return xprt_switch_set_next_cursor(xps, &xpi->xpi_cursor, find_next); 41662306a36Sopenharmony_ci} 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_cistatic 41962306a36Sopenharmony_cistruct rpc_xprt *__xprt_switch_find_next_entry_roundrobin(struct list_head *head, 42062306a36Sopenharmony_ci const struct rpc_xprt *cur) 42162306a36Sopenharmony_ci{ 42262306a36Sopenharmony_ci struct rpc_xprt *ret; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci ret = xprt_switch_find_next_entry(head, cur, true); 42562306a36Sopenharmony_ci if (ret != NULL) 42662306a36Sopenharmony_ci return ret; 42762306a36Sopenharmony_ci return xprt_switch_find_first_entry(head); 42862306a36Sopenharmony_ci} 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_cistatic 43162306a36Sopenharmony_cistruct rpc_xprt *xprt_switch_find_next_entry_roundrobin(struct rpc_xprt_switch *xps, 43262306a36Sopenharmony_ci const struct rpc_xprt *cur) 43362306a36Sopenharmony_ci{ 43462306a36Sopenharmony_ci struct list_head *head = &xps->xps_xprt_list; 43562306a36Sopenharmony_ci struct rpc_xprt *xprt; 43662306a36Sopenharmony_ci unsigned int nactive; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci for (;;) { 43962306a36Sopenharmony_ci unsigned long xprt_queuelen, xps_queuelen; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci xprt = __xprt_switch_find_next_entry_roundrobin(head, cur); 44262306a36Sopenharmony_ci if (!xprt) 44362306a36Sopenharmony_ci break; 44462306a36Sopenharmony_ci xprt_queuelen = atomic_long_read(&xprt->queuelen); 44562306a36Sopenharmony_ci xps_queuelen = atomic_long_read(&xps->xps_queuelen); 44662306a36Sopenharmony_ci nactive = READ_ONCE(xps->xps_nactive); 44762306a36Sopenharmony_ci /* Exit loop if xprt_queuelen <= average queue length */ 44862306a36Sopenharmony_ci if (xprt_queuelen * nactive <= xps_queuelen) 44962306a36Sopenharmony_ci break; 45062306a36Sopenharmony_ci cur = xprt; 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci return xprt; 45362306a36Sopenharmony_ci} 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_cistatic 45662306a36Sopenharmony_cistruct rpc_xprt *xprt_iter_next_entry_roundrobin(struct rpc_xprt_iter *xpi) 45762306a36Sopenharmony_ci{ 45862306a36Sopenharmony_ci return xprt_iter_next_entry_multiple(xpi, 45962306a36Sopenharmony_ci xprt_switch_find_next_entry_roundrobin); 46062306a36Sopenharmony_ci} 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_cistatic 46362306a36Sopenharmony_cistruct rpc_xprt *xprt_switch_find_next_entry_all(struct rpc_xprt_switch *xps, 46462306a36Sopenharmony_ci const struct rpc_xprt *cur) 46562306a36Sopenharmony_ci{ 46662306a36Sopenharmony_ci return xprt_switch_find_next_entry(&xps->xps_xprt_list, cur, true); 46762306a36Sopenharmony_ci} 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_cistatic 47062306a36Sopenharmony_cistruct rpc_xprt *xprt_switch_find_next_entry_offline(struct rpc_xprt_switch *xps, 47162306a36Sopenharmony_ci const struct rpc_xprt *cur) 47262306a36Sopenharmony_ci{ 47362306a36Sopenharmony_ci return xprt_switch_find_next_entry(&xps->xps_xprt_list, cur, false); 47462306a36Sopenharmony_ci} 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_cistatic 47762306a36Sopenharmony_cistruct rpc_xprt *xprt_iter_next_entry_all(struct rpc_xprt_iter *xpi) 47862306a36Sopenharmony_ci{ 47962306a36Sopenharmony_ci return xprt_iter_next_entry_multiple(xpi, 48062306a36Sopenharmony_ci xprt_switch_find_next_entry_all); 48162306a36Sopenharmony_ci} 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_cistatic 48462306a36Sopenharmony_cistruct rpc_xprt *xprt_iter_next_entry_offline(struct rpc_xprt_iter *xpi) 48562306a36Sopenharmony_ci{ 48662306a36Sopenharmony_ci return xprt_iter_next_entry_multiple(xpi, 48762306a36Sopenharmony_ci xprt_switch_find_next_entry_offline); 48862306a36Sopenharmony_ci} 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci/* 49162306a36Sopenharmony_ci * xprt_iter_rewind - Resets the xprt iterator 49262306a36Sopenharmony_ci * @xpi: pointer to rpc_xprt_iter 49362306a36Sopenharmony_ci * 49462306a36Sopenharmony_ci * Resets xpi to ensure that it points to the first entry in the list 49562306a36Sopenharmony_ci * of transports. 49662306a36Sopenharmony_ci */ 49762306a36Sopenharmony_civoid xprt_iter_rewind(struct rpc_xprt_iter *xpi) 49862306a36Sopenharmony_ci{ 49962306a36Sopenharmony_ci rcu_read_lock(); 50062306a36Sopenharmony_ci xprt_iter_ops(xpi)->xpi_rewind(xpi); 50162306a36Sopenharmony_ci rcu_read_unlock(); 50262306a36Sopenharmony_ci} 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_cistatic void __xprt_iter_init(struct rpc_xprt_iter *xpi, 50562306a36Sopenharmony_ci struct rpc_xprt_switch *xps, 50662306a36Sopenharmony_ci const struct rpc_xprt_iter_ops *ops) 50762306a36Sopenharmony_ci{ 50862306a36Sopenharmony_ci rcu_assign_pointer(xpi->xpi_xpswitch, xprt_switch_get(xps)); 50962306a36Sopenharmony_ci xpi->xpi_cursor = NULL; 51062306a36Sopenharmony_ci xpi->xpi_ops = ops; 51162306a36Sopenharmony_ci} 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci/** 51462306a36Sopenharmony_ci * xprt_iter_init - Initialise an xprt iterator 51562306a36Sopenharmony_ci * @xpi: pointer to rpc_xprt_iter 51662306a36Sopenharmony_ci * @xps: pointer to rpc_xprt_switch 51762306a36Sopenharmony_ci * 51862306a36Sopenharmony_ci * Initialises the iterator to use the default iterator ops 51962306a36Sopenharmony_ci * as set in xps. This function is mainly intended for internal 52062306a36Sopenharmony_ci * use in the rpc_client. 52162306a36Sopenharmony_ci */ 52262306a36Sopenharmony_civoid xprt_iter_init(struct rpc_xprt_iter *xpi, 52362306a36Sopenharmony_ci struct rpc_xprt_switch *xps) 52462306a36Sopenharmony_ci{ 52562306a36Sopenharmony_ci __xprt_iter_init(xpi, xps, NULL); 52662306a36Sopenharmony_ci} 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci/** 52962306a36Sopenharmony_ci * xprt_iter_init_listall - Initialise an xprt iterator 53062306a36Sopenharmony_ci * @xpi: pointer to rpc_xprt_iter 53162306a36Sopenharmony_ci * @xps: pointer to rpc_xprt_switch 53262306a36Sopenharmony_ci * 53362306a36Sopenharmony_ci * Initialises the iterator to iterate once through the entire list 53462306a36Sopenharmony_ci * of entries in xps. 53562306a36Sopenharmony_ci */ 53662306a36Sopenharmony_civoid xprt_iter_init_listall(struct rpc_xprt_iter *xpi, 53762306a36Sopenharmony_ci struct rpc_xprt_switch *xps) 53862306a36Sopenharmony_ci{ 53962306a36Sopenharmony_ci __xprt_iter_init(xpi, xps, &rpc_xprt_iter_listall); 54062306a36Sopenharmony_ci} 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_civoid xprt_iter_init_listoffline(struct rpc_xprt_iter *xpi, 54362306a36Sopenharmony_ci struct rpc_xprt_switch *xps) 54462306a36Sopenharmony_ci{ 54562306a36Sopenharmony_ci __xprt_iter_init(xpi, xps, &rpc_xprt_iter_listoffline); 54662306a36Sopenharmony_ci} 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci/** 54962306a36Sopenharmony_ci * xprt_iter_xchg_switch - Atomically swap out the rpc_xprt_switch 55062306a36Sopenharmony_ci * @xpi: pointer to rpc_xprt_iter 55162306a36Sopenharmony_ci * @newswitch: pointer to a new rpc_xprt_switch or NULL 55262306a36Sopenharmony_ci * 55362306a36Sopenharmony_ci * Swaps out the existing xpi->xpi_xpswitch with a new value. 55462306a36Sopenharmony_ci */ 55562306a36Sopenharmony_cistruct rpc_xprt_switch *xprt_iter_xchg_switch(struct rpc_xprt_iter *xpi, 55662306a36Sopenharmony_ci struct rpc_xprt_switch *newswitch) 55762306a36Sopenharmony_ci{ 55862306a36Sopenharmony_ci struct rpc_xprt_switch __rcu *oldswitch; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci /* Atomically swap out the old xpswitch */ 56162306a36Sopenharmony_ci oldswitch = xchg(&xpi->xpi_xpswitch, RCU_INITIALIZER(newswitch)); 56262306a36Sopenharmony_ci if (newswitch != NULL) 56362306a36Sopenharmony_ci xprt_iter_rewind(xpi); 56462306a36Sopenharmony_ci return rcu_dereference_protected(oldswitch, true); 56562306a36Sopenharmony_ci} 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci/** 56862306a36Sopenharmony_ci * xprt_iter_destroy - Destroys the xprt iterator 56962306a36Sopenharmony_ci * @xpi: pointer to rpc_xprt_iter 57062306a36Sopenharmony_ci */ 57162306a36Sopenharmony_civoid xprt_iter_destroy(struct rpc_xprt_iter *xpi) 57262306a36Sopenharmony_ci{ 57362306a36Sopenharmony_ci xprt_switch_put(xprt_iter_xchg_switch(xpi, NULL)); 57462306a36Sopenharmony_ci} 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci/** 57762306a36Sopenharmony_ci * xprt_iter_xprt - Returns the rpc_xprt pointed to by the cursor 57862306a36Sopenharmony_ci * @xpi: pointer to rpc_xprt_iter 57962306a36Sopenharmony_ci * 58062306a36Sopenharmony_ci * Returns a pointer to the struct rpc_xprt that is currently 58162306a36Sopenharmony_ci * pointed to by the cursor. 58262306a36Sopenharmony_ci * Caller must be holding rcu_read_lock(). 58362306a36Sopenharmony_ci */ 58462306a36Sopenharmony_cistruct rpc_xprt *xprt_iter_xprt(struct rpc_xprt_iter *xpi) 58562306a36Sopenharmony_ci{ 58662306a36Sopenharmony_ci WARN_ON_ONCE(!rcu_read_lock_held()); 58762306a36Sopenharmony_ci return xprt_iter_ops(xpi)->xpi_xprt(xpi); 58862306a36Sopenharmony_ci} 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_cistatic 59162306a36Sopenharmony_cistruct rpc_xprt *xprt_iter_get_helper(struct rpc_xprt_iter *xpi, 59262306a36Sopenharmony_ci struct rpc_xprt *(*fn)(struct rpc_xprt_iter *)) 59362306a36Sopenharmony_ci{ 59462306a36Sopenharmony_ci struct rpc_xprt *ret; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci do { 59762306a36Sopenharmony_ci ret = fn(xpi); 59862306a36Sopenharmony_ci if (ret == NULL) 59962306a36Sopenharmony_ci break; 60062306a36Sopenharmony_ci ret = xprt_get(ret); 60162306a36Sopenharmony_ci } while (ret == NULL); 60262306a36Sopenharmony_ci return ret; 60362306a36Sopenharmony_ci} 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci/** 60662306a36Sopenharmony_ci * xprt_iter_get_xprt - Returns the rpc_xprt pointed to by the cursor 60762306a36Sopenharmony_ci * @xpi: pointer to rpc_xprt_iter 60862306a36Sopenharmony_ci * 60962306a36Sopenharmony_ci * Returns a reference to the struct rpc_xprt that is currently 61062306a36Sopenharmony_ci * pointed to by the cursor. 61162306a36Sopenharmony_ci */ 61262306a36Sopenharmony_cistruct rpc_xprt *xprt_iter_get_xprt(struct rpc_xprt_iter *xpi) 61362306a36Sopenharmony_ci{ 61462306a36Sopenharmony_ci struct rpc_xprt *xprt; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci rcu_read_lock(); 61762306a36Sopenharmony_ci xprt = xprt_iter_get_helper(xpi, xprt_iter_ops(xpi)->xpi_xprt); 61862306a36Sopenharmony_ci rcu_read_unlock(); 61962306a36Sopenharmony_ci return xprt; 62062306a36Sopenharmony_ci} 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci/** 62362306a36Sopenharmony_ci * xprt_iter_get_next - Returns the next rpc_xprt following the cursor 62462306a36Sopenharmony_ci * @xpi: pointer to rpc_xprt_iter 62562306a36Sopenharmony_ci * 62662306a36Sopenharmony_ci * Returns a reference to the struct rpc_xprt that immediately follows the 62762306a36Sopenharmony_ci * entry pointed to by the cursor. 62862306a36Sopenharmony_ci */ 62962306a36Sopenharmony_cistruct rpc_xprt *xprt_iter_get_next(struct rpc_xprt_iter *xpi) 63062306a36Sopenharmony_ci{ 63162306a36Sopenharmony_ci struct rpc_xprt *xprt; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci rcu_read_lock(); 63462306a36Sopenharmony_ci xprt = xprt_iter_get_helper(xpi, xprt_iter_ops(xpi)->xpi_next); 63562306a36Sopenharmony_ci rcu_read_unlock(); 63662306a36Sopenharmony_ci return xprt; 63762306a36Sopenharmony_ci} 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci/* Policy for always returning the first entry in the rpc_xprt_switch */ 64062306a36Sopenharmony_cistatic 64162306a36Sopenharmony_ciconst struct rpc_xprt_iter_ops rpc_xprt_iter_singular = { 64262306a36Sopenharmony_ci .xpi_rewind = xprt_iter_no_rewind, 64362306a36Sopenharmony_ci .xpi_xprt = xprt_iter_first_entry, 64462306a36Sopenharmony_ci .xpi_next = xprt_iter_first_entry, 64562306a36Sopenharmony_ci}; 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci/* Policy for round-robin iteration of entries in the rpc_xprt_switch */ 64862306a36Sopenharmony_cistatic 64962306a36Sopenharmony_ciconst struct rpc_xprt_iter_ops rpc_xprt_iter_roundrobin = { 65062306a36Sopenharmony_ci .xpi_rewind = xprt_iter_default_rewind, 65162306a36Sopenharmony_ci .xpi_xprt = xprt_iter_current_entry, 65262306a36Sopenharmony_ci .xpi_next = xprt_iter_next_entry_roundrobin, 65362306a36Sopenharmony_ci}; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci/* Policy for once-through iteration of entries in the rpc_xprt_switch */ 65662306a36Sopenharmony_cistatic 65762306a36Sopenharmony_ciconst struct rpc_xprt_iter_ops rpc_xprt_iter_listall = { 65862306a36Sopenharmony_ci .xpi_rewind = xprt_iter_default_rewind, 65962306a36Sopenharmony_ci .xpi_xprt = xprt_iter_current_entry, 66062306a36Sopenharmony_ci .xpi_next = xprt_iter_next_entry_all, 66162306a36Sopenharmony_ci}; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_cistatic 66462306a36Sopenharmony_ciconst struct rpc_xprt_iter_ops rpc_xprt_iter_listoffline = { 66562306a36Sopenharmony_ci .xpi_rewind = xprt_iter_default_rewind, 66662306a36Sopenharmony_ci .xpi_xprt = xprt_iter_current_entry_offline, 66762306a36Sopenharmony_ci .xpi_next = xprt_iter_next_entry_offline, 66862306a36Sopenharmony_ci}; 669