1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 280b14d5eSTrond Myklebust /* 380b14d5eSTrond Myklebust * Multipath support for RPC 480b14d5eSTrond Myklebust * 580b14d5eSTrond Myklebust * Copyright (c) 2015, 2016, Primary Data, Inc. All rights reserved. 680b14d5eSTrond Myklebust * 780b14d5eSTrond Myklebust * Trond Myklebust <trond.myklebust@primarydata.com> 880b14d5eSTrond Myklebust * 980b14d5eSTrond Myklebust */ 10201e2c1bSMark Rutland #include <linux/atomic.h> 1180b14d5eSTrond Myklebust #include <linux/types.h> 1280b14d5eSTrond Myklebust #include <linux/kref.h> 1380b14d5eSTrond Myklebust #include <linux/list.h> 1480b14d5eSTrond Myklebust #include <linux/rcupdate.h> 1580b14d5eSTrond Myklebust #include <linux/rculist.h> 1680b14d5eSTrond Myklebust #include <linux/slab.h> 1780b14d5eSTrond Myklebust #include <linux/spinlock.h> 1880b14d5eSTrond Myklebust #include <linux/sunrpc/xprt.h> 1939e5d2dfSAndy Adamson #include <linux/sunrpc/addr.h> 2080b14d5eSTrond Myklebust #include <linux/sunrpc/xprtmultipath.h> 2180b14d5eSTrond Myklebust 22baea9944SOlga Kornievskaia #include "sysfs.h" 23baea9944SOlga Kornievskaia 24f554af28STrond Myklebust typedef struct rpc_xprt *(*xprt_switch_find_xprt_t)(struct rpc_xprt_switch *xps, 2580b14d5eSTrond Myklebust const struct rpc_xprt *cur); 2680b14d5eSTrond Myklebust 2780b14d5eSTrond Myklebust static const struct rpc_xprt_iter_ops rpc_xprt_iter_singular; 2880b14d5eSTrond Myklebust static const struct rpc_xprt_iter_ops rpc_xprt_iter_roundrobin; 2980b14d5eSTrond Myklebust static const struct rpc_xprt_iter_ops rpc_xprt_iter_listall; 30*95d0d30cSOlga Kornievskaia static const struct rpc_xprt_iter_ops rpc_xprt_iter_listoffline; 3180b14d5eSTrond Myklebust 3280b14d5eSTrond Myklebust static void xprt_switch_add_xprt_locked(struct rpc_xprt_switch *xps, 3380b14d5eSTrond Myklebust struct rpc_xprt *xprt) 3480b14d5eSTrond Myklebust { 3580b14d5eSTrond Myklebust if (unlikely(xprt_get(xprt) == NULL)) 3680b14d5eSTrond Myklebust return; 3780b14d5eSTrond Myklebust list_add_tail_rcu(&xprt->xprt_switch, &xps->xps_xprt_list); 3880b14d5eSTrond Myklebust smp_wmb(); 3980b14d5eSTrond Myklebust if (xps->xps_nxprts == 0) 4080b14d5eSTrond Myklebust xps->xps_net = xprt->xprt_net; 4180b14d5eSTrond Myklebust xps->xps_nxprts++; 4221f0ffafSTrond Myklebust xps->xps_nactive++; 4380b14d5eSTrond Myklebust } 4480b14d5eSTrond Myklebust 4580b14d5eSTrond Myklebust /** 4680b14d5eSTrond Myklebust * rpc_xprt_switch_add_xprt - Add a new rpc_xprt to an rpc_xprt_switch 4780b14d5eSTrond Myklebust * @xps: pointer to struct rpc_xprt_switch 4880b14d5eSTrond Myklebust * @xprt: pointer to struct rpc_xprt 4980b14d5eSTrond Myklebust * 5080b14d5eSTrond Myklebust * Adds xprt to the end of the list of struct rpc_xprt in xps. 5180b14d5eSTrond Myklebust */ 5280b14d5eSTrond Myklebust void rpc_xprt_switch_add_xprt(struct rpc_xprt_switch *xps, 5380b14d5eSTrond Myklebust struct rpc_xprt *xprt) 5480b14d5eSTrond Myklebust { 5580b14d5eSTrond Myklebust if (xprt == NULL) 5680b14d5eSTrond Myklebust return; 5780b14d5eSTrond Myklebust spin_lock(&xps->xps_lock); 58612b41f8STrond Myklebust if (xps->xps_net == xprt->xprt_net || xps->xps_net == NULL) 5980b14d5eSTrond Myklebust xprt_switch_add_xprt_locked(xps, xprt); 6080b14d5eSTrond Myklebust spin_unlock(&xps->xps_lock); 61d408ebe0SOlga Kornievskaia rpc_sysfs_xprt_setup(xps, xprt, GFP_KERNEL); 6280b14d5eSTrond Myklebust } 6380b14d5eSTrond Myklebust 6480b14d5eSTrond Myklebust static void xprt_switch_remove_xprt_locked(struct rpc_xprt_switch *xps, 6580b14d5eSTrond Myklebust struct rpc_xprt *xprt) 6680b14d5eSTrond Myklebust { 6780b14d5eSTrond Myklebust if (unlikely(xprt == NULL)) 6880b14d5eSTrond Myklebust return; 695b7eb784SOlga Kornievskaia if (!test_bit(XPRT_OFFLINE, &xprt->state)) 7021f0ffafSTrond Myklebust xps->xps_nactive--; 7180b14d5eSTrond Myklebust xps->xps_nxprts--; 7280b14d5eSTrond Myklebust if (xps->xps_nxprts == 0) 7380b14d5eSTrond Myklebust xps->xps_net = NULL; 7480b14d5eSTrond Myklebust smp_wmb(); 7580b14d5eSTrond Myklebust list_del_rcu(&xprt->xprt_switch); 7680b14d5eSTrond Myklebust } 7780b14d5eSTrond Myklebust 7880b14d5eSTrond Myklebust /** 7980b14d5eSTrond Myklebust * rpc_xprt_switch_remove_xprt - Removes an rpc_xprt from a rpc_xprt_switch 8080b14d5eSTrond Myklebust * @xps: pointer to struct rpc_xprt_switch 8180b14d5eSTrond Myklebust * @xprt: pointer to struct rpc_xprt 8280b14d5eSTrond Myklebust * 8380b14d5eSTrond Myklebust * Removes xprt from the list of struct rpc_xprt in xps. 8480b14d5eSTrond Myklebust */ 8580b14d5eSTrond Myklebust void rpc_xprt_switch_remove_xprt(struct rpc_xprt_switch *xps, 8680b14d5eSTrond Myklebust struct rpc_xprt *xprt) 8780b14d5eSTrond Myklebust { 8880b14d5eSTrond Myklebust spin_lock(&xps->xps_lock); 8980b14d5eSTrond Myklebust xprt_switch_remove_xprt_locked(xps, xprt); 9080b14d5eSTrond Myklebust spin_unlock(&xps->xps_lock); 9180b14d5eSTrond Myklebust xprt_put(xprt); 9280b14d5eSTrond Myklebust } 9380b14d5eSTrond Myklebust 945b926872SOlga Kornievskaia static DEFINE_IDA(rpc_xprtswitch_ids); 955b926872SOlga Kornievskaia 965b926872SOlga Kornievskaia void xprt_multipath_cleanup_ids(void) 975b926872SOlga Kornievskaia { 985b926872SOlga Kornievskaia ida_destroy(&rpc_xprtswitch_ids); 995b926872SOlga Kornievskaia } 1005b926872SOlga Kornievskaia 1015b926872SOlga Kornievskaia static int xprt_switch_alloc_id(struct rpc_xprt_switch *xps, gfp_t gfp_flags) 1025b926872SOlga Kornievskaia { 1035b926872SOlga Kornievskaia int id; 1045b926872SOlga Kornievskaia 1055b926872SOlga Kornievskaia id = ida_simple_get(&rpc_xprtswitch_ids, 0, 0, gfp_flags); 1065b926872SOlga Kornievskaia if (id < 0) 1075b926872SOlga Kornievskaia return id; 1085b926872SOlga Kornievskaia 1095b926872SOlga Kornievskaia xps->xps_id = id; 1105b926872SOlga Kornievskaia return 0; 1115b926872SOlga Kornievskaia } 1125b926872SOlga Kornievskaia 1135b926872SOlga Kornievskaia static void xprt_switch_free_id(struct rpc_xprt_switch *xps) 1145b926872SOlga Kornievskaia { 1155b926872SOlga Kornievskaia ida_simple_remove(&rpc_xprtswitch_ids, xps->xps_id); 1165b926872SOlga Kornievskaia } 1175b926872SOlga Kornievskaia 11880b14d5eSTrond Myklebust /** 11980b14d5eSTrond Myklebust * xprt_switch_alloc - Allocate a new struct rpc_xprt_switch 12080b14d5eSTrond Myklebust * @xprt: pointer to struct rpc_xprt 12180b14d5eSTrond Myklebust * @gfp_flags: allocation flags 12280b14d5eSTrond Myklebust * 12380b14d5eSTrond Myklebust * On success, returns an initialised struct rpc_xprt_switch, containing 12480b14d5eSTrond Myklebust * the entry xprt. Returns NULL on failure. 12580b14d5eSTrond Myklebust */ 12680b14d5eSTrond Myklebust struct rpc_xprt_switch *xprt_switch_alloc(struct rpc_xprt *xprt, 12780b14d5eSTrond Myklebust gfp_t gfp_flags) 12880b14d5eSTrond Myklebust { 12980b14d5eSTrond Myklebust struct rpc_xprt_switch *xps; 13080b14d5eSTrond Myklebust 13180b14d5eSTrond Myklebust xps = kmalloc(sizeof(*xps), gfp_flags); 13280b14d5eSTrond Myklebust if (xps != NULL) { 13380b14d5eSTrond Myklebust spin_lock_init(&xps->xps_lock); 13480b14d5eSTrond Myklebust kref_init(&xps->xps_kref); 1355b926872SOlga Kornievskaia xprt_switch_alloc_id(xps, gfp_flags); 1369f98effcSTrond Myklebust xps->xps_nxprts = xps->xps_nactive = 0; 1379f98effcSTrond Myklebust atomic_long_set(&xps->xps_queuelen, 0); 1389f98effcSTrond Myklebust xps->xps_net = NULL; 13980b14d5eSTrond Myklebust INIT_LIST_HEAD(&xps->xps_xprt_list); 14080b14d5eSTrond Myklebust xps->xps_iter_ops = &rpc_xprt_iter_singular; 141baea9944SOlga Kornievskaia rpc_sysfs_xprt_switch_setup(xps, xprt, gfp_flags); 14280b14d5eSTrond Myklebust xprt_switch_add_xprt_locked(xps, xprt); 1433a3f9766SOlga Kornievskaia xps->xps_nunique_destaddr_xprts = 1; 144d408ebe0SOlga Kornievskaia rpc_sysfs_xprt_setup(xps, xprt, gfp_flags); 14580b14d5eSTrond Myklebust } 14680b14d5eSTrond Myklebust 14780b14d5eSTrond Myklebust return xps; 14880b14d5eSTrond Myklebust } 14980b14d5eSTrond Myklebust 15080b14d5eSTrond Myklebust static void xprt_switch_free_entries(struct rpc_xprt_switch *xps) 15180b14d5eSTrond Myklebust { 15280b14d5eSTrond Myklebust spin_lock(&xps->xps_lock); 15380b14d5eSTrond Myklebust while (!list_empty(&xps->xps_xprt_list)) { 15480b14d5eSTrond Myklebust struct rpc_xprt *xprt; 15580b14d5eSTrond Myklebust 15680b14d5eSTrond Myklebust xprt = list_first_entry(&xps->xps_xprt_list, 15780b14d5eSTrond Myklebust struct rpc_xprt, xprt_switch); 15880b14d5eSTrond Myklebust xprt_switch_remove_xprt_locked(xps, xprt); 15980b14d5eSTrond Myklebust spin_unlock(&xps->xps_lock); 16080b14d5eSTrond Myklebust xprt_put(xprt); 16180b14d5eSTrond Myklebust spin_lock(&xps->xps_lock); 16280b14d5eSTrond Myklebust } 16380b14d5eSTrond Myklebust spin_unlock(&xps->xps_lock); 16480b14d5eSTrond Myklebust } 16580b14d5eSTrond Myklebust 16680b14d5eSTrond Myklebust static void xprt_switch_free(struct kref *kref) 16780b14d5eSTrond Myklebust { 16880b14d5eSTrond Myklebust struct rpc_xprt_switch *xps = container_of(kref, 16980b14d5eSTrond Myklebust struct rpc_xprt_switch, xps_kref); 17080b14d5eSTrond Myklebust 17180b14d5eSTrond Myklebust xprt_switch_free_entries(xps); 172baea9944SOlga Kornievskaia rpc_sysfs_xprt_switch_destroy(xps); 1735b926872SOlga Kornievskaia xprt_switch_free_id(xps); 17480b14d5eSTrond Myklebust kfree_rcu(xps, xps_rcu); 17580b14d5eSTrond Myklebust } 17680b14d5eSTrond Myklebust 17780b14d5eSTrond Myklebust /** 17880b14d5eSTrond Myklebust * xprt_switch_get - Return a reference to a rpc_xprt_switch 17980b14d5eSTrond Myklebust * @xps: pointer to struct rpc_xprt_switch 18080b14d5eSTrond Myklebust * 18180b14d5eSTrond Myklebust * Returns a reference to xps unless the refcount is already zero. 18280b14d5eSTrond Myklebust */ 18380b14d5eSTrond Myklebust struct rpc_xprt_switch *xprt_switch_get(struct rpc_xprt_switch *xps) 18480b14d5eSTrond Myklebust { 18580b14d5eSTrond Myklebust if (xps != NULL && kref_get_unless_zero(&xps->xps_kref)) 18680b14d5eSTrond Myklebust return xps; 18780b14d5eSTrond Myklebust return NULL; 18880b14d5eSTrond Myklebust } 18980b14d5eSTrond Myklebust 19080b14d5eSTrond Myklebust /** 19180b14d5eSTrond Myklebust * xprt_switch_put - Release a reference to a rpc_xprt_switch 19280b14d5eSTrond Myklebust * @xps: pointer to struct rpc_xprt_switch 19380b14d5eSTrond Myklebust * 19480b14d5eSTrond Myklebust * Release the reference to xps, and free it once the refcount is zero. 19580b14d5eSTrond Myklebust */ 19680b14d5eSTrond Myklebust void xprt_switch_put(struct rpc_xprt_switch *xps) 19780b14d5eSTrond Myklebust { 19880b14d5eSTrond Myklebust if (xps != NULL) 19980b14d5eSTrond Myklebust kref_put(&xps->xps_kref, xprt_switch_free); 20080b14d5eSTrond Myklebust } 20180b14d5eSTrond Myklebust 20280b14d5eSTrond Myklebust /** 20380b14d5eSTrond Myklebust * rpc_xprt_switch_set_roundrobin - Set a round-robin policy on rpc_xprt_switch 20480b14d5eSTrond Myklebust * @xps: pointer to struct rpc_xprt_switch 20580b14d5eSTrond Myklebust * 20680b14d5eSTrond Myklebust * Sets a round-robin default policy for iterators acting on xps. 20780b14d5eSTrond Myklebust */ 20880b14d5eSTrond Myklebust void rpc_xprt_switch_set_roundrobin(struct rpc_xprt_switch *xps) 20980b14d5eSTrond Myklebust { 21080b14d5eSTrond Myklebust if (READ_ONCE(xps->xps_iter_ops) != &rpc_xprt_iter_roundrobin) 21180b14d5eSTrond Myklebust WRITE_ONCE(xps->xps_iter_ops, &rpc_xprt_iter_roundrobin); 21280b14d5eSTrond Myklebust } 21380b14d5eSTrond Myklebust 21480b14d5eSTrond Myklebust static 21580b14d5eSTrond Myklebust const struct rpc_xprt_iter_ops *xprt_iter_ops(const struct rpc_xprt_iter *xpi) 21680b14d5eSTrond Myklebust { 21780b14d5eSTrond Myklebust if (xpi->xpi_ops != NULL) 21880b14d5eSTrond Myklebust return xpi->xpi_ops; 21980b14d5eSTrond Myklebust return rcu_dereference(xpi->xpi_xpswitch)->xps_iter_ops; 22080b14d5eSTrond Myklebust } 22180b14d5eSTrond Myklebust 22280b14d5eSTrond Myklebust static 22380b14d5eSTrond Myklebust void xprt_iter_no_rewind(struct rpc_xprt_iter *xpi) 22480b14d5eSTrond Myklebust { 22580b14d5eSTrond Myklebust } 22680b14d5eSTrond Myklebust 22780b14d5eSTrond Myklebust static 22880b14d5eSTrond Myklebust void xprt_iter_default_rewind(struct rpc_xprt_iter *xpi) 22980b14d5eSTrond Myklebust { 23080b14d5eSTrond Myklebust WRITE_ONCE(xpi->xpi_cursor, NULL); 23180b14d5eSTrond Myklebust } 23280b14d5eSTrond Myklebust 23380b14d5eSTrond Myklebust static 234163f8821STrond Myklebust bool xprt_is_active(const struct rpc_xprt *xprt) 235163f8821STrond Myklebust { 2365b7eb784SOlga Kornievskaia return (kref_read(&xprt->kref) != 0 && 2375b7eb784SOlga Kornievskaia !test_bit(XPRT_OFFLINE, &xprt->state)); 238163f8821STrond Myklebust } 239163f8821STrond Myklebust 240163f8821STrond Myklebust static 24180b14d5eSTrond Myklebust struct rpc_xprt *xprt_switch_find_first_entry(struct list_head *head) 24280b14d5eSTrond Myklebust { 243163f8821STrond Myklebust struct rpc_xprt *pos; 244163f8821STrond Myklebust 245163f8821STrond Myklebust list_for_each_entry_rcu(pos, head, xprt_switch) { 246163f8821STrond Myklebust if (xprt_is_active(pos)) 247163f8821STrond Myklebust return pos; 248163f8821STrond Myklebust } 249163f8821STrond Myklebust return NULL; 25080b14d5eSTrond Myklebust } 25180b14d5eSTrond Myklebust 25280b14d5eSTrond Myklebust static 253*95d0d30cSOlga Kornievskaia struct rpc_xprt *xprt_switch_find_first_entry_offline(struct list_head *head) 254*95d0d30cSOlga Kornievskaia { 255*95d0d30cSOlga Kornievskaia struct rpc_xprt *pos; 256*95d0d30cSOlga Kornievskaia 257*95d0d30cSOlga Kornievskaia list_for_each_entry_rcu(pos, head, xprt_switch) { 258*95d0d30cSOlga Kornievskaia if (!xprt_is_active(pos)) 259*95d0d30cSOlga Kornievskaia return pos; 260*95d0d30cSOlga Kornievskaia } 261*95d0d30cSOlga Kornievskaia return NULL; 262*95d0d30cSOlga Kornievskaia } 263*95d0d30cSOlga Kornievskaia 264*95d0d30cSOlga Kornievskaia static 26580b14d5eSTrond Myklebust struct rpc_xprt *xprt_iter_first_entry(struct rpc_xprt_iter *xpi) 26680b14d5eSTrond Myklebust { 26780b14d5eSTrond Myklebust struct rpc_xprt_switch *xps = rcu_dereference(xpi->xpi_xpswitch); 26880b14d5eSTrond Myklebust 26980b14d5eSTrond Myklebust if (xps == NULL) 27080b14d5eSTrond Myklebust return NULL; 27180b14d5eSTrond Myklebust return xprt_switch_find_first_entry(&xps->xps_xprt_list); 27280b14d5eSTrond Myklebust } 27380b14d5eSTrond Myklebust 27480b14d5eSTrond Myklebust static 275*95d0d30cSOlga Kornievskaia struct rpc_xprt *_xprt_switch_find_current_entry(struct list_head *head, 276*95d0d30cSOlga Kornievskaia const struct rpc_xprt *cur, 277*95d0d30cSOlga Kornievskaia bool find_active) 27880b14d5eSTrond Myklebust { 27980b14d5eSTrond Myklebust struct rpc_xprt *pos; 280163f8821STrond Myklebust bool found = false; 28180b14d5eSTrond Myklebust 28280b14d5eSTrond Myklebust list_for_each_entry_rcu(pos, head, xprt_switch) { 28380b14d5eSTrond Myklebust if (cur == pos) 284163f8821STrond Myklebust found = true; 285*95d0d30cSOlga Kornievskaia if (found && ((find_active && xprt_is_active(pos)) || 286*95d0d30cSOlga Kornievskaia (!find_active && xprt_is_active(pos)))) 28780b14d5eSTrond Myklebust return pos; 28880b14d5eSTrond Myklebust } 28980b14d5eSTrond Myklebust return NULL; 29080b14d5eSTrond Myklebust } 29180b14d5eSTrond Myklebust 29280b14d5eSTrond Myklebust static 293*95d0d30cSOlga Kornievskaia struct rpc_xprt *xprt_switch_find_current_entry(struct list_head *head, 294*95d0d30cSOlga Kornievskaia const struct rpc_xprt *cur) 295*95d0d30cSOlga Kornievskaia { 296*95d0d30cSOlga Kornievskaia return _xprt_switch_find_current_entry(head, cur, true); 297*95d0d30cSOlga Kornievskaia } 298*95d0d30cSOlga Kornievskaia 299*95d0d30cSOlga Kornievskaia static 300*95d0d30cSOlga Kornievskaia struct rpc_xprt * _xprt_iter_current_entry(struct rpc_xprt_iter *xpi, 301*95d0d30cSOlga Kornievskaia struct rpc_xprt *first_entry(struct list_head *head), 302*95d0d30cSOlga Kornievskaia struct rpc_xprt *current_entry(struct list_head *head, 303*95d0d30cSOlga Kornievskaia const struct rpc_xprt *cur)) 30480b14d5eSTrond Myklebust { 30580b14d5eSTrond Myklebust struct rpc_xprt_switch *xps = rcu_dereference(xpi->xpi_xpswitch); 30680b14d5eSTrond Myklebust struct list_head *head; 30780b14d5eSTrond Myklebust 30880b14d5eSTrond Myklebust if (xps == NULL) 30980b14d5eSTrond Myklebust return NULL; 31080b14d5eSTrond Myklebust head = &xps->xps_xprt_list; 31180b14d5eSTrond Myklebust if (xpi->xpi_cursor == NULL || xps->xps_nxprts < 2) 312*95d0d30cSOlga Kornievskaia return first_entry(head); 313*95d0d30cSOlga Kornievskaia return current_entry(head, xpi->xpi_cursor); 314*95d0d30cSOlga Kornievskaia } 315*95d0d30cSOlga Kornievskaia 316*95d0d30cSOlga Kornievskaia static 317*95d0d30cSOlga Kornievskaia struct rpc_xprt *xprt_iter_current_entry(struct rpc_xprt_iter *xpi) 318*95d0d30cSOlga Kornievskaia { 319*95d0d30cSOlga Kornievskaia return _xprt_iter_current_entry(xpi, xprt_switch_find_first_entry, 320*95d0d30cSOlga Kornievskaia xprt_switch_find_current_entry); 321*95d0d30cSOlga Kornievskaia } 322*95d0d30cSOlga Kornievskaia 323*95d0d30cSOlga Kornievskaia static 324*95d0d30cSOlga Kornievskaia struct rpc_xprt *xprt_switch_find_current_entry_offline(struct list_head *head, 325*95d0d30cSOlga Kornievskaia const struct rpc_xprt *cur) 326*95d0d30cSOlga Kornievskaia { 327*95d0d30cSOlga Kornievskaia return _xprt_switch_find_current_entry(head, cur, false); 328*95d0d30cSOlga Kornievskaia } 329*95d0d30cSOlga Kornievskaia 330*95d0d30cSOlga Kornievskaia static 331*95d0d30cSOlga Kornievskaia struct rpc_xprt *xprt_iter_current_entry_offline(struct rpc_xprt_iter *xpi) 332*95d0d30cSOlga Kornievskaia { 333*95d0d30cSOlga Kornievskaia return _xprt_iter_current_entry(xpi, 334*95d0d30cSOlga Kornievskaia xprt_switch_find_first_entry_offline, 335*95d0d30cSOlga Kornievskaia xprt_switch_find_current_entry_offline); 33680b14d5eSTrond Myklebust } 33780b14d5eSTrond Myklebust 33839e5d2dfSAndy Adamson bool rpc_xprt_switch_has_addr(struct rpc_xprt_switch *xps, 33939e5d2dfSAndy Adamson const struct sockaddr *sap) 34039e5d2dfSAndy Adamson { 34139e5d2dfSAndy Adamson struct list_head *head; 34239e5d2dfSAndy Adamson struct rpc_xprt *pos; 34339e5d2dfSAndy Adamson 34439e5d2dfSAndy Adamson if (xps == NULL || sap == NULL) 34539e5d2dfSAndy Adamson return false; 34639e5d2dfSAndy Adamson 34739e5d2dfSAndy Adamson head = &xps->xps_xprt_list; 34839e5d2dfSAndy Adamson list_for_each_entry_rcu(pos, head, xprt_switch) { 34939e5d2dfSAndy Adamson if (rpc_cmp_addr_port(sap, (struct sockaddr *)&pos->addr)) { 35039e5d2dfSAndy Adamson pr_info("RPC: addr %s already in xprt switch\n", 35139e5d2dfSAndy Adamson pos->address_strings[RPC_DISPLAY_ADDR]); 35239e5d2dfSAndy Adamson return true; 35339e5d2dfSAndy Adamson } 35439e5d2dfSAndy Adamson } 35539e5d2dfSAndy Adamson return false; 35639e5d2dfSAndy Adamson } 35739e5d2dfSAndy Adamson 35880b14d5eSTrond Myklebust static 35980b14d5eSTrond Myklebust struct rpc_xprt *xprt_switch_find_next_entry(struct list_head *head, 360*95d0d30cSOlga Kornievskaia const struct rpc_xprt *cur, bool check_active) 36180b14d5eSTrond Myklebust { 36280b14d5eSTrond Myklebust struct rpc_xprt *pos, *prev = NULL; 363163f8821STrond Myklebust bool found = false; 36480b14d5eSTrond Myklebust 36580b14d5eSTrond Myklebust list_for_each_entry_rcu(pos, head, xprt_switch) { 36680b14d5eSTrond Myklebust if (cur == prev) 367163f8821STrond Myklebust found = true; 368*95d0d30cSOlga Kornievskaia /* for request to return active transports return only 369*95d0d30cSOlga Kornievskaia * active, for request to return offline transports 370*95d0d30cSOlga Kornievskaia * return only offline 371*95d0d30cSOlga Kornievskaia */ 372*95d0d30cSOlga Kornievskaia if (found && ((check_active && xprt_is_active(pos)) || 373*95d0d30cSOlga Kornievskaia (!check_active && !xprt_is_active(pos)))) 37480b14d5eSTrond Myklebust return pos; 37580b14d5eSTrond Myklebust prev = pos; 37680b14d5eSTrond Myklebust } 37780b14d5eSTrond Myklebust return NULL; 37880b14d5eSTrond Myklebust } 37980b14d5eSTrond Myklebust 38080b14d5eSTrond Myklebust static 381f554af28STrond Myklebust struct rpc_xprt *xprt_switch_set_next_cursor(struct rpc_xprt_switch *xps, 38280b14d5eSTrond Myklebust struct rpc_xprt **cursor, 38380b14d5eSTrond Myklebust xprt_switch_find_xprt_t find_next) 38480b14d5eSTrond Myklebust { 385f554af28STrond Myklebust struct rpc_xprt *pos, *old; 38680b14d5eSTrond Myklebust 387f554af28STrond Myklebust old = smp_load_acquire(cursor); 388f554af28STrond Myklebust pos = find_next(xps, old); 389f554af28STrond Myklebust smp_store_release(cursor, pos); 39080b14d5eSTrond Myklebust return pos; 39180b14d5eSTrond Myklebust } 39280b14d5eSTrond Myklebust 39380b14d5eSTrond Myklebust static 39480b14d5eSTrond Myklebust struct rpc_xprt *xprt_iter_next_entry_multiple(struct rpc_xprt_iter *xpi, 39580b14d5eSTrond Myklebust xprt_switch_find_xprt_t find_next) 39680b14d5eSTrond Myklebust { 39780b14d5eSTrond Myklebust struct rpc_xprt_switch *xps = rcu_dereference(xpi->xpi_xpswitch); 39880b14d5eSTrond Myklebust 39980b14d5eSTrond Myklebust if (xps == NULL) 40080b14d5eSTrond Myklebust return NULL; 401f554af28STrond Myklebust return xprt_switch_set_next_cursor(xps, &xpi->xpi_cursor, find_next); 40280b14d5eSTrond Myklebust } 40380b14d5eSTrond Myklebust 40480b14d5eSTrond Myklebust static 405f554af28STrond Myklebust struct rpc_xprt *__xprt_switch_find_next_entry_roundrobin(struct list_head *head, 40680b14d5eSTrond Myklebust const struct rpc_xprt *cur) 40780b14d5eSTrond Myklebust { 40880b14d5eSTrond Myklebust struct rpc_xprt *ret; 40980b14d5eSTrond Myklebust 410*95d0d30cSOlga Kornievskaia ret = xprt_switch_find_next_entry(head, cur, true); 41180b14d5eSTrond Myklebust if (ret != NULL) 41280b14d5eSTrond Myklebust return ret; 41380b14d5eSTrond Myklebust return xprt_switch_find_first_entry(head); 41480b14d5eSTrond Myklebust } 41580b14d5eSTrond Myklebust 41680b14d5eSTrond Myklebust static 417f554af28STrond Myklebust struct rpc_xprt *xprt_switch_find_next_entry_roundrobin(struct rpc_xprt_switch *xps, 418f554af28STrond Myklebust const struct rpc_xprt *cur) 41980b14d5eSTrond Myklebust { 420f554af28STrond Myklebust struct list_head *head = &xps->xps_xprt_list; 42121f0ffafSTrond Myklebust struct rpc_xprt *xprt; 422f554af28STrond Myklebust unsigned int nactive; 42321f0ffafSTrond Myklebust 424f554af28STrond Myklebust for (;;) { 425f554af28STrond Myklebust unsigned long xprt_queuelen, xps_queuelen; 426f554af28STrond Myklebust 427f554af28STrond Myklebust xprt = __xprt_switch_find_next_entry_roundrobin(head, cur); 428f554af28STrond Myklebust if (!xprt) 42921f0ffafSTrond Myklebust break; 43021f0ffafSTrond Myklebust xprt_queuelen = atomic_long_read(&xprt->queuelen); 43121f0ffafSTrond Myklebust xps_queuelen = atomic_long_read(&xps->xps_queuelen); 432f554af28STrond Myklebust nactive = READ_ONCE(xps->xps_nactive); 4333cf72922STrond Myklebust /* Exit loop if xprt_queuelen <= average queue length */ 434f554af28STrond Myklebust if (xprt_queuelen * nactive <= xps_queuelen) 435f554af28STrond Myklebust break; 436f554af28STrond Myklebust cur = xprt; 437f554af28STrond Myklebust } 43821f0ffafSTrond Myklebust return xprt; 43980b14d5eSTrond Myklebust } 44080b14d5eSTrond Myklebust 44180b14d5eSTrond Myklebust static 442f554af28STrond Myklebust struct rpc_xprt *xprt_iter_next_entry_roundrobin(struct rpc_xprt_iter *xpi) 443f554af28STrond Myklebust { 444f554af28STrond Myklebust return xprt_iter_next_entry_multiple(xpi, 445f554af28STrond Myklebust xprt_switch_find_next_entry_roundrobin); 446f554af28STrond Myklebust } 447f554af28STrond Myklebust 448f554af28STrond Myklebust static 449f554af28STrond Myklebust struct rpc_xprt *xprt_switch_find_next_entry_all(struct rpc_xprt_switch *xps, 450f554af28STrond Myklebust const struct rpc_xprt *cur) 451f554af28STrond Myklebust { 452*95d0d30cSOlga Kornievskaia return xprt_switch_find_next_entry(&xps->xps_xprt_list, cur, true); 453*95d0d30cSOlga Kornievskaia } 454*95d0d30cSOlga Kornievskaia 455*95d0d30cSOlga Kornievskaia static 456*95d0d30cSOlga Kornievskaia struct rpc_xprt *xprt_switch_find_next_entry_offline(struct rpc_xprt_switch *xps, 457*95d0d30cSOlga Kornievskaia const struct rpc_xprt *cur) 458*95d0d30cSOlga Kornievskaia { 459*95d0d30cSOlga Kornievskaia return xprt_switch_find_next_entry(&xps->xps_xprt_list, cur, false); 460f554af28STrond Myklebust } 461f554af28STrond Myklebust 462f554af28STrond Myklebust static 46380b14d5eSTrond Myklebust struct rpc_xprt *xprt_iter_next_entry_all(struct rpc_xprt_iter *xpi) 46480b14d5eSTrond Myklebust { 465f554af28STrond Myklebust return xprt_iter_next_entry_multiple(xpi, 466f554af28STrond Myklebust xprt_switch_find_next_entry_all); 46780b14d5eSTrond Myklebust } 46880b14d5eSTrond Myklebust 469*95d0d30cSOlga Kornievskaia static 470*95d0d30cSOlga Kornievskaia struct rpc_xprt *xprt_iter_next_entry_offline(struct rpc_xprt_iter *xpi) 471*95d0d30cSOlga Kornievskaia { 472*95d0d30cSOlga Kornievskaia return xprt_iter_next_entry_multiple(xpi, 473*95d0d30cSOlga Kornievskaia xprt_switch_find_next_entry_offline); 474*95d0d30cSOlga Kornievskaia } 475*95d0d30cSOlga Kornievskaia 47680b14d5eSTrond Myklebust /* 47780b14d5eSTrond Myklebust * xprt_iter_rewind - Resets the xprt iterator 47880b14d5eSTrond Myklebust * @xpi: pointer to rpc_xprt_iter 47980b14d5eSTrond Myklebust * 48080b14d5eSTrond Myklebust * Resets xpi to ensure that it points to the first entry in the list 48180b14d5eSTrond Myklebust * of transports. 48280b14d5eSTrond Myklebust */ 48380b14d5eSTrond Myklebust static 48480b14d5eSTrond Myklebust void xprt_iter_rewind(struct rpc_xprt_iter *xpi) 48580b14d5eSTrond Myklebust { 48680b14d5eSTrond Myklebust rcu_read_lock(); 48780b14d5eSTrond Myklebust xprt_iter_ops(xpi)->xpi_rewind(xpi); 48880b14d5eSTrond Myklebust rcu_read_unlock(); 48980b14d5eSTrond Myklebust } 49080b14d5eSTrond Myklebust 49180b14d5eSTrond Myklebust static void __xprt_iter_init(struct rpc_xprt_iter *xpi, 49280b14d5eSTrond Myklebust struct rpc_xprt_switch *xps, 49380b14d5eSTrond Myklebust const struct rpc_xprt_iter_ops *ops) 49480b14d5eSTrond Myklebust { 49580b14d5eSTrond Myklebust rcu_assign_pointer(xpi->xpi_xpswitch, xprt_switch_get(xps)); 49680b14d5eSTrond Myklebust xpi->xpi_cursor = NULL; 49780b14d5eSTrond Myklebust xpi->xpi_ops = ops; 49880b14d5eSTrond Myklebust } 49980b14d5eSTrond Myklebust 50080b14d5eSTrond Myklebust /** 50180b14d5eSTrond Myklebust * xprt_iter_init - Initialise an xprt iterator 50280b14d5eSTrond Myklebust * @xpi: pointer to rpc_xprt_iter 50380b14d5eSTrond Myklebust * @xps: pointer to rpc_xprt_switch 50480b14d5eSTrond Myklebust * 50580b14d5eSTrond Myklebust * Initialises the iterator to use the default iterator ops 50680b14d5eSTrond Myklebust * as set in xps. This function is mainly intended for internal 50780b14d5eSTrond Myklebust * use in the rpc_client. 50880b14d5eSTrond Myklebust */ 50980b14d5eSTrond Myklebust void xprt_iter_init(struct rpc_xprt_iter *xpi, 51080b14d5eSTrond Myklebust struct rpc_xprt_switch *xps) 51180b14d5eSTrond Myklebust { 51280b14d5eSTrond Myklebust __xprt_iter_init(xpi, xps, NULL); 51380b14d5eSTrond Myklebust } 51480b14d5eSTrond Myklebust 51580b14d5eSTrond Myklebust /** 51680b14d5eSTrond Myklebust * xprt_iter_init_listall - Initialise an xprt iterator 51780b14d5eSTrond Myklebust * @xpi: pointer to rpc_xprt_iter 51880b14d5eSTrond Myklebust * @xps: pointer to rpc_xprt_switch 51980b14d5eSTrond Myklebust * 52080b14d5eSTrond Myklebust * Initialises the iterator to iterate once through the entire list 52180b14d5eSTrond Myklebust * of entries in xps. 52280b14d5eSTrond Myklebust */ 52380b14d5eSTrond Myklebust void xprt_iter_init_listall(struct rpc_xprt_iter *xpi, 52480b14d5eSTrond Myklebust struct rpc_xprt_switch *xps) 52580b14d5eSTrond Myklebust { 52680b14d5eSTrond Myklebust __xprt_iter_init(xpi, xps, &rpc_xprt_iter_listall); 52780b14d5eSTrond Myklebust } 52880b14d5eSTrond Myklebust 529*95d0d30cSOlga Kornievskaia void xprt_iter_init_listoffline(struct rpc_xprt_iter *xpi, 530*95d0d30cSOlga Kornievskaia struct rpc_xprt_switch *xps) 531*95d0d30cSOlga Kornievskaia { 532*95d0d30cSOlga Kornievskaia __xprt_iter_init(xpi, xps, &rpc_xprt_iter_listoffline); 533*95d0d30cSOlga Kornievskaia } 534*95d0d30cSOlga Kornievskaia 53580b14d5eSTrond Myklebust /** 53680b14d5eSTrond Myklebust * xprt_iter_xchg_switch - Atomically swap out the rpc_xprt_switch 53780b14d5eSTrond Myklebust * @xpi: pointer to rpc_xprt_iter 538acf0a39fSChuck Lever * @newswitch: pointer to a new rpc_xprt_switch or NULL 53980b14d5eSTrond Myklebust * 54080b14d5eSTrond Myklebust * Swaps out the existing xpi->xpi_xpswitch with a new value. 54180b14d5eSTrond Myklebust */ 54280b14d5eSTrond Myklebust struct rpc_xprt_switch *xprt_iter_xchg_switch(struct rpc_xprt_iter *xpi, 54380b14d5eSTrond Myklebust struct rpc_xprt_switch *newswitch) 54480b14d5eSTrond Myklebust { 54580b14d5eSTrond Myklebust struct rpc_xprt_switch __rcu *oldswitch; 54680b14d5eSTrond Myklebust 54780b14d5eSTrond Myklebust /* Atomically swap out the old xpswitch */ 54880b14d5eSTrond Myklebust oldswitch = xchg(&xpi->xpi_xpswitch, RCU_INITIALIZER(newswitch)); 54980b14d5eSTrond Myklebust if (newswitch != NULL) 55080b14d5eSTrond Myklebust xprt_iter_rewind(xpi); 55180b14d5eSTrond Myklebust return rcu_dereference_protected(oldswitch, true); 55280b14d5eSTrond Myklebust } 55380b14d5eSTrond Myklebust 55480b14d5eSTrond Myklebust /** 55580b14d5eSTrond Myklebust * xprt_iter_destroy - Destroys the xprt iterator 556acf0a39fSChuck Lever * @xpi: pointer to rpc_xprt_iter 55780b14d5eSTrond Myklebust */ 55880b14d5eSTrond Myklebust void xprt_iter_destroy(struct rpc_xprt_iter *xpi) 55980b14d5eSTrond Myklebust { 56080b14d5eSTrond Myklebust xprt_switch_put(xprt_iter_xchg_switch(xpi, NULL)); 56180b14d5eSTrond Myklebust } 56280b14d5eSTrond Myklebust 56380b14d5eSTrond Myklebust /** 56480b14d5eSTrond Myklebust * xprt_iter_xprt - Returns the rpc_xprt pointed to by the cursor 56580b14d5eSTrond Myklebust * @xpi: pointer to rpc_xprt_iter 56680b14d5eSTrond Myklebust * 56780b14d5eSTrond Myklebust * Returns a pointer to the struct rpc_xprt that is currently 56880b14d5eSTrond Myklebust * pointed to by the cursor. 56980b14d5eSTrond Myklebust * Caller must be holding rcu_read_lock(). 57080b14d5eSTrond Myklebust */ 57180b14d5eSTrond Myklebust struct rpc_xprt *xprt_iter_xprt(struct rpc_xprt_iter *xpi) 57280b14d5eSTrond Myklebust { 57380b14d5eSTrond Myklebust WARN_ON_ONCE(!rcu_read_lock_held()); 57480b14d5eSTrond Myklebust return xprt_iter_ops(xpi)->xpi_xprt(xpi); 57580b14d5eSTrond Myklebust } 57680b14d5eSTrond Myklebust 57780b14d5eSTrond Myklebust static 57880b14d5eSTrond Myklebust struct rpc_xprt *xprt_iter_get_helper(struct rpc_xprt_iter *xpi, 57980b14d5eSTrond Myklebust struct rpc_xprt *(*fn)(struct rpc_xprt_iter *)) 58080b14d5eSTrond Myklebust { 58180b14d5eSTrond Myklebust struct rpc_xprt *ret; 58280b14d5eSTrond Myklebust 58380b14d5eSTrond Myklebust do { 58480b14d5eSTrond Myklebust ret = fn(xpi); 58580b14d5eSTrond Myklebust if (ret == NULL) 58680b14d5eSTrond Myklebust break; 58780b14d5eSTrond Myklebust ret = xprt_get(ret); 58880b14d5eSTrond Myklebust } while (ret == NULL); 58980b14d5eSTrond Myklebust return ret; 59080b14d5eSTrond Myklebust } 59180b14d5eSTrond Myklebust 59280b14d5eSTrond Myklebust /** 59380b14d5eSTrond Myklebust * xprt_iter_get_xprt - Returns the rpc_xprt pointed to by the cursor 59480b14d5eSTrond Myklebust * @xpi: pointer to rpc_xprt_iter 59580b14d5eSTrond Myklebust * 59680b14d5eSTrond Myklebust * Returns a reference to the struct rpc_xprt that is currently 59780b14d5eSTrond Myklebust * pointed to by the cursor. 59880b14d5eSTrond Myklebust */ 59980b14d5eSTrond Myklebust struct rpc_xprt *xprt_iter_get_xprt(struct rpc_xprt_iter *xpi) 60080b14d5eSTrond Myklebust { 60180b14d5eSTrond Myklebust struct rpc_xprt *xprt; 60280b14d5eSTrond Myklebust 60380b14d5eSTrond Myklebust rcu_read_lock(); 60480b14d5eSTrond Myklebust xprt = xprt_iter_get_helper(xpi, xprt_iter_ops(xpi)->xpi_xprt); 60580b14d5eSTrond Myklebust rcu_read_unlock(); 60680b14d5eSTrond Myklebust return xprt; 60780b14d5eSTrond Myklebust } 60880b14d5eSTrond Myklebust 60980b14d5eSTrond Myklebust /** 61080b14d5eSTrond Myklebust * xprt_iter_get_next - Returns the next rpc_xprt following the cursor 61180b14d5eSTrond Myklebust * @xpi: pointer to rpc_xprt_iter 61280b14d5eSTrond Myklebust * 61380b14d5eSTrond Myklebust * Returns a reference to the struct rpc_xprt that immediately follows the 61480b14d5eSTrond Myklebust * entry pointed to by the cursor. 61580b14d5eSTrond Myklebust */ 61680b14d5eSTrond Myklebust struct rpc_xprt *xprt_iter_get_next(struct rpc_xprt_iter *xpi) 61780b14d5eSTrond Myklebust { 61880b14d5eSTrond Myklebust struct rpc_xprt *xprt; 61980b14d5eSTrond Myklebust 62080b14d5eSTrond Myklebust rcu_read_lock(); 62180b14d5eSTrond Myklebust xprt = xprt_iter_get_helper(xpi, xprt_iter_ops(xpi)->xpi_next); 62280b14d5eSTrond Myklebust rcu_read_unlock(); 62380b14d5eSTrond Myklebust return xprt; 62480b14d5eSTrond Myklebust } 62580b14d5eSTrond Myklebust 62680b14d5eSTrond Myklebust /* Policy for always returning the first entry in the rpc_xprt_switch */ 62780b14d5eSTrond Myklebust static 62880b14d5eSTrond Myklebust const struct rpc_xprt_iter_ops rpc_xprt_iter_singular = { 62980b14d5eSTrond Myklebust .xpi_rewind = xprt_iter_no_rewind, 63080b14d5eSTrond Myklebust .xpi_xprt = xprt_iter_first_entry, 63180b14d5eSTrond Myklebust .xpi_next = xprt_iter_first_entry, 63280b14d5eSTrond Myklebust }; 63380b14d5eSTrond Myklebust 63480b14d5eSTrond Myklebust /* Policy for round-robin iteration of entries in the rpc_xprt_switch */ 63580b14d5eSTrond Myklebust static 63680b14d5eSTrond Myklebust const struct rpc_xprt_iter_ops rpc_xprt_iter_roundrobin = { 63780b14d5eSTrond Myklebust .xpi_rewind = xprt_iter_default_rewind, 63880b14d5eSTrond Myklebust .xpi_xprt = xprt_iter_current_entry, 63980b14d5eSTrond Myklebust .xpi_next = xprt_iter_next_entry_roundrobin, 64080b14d5eSTrond Myklebust }; 64180b14d5eSTrond Myklebust 64280b14d5eSTrond Myklebust /* Policy for once-through iteration of entries in the rpc_xprt_switch */ 64380b14d5eSTrond Myklebust static 64480b14d5eSTrond Myklebust const struct rpc_xprt_iter_ops rpc_xprt_iter_listall = { 64580b14d5eSTrond Myklebust .xpi_rewind = xprt_iter_default_rewind, 64680b14d5eSTrond Myklebust .xpi_xprt = xprt_iter_current_entry, 64780b14d5eSTrond Myklebust .xpi_next = xprt_iter_next_entry_all, 64880b14d5eSTrond Myklebust }; 649*95d0d30cSOlga Kornievskaia 650*95d0d30cSOlga Kornievskaia static 651*95d0d30cSOlga Kornievskaia const struct rpc_xprt_iter_ops rpc_xprt_iter_listoffline = { 652*95d0d30cSOlga Kornievskaia .xpi_rewind = xprt_iter_default_rewind, 653*95d0d30cSOlga Kornievskaia .xpi_xprt = xprt_iter_current_entry_offline, 654*95d0d30cSOlga Kornievskaia .xpi_next = xprt_iter_next_entry_offline, 655*95d0d30cSOlga Kornievskaia }; 656