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 */ 1080b14d5eSTrond Myklebust #include <linux/types.h> 1180b14d5eSTrond Myklebust #include <linux/kref.h> 1280b14d5eSTrond Myklebust #include <linux/list.h> 1380b14d5eSTrond Myklebust #include <linux/rcupdate.h> 1480b14d5eSTrond Myklebust #include <linux/rculist.h> 1580b14d5eSTrond Myklebust #include <linux/slab.h> 1680b14d5eSTrond Myklebust #include <asm/cmpxchg.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 2280b14d5eSTrond Myklebust typedef struct rpc_xprt *(*xprt_switch_find_xprt_t)(struct list_head *head, 2380b14d5eSTrond Myklebust const struct rpc_xprt *cur); 2480b14d5eSTrond Myklebust 2580b14d5eSTrond Myklebust static const struct rpc_xprt_iter_ops rpc_xprt_iter_singular; 2680b14d5eSTrond Myklebust static const struct rpc_xprt_iter_ops rpc_xprt_iter_roundrobin; 2780b14d5eSTrond Myklebust static const struct rpc_xprt_iter_ops rpc_xprt_iter_listall; 2880b14d5eSTrond Myklebust 2980b14d5eSTrond Myklebust static void xprt_switch_add_xprt_locked(struct rpc_xprt_switch *xps, 3080b14d5eSTrond Myklebust struct rpc_xprt *xprt) 3180b14d5eSTrond Myklebust { 3280b14d5eSTrond Myklebust if (unlikely(xprt_get(xprt) == NULL)) 3380b14d5eSTrond Myklebust return; 3480b14d5eSTrond Myklebust list_add_tail_rcu(&xprt->xprt_switch, &xps->xps_xprt_list); 3580b14d5eSTrond Myklebust smp_wmb(); 3680b14d5eSTrond Myklebust if (xps->xps_nxprts == 0) 3780b14d5eSTrond Myklebust xps->xps_net = xprt->xprt_net; 3880b14d5eSTrond Myklebust xps->xps_nxprts++; 3921f0ffafSTrond Myklebust xps->xps_nactive++; 4080b14d5eSTrond Myklebust } 4180b14d5eSTrond Myklebust 4280b14d5eSTrond Myklebust /** 4380b14d5eSTrond Myklebust * rpc_xprt_switch_add_xprt - Add a new rpc_xprt to an rpc_xprt_switch 4480b14d5eSTrond Myklebust * @xps: pointer to struct rpc_xprt_switch 4580b14d5eSTrond Myklebust * @xprt: pointer to struct rpc_xprt 4680b14d5eSTrond Myklebust * 4780b14d5eSTrond Myklebust * Adds xprt to the end of the list of struct rpc_xprt in xps. 4880b14d5eSTrond Myklebust */ 4980b14d5eSTrond Myklebust void rpc_xprt_switch_add_xprt(struct rpc_xprt_switch *xps, 5080b14d5eSTrond Myklebust struct rpc_xprt *xprt) 5180b14d5eSTrond Myklebust { 5280b14d5eSTrond Myklebust if (xprt == NULL) 5380b14d5eSTrond Myklebust return; 5480b14d5eSTrond Myklebust spin_lock(&xps->xps_lock); 5539e5d2dfSAndy Adamson if ((xps->xps_net == xprt->xprt_net || xps->xps_net == NULL) && 5639e5d2dfSAndy Adamson !rpc_xprt_switch_has_addr(xps, (struct sockaddr *)&xprt->addr)) 5780b14d5eSTrond Myklebust xprt_switch_add_xprt_locked(xps, xprt); 5880b14d5eSTrond Myklebust spin_unlock(&xps->xps_lock); 5980b14d5eSTrond Myklebust } 6080b14d5eSTrond Myklebust 6180b14d5eSTrond Myklebust static void xprt_switch_remove_xprt_locked(struct rpc_xprt_switch *xps, 6280b14d5eSTrond Myklebust struct rpc_xprt *xprt) 6380b14d5eSTrond Myklebust { 6480b14d5eSTrond Myklebust if (unlikely(xprt == NULL)) 6580b14d5eSTrond Myklebust return; 6621f0ffafSTrond Myklebust xps->xps_nactive--; 6780b14d5eSTrond Myklebust xps->xps_nxprts--; 6880b14d5eSTrond Myklebust if (xps->xps_nxprts == 0) 6980b14d5eSTrond Myklebust xps->xps_net = NULL; 7080b14d5eSTrond Myklebust smp_wmb(); 7180b14d5eSTrond Myklebust list_del_rcu(&xprt->xprt_switch); 7280b14d5eSTrond Myklebust } 7380b14d5eSTrond Myklebust 7480b14d5eSTrond Myklebust /** 7580b14d5eSTrond Myklebust * rpc_xprt_switch_remove_xprt - Removes an rpc_xprt from a rpc_xprt_switch 7680b14d5eSTrond Myklebust * @xps: pointer to struct rpc_xprt_switch 7780b14d5eSTrond Myklebust * @xprt: pointer to struct rpc_xprt 7880b14d5eSTrond Myklebust * 7980b14d5eSTrond Myklebust * Removes xprt from the list of struct rpc_xprt in xps. 8080b14d5eSTrond Myklebust */ 8180b14d5eSTrond Myklebust void rpc_xprt_switch_remove_xprt(struct rpc_xprt_switch *xps, 8280b14d5eSTrond Myklebust struct rpc_xprt *xprt) 8380b14d5eSTrond Myklebust { 8480b14d5eSTrond Myklebust spin_lock(&xps->xps_lock); 8580b14d5eSTrond Myklebust xprt_switch_remove_xprt_locked(xps, xprt); 8680b14d5eSTrond Myklebust spin_unlock(&xps->xps_lock); 8780b14d5eSTrond Myklebust xprt_put(xprt); 8880b14d5eSTrond Myklebust } 8980b14d5eSTrond Myklebust 9080b14d5eSTrond Myklebust /** 9180b14d5eSTrond Myklebust * xprt_switch_alloc - Allocate a new struct rpc_xprt_switch 9280b14d5eSTrond Myklebust * @xprt: pointer to struct rpc_xprt 9380b14d5eSTrond Myklebust * @gfp_flags: allocation flags 9480b14d5eSTrond Myklebust * 9580b14d5eSTrond Myklebust * On success, returns an initialised struct rpc_xprt_switch, containing 9680b14d5eSTrond Myklebust * the entry xprt. Returns NULL on failure. 9780b14d5eSTrond Myklebust */ 9880b14d5eSTrond Myklebust struct rpc_xprt_switch *xprt_switch_alloc(struct rpc_xprt *xprt, 9980b14d5eSTrond Myklebust gfp_t gfp_flags) 10080b14d5eSTrond Myklebust { 10180b14d5eSTrond Myklebust struct rpc_xprt_switch *xps; 10280b14d5eSTrond Myklebust 10380b14d5eSTrond Myklebust xps = kmalloc(sizeof(*xps), gfp_flags); 10480b14d5eSTrond Myklebust if (xps != NULL) { 10580b14d5eSTrond Myklebust spin_lock_init(&xps->xps_lock); 10680b14d5eSTrond Myklebust kref_init(&xps->xps_kref); 10780b14d5eSTrond Myklebust xps->xps_nxprts = 0; 10880b14d5eSTrond Myklebust INIT_LIST_HEAD(&xps->xps_xprt_list); 10980b14d5eSTrond Myklebust xps->xps_iter_ops = &rpc_xprt_iter_singular; 11080b14d5eSTrond Myklebust xprt_switch_add_xprt_locked(xps, xprt); 11180b14d5eSTrond Myklebust } 11280b14d5eSTrond Myklebust 11380b14d5eSTrond Myklebust return xps; 11480b14d5eSTrond Myklebust } 11580b14d5eSTrond Myklebust 11680b14d5eSTrond Myklebust static void xprt_switch_free_entries(struct rpc_xprt_switch *xps) 11780b14d5eSTrond Myklebust { 11880b14d5eSTrond Myklebust spin_lock(&xps->xps_lock); 11980b14d5eSTrond Myklebust while (!list_empty(&xps->xps_xprt_list)) { 12080b14d5eSTrond Myklebust struct rpc_xprt *xprt; 12180b14d5eSTrond Myklebust 12280b14d5eSTrond Myklebust xprt = list_first_entry(&xps->xps_xprt_list, 12380b14d5eSTrond Myklebust struct rpc_xprt, xprt_switch); 12480b14d5eSTrond Myklebust xprt_switch_remove_xprt_locked(xps, xprt); 12580b14d5eSTrond Myklebust spin_unlock(&xps->xps_lock); 12680b14d5eSTrond Myklebust xprt_put(xprt); 12780b14d5eSTrond Myklebust spin_lock(&xps->xps_lock); 12880b14d5eSTrond Myklebust } 12980b14d5eSTrond Myklebust spin_unlock(&xps->xps_lock); 13080b14d5eSTrond Myklebust } 13180b14d5eSTrond Myklebust 13280b14d5eSTrond Myklebust static void xprt_switch_free(struct kref *kref) 13380b14d5eSTrond Myklebust { 13480b14d5eSTrond Myklebust struct rpc_xprt_switch *xps = container_of(kref, 13580b14d5eSTrond Myklebust struct rpc_xprt_switch, xps_kref); 13680b14d5eSTrond Myklebust 13780b14d5eSTrond Myklebust xprt_switch_free_entries(xps); 13880b14d5eSTrond Myklebust kfree_rcu(xps, xps_rcu); 13980b14d5eSTrond Myklebust } 14080b14d5eSTrond Myklebust 14180b14d5eSTrond Myklebust /** 14280b14d5eSTrond Myklebust * xprt_switch_get - Return a reference to a rpc_xprt_switch 14380b14d5eSTrond Myklebust * @xps: pointer to struct rpc_xprt_switch 14480b14d5eSTrond Myklebust * 14580b14d5eSTrond Myklebust * Returns a reference to xps unless the refcount is already zero. 14680b14d5eSTrond Myklebust */ 14780b14d5eSTrond Myklebust struct rpc_xprt_switch *xprt_switch_get(struct rpc_xprt_switch *xps) 14880b14d5eSTrond Myklebust { 14980b14d5eSTrond Myklebust if (xps != NULL && kref_get_unless_zero(&xps->xps_kref)) 15080b14d5eSTrond Myklebust return xps; 15180b14d5eSTrond Myklebust return NULL; 15280b14d5eSTrond Myklebust } 15380b14d5eSTrond Myklebust 15480b14d5eSTrond Myklebust /** 15580b14d5eSTrond Myklebust * xprt_switch_put - Release a reference to a rpc_xprt_switch 15680b14d5eSTrond Myklebust * @xps: pointer to struct rpc_xprt_switch 15780b14d5eSTrond Myklebust * 15880b14d5eSTrond Myklebust * Release the reference to xps, and free it once the refcount is zero. 15980b14d5eSTrond Myklebust */ 16080b14d5eSTrond Myklebust void xprt_switch_put(struct rpc_xprt_switch *xps) 16180b14d5eSTrond Myklebust { 16280b14d5eSTrond Myklebust if (xps != NULL) 16380b14d5eSTrond Myklebust kref_put(&xps->xps_kref, xprt_switch_free); 16480b14d5eSTrond Myklebust } 16580b14d5eSTrond Myklebust 16680b14d5eSTrond Myklebust /** 16780b14d5eSTrond Myklebust * rpc_xprt_switch_set_roundrobin - Set a round-robin policy on rpc_xprt_switch 16880b14d5eSTrond Myklebust * @xps: pointer to struct rpc_xprt_switch 16980b14d5eSTrond Myklebust * 17080b14d5eSTrond Myklebust * Sets a round-robin default policy for iterators acting on xps. 17180b14d5eSTrond Myklebust */ 17280b14d5eSTrond Myklebust void rpc_xprt_switch_set_roundrobin(struct rpc_xprt_switch *xps) 17380b14d5eSTrond Myklebust { 17480b14d5eSTrond Myklebust if (READ_ONCE(xps->xps_iter_ops) != &rpc_xprt_iter_roundrobin) 17580b14d5eSTrond Myklebust WRITE_ONCE(xps->xps_iter_ops, &rpc_xprt_iter_roundrobin); 17680b14d5eSTrond Myklebust } 17780b14d5eSTrond Myklebust 17880b14d5eSTrond Myklebust static 17980b14d5eSTrond Myklebust const struct rpc_xprt_iter_ops *xprt_iter_ops(const struct rpc_xprt_iter *xpi) 18080b14d5eSTrond Myklebust { 18180b14d5eSTrond Myklebust if (xpi->xpi_ops != NULL) 18280b14d5eSTrond Myklebust return xpi->xpi_ops; 18380b14d5eSTrond Myklebust return rcu_dereference(xpi->xpi_xpswitch)->xps_iter_ops; 18480b14d5eSTrond Myklebust } 18580b14d5eSTrond Myklebust 18680b14d5eSTrond Myklebust static 18780b14d5eSTrond Myklebust void xprt_iter_no_rewind(struct rpc_xprt_iter *xpi) 18880b14d5eSTrond Myklebust { 18980b14d5eSTrond Myklebust } 19080b14d5eSTrond Myklebust 19180b14d5eSTrond Myklebust static 19280b14d5eSTrond Myklebust void xprt_iter_default_rewind(struct rpc_xprt_iter *xpi) 19380b14d5eSTrond Myklebust { 19480b14d5eSTrond Myklebust WRITE_ONCE(xpi->xpi_cursor, NULL); 19580b14d5eSTrond Myklebust } 19680b14d5eSTrond Myklebust 19780b14d5eSTrond Myklebust static 19880b14d5eSTrond Myklebust struct rpc_xprt *xprt_switch_find_first_entry(struct list_head *head) 19980b14d5eSTrond Myklebust { 20080b14d5eSTrond Myklebust return list_first_or_null_rcu(head, struct rpc_xprt, xprt_switch); 20180b14d5eSTrond Myklebust } 20280b14d5eSTrond Myklebust 20380b14d5eSTrond Myklebust static 20480b14d5eSTrond Myklebust struct rpc_xprt *xprt_iter_first_entry(struct rpc_xprt_iter *xpi) 20580b14d5eSTrond Myklebust { 20680b14d5eSTrond Myklebust struct rpc_xprt_switch *xps = rcu_dereference(xpi->xpi_xpswitch); 20780b14d5eSTrond Myklebust 20880b14d5eSTrond Myklebust if (xps == NULL) 20980b14d5eSTrond Myklebust return NULL; 21080b14d5eSTrond Myklebust return xprt_switch_find_first_entry(&xps->xps_xprt_list); 21180b14d5eSTrond Myklebust } 21280b14d5eSTrond Myklebust 21380b14d5eSTrond Myklebust static 21480b14d5eSTrond Myklebust struct rpc_xprt *xprt_switch_find_current_entry(struct list_head *head, 21580b14d5eSTrond Myklebust const struct rpc_xprt *cur) 21680b14d5eSTrond Myklebust { 21780b14d5eSTrond Myklebust struct rpc_xprt *pos; 21880b14d5eSTrond Myklebust 21980b14d5eSTrond Myklebust list_for_each_entry_rcu(pos, head, xprt_switch) { 22080b14d5eSTrond Myklebust if (cur == pos) 22180b14d5eSTrond Myklebust return pos; 22280b14d5eSTrond Myklebust } 22380b14d5eSTrond Myklebust return NULL; 22480b14d5eSTrond Myklebust } 22580b14d5eSTrond Myklebust 22680b14d5eSTrond Myklebust static 22780b14d5eSTrond Myklebust struct rpc_xprt *xprt_iter_current_entry(struct rpc_xprt_iter *xpi) 22880b14d5eSTrond Myklebust { 22980b14d5eSTrond Myklebust struct rpc_xprt_switch *xps = rcu_dereference(xpi->xpi_xpswitch); 23080b14d5eSTrond Myklebust struct list_head *head; 23180b14d5eSTrond Myklebust 23280b14d5eSTrond Myklebust if (xps == NULL) 23380b14d5eSTrond Myklebust return NULL; 23480b14d5eSTrond Myklebust head = &xps->xps_xprt_list; 23580b14d5eSTrond Myklebust if (xpi->xpi_cursor == NULL || xps->xps_nxprts < 2) 23680b14d5eSTrond Myklebust return xprt_switch_find_first_entry(head); 23780b14d5eSTrond Myklebust return xprt_switch_find_current_entry(head, xpi->xpi_cursor); 23880b14d5eSTrond Myklebust } 23980b14d5eSTrond Myklebust 24039e5d2dfSAndy Adamson bool rpc_xprt_switch_has_addr(struct rpc_xprt_switch *xps, 24139e5d2dfSAndy Adamson const struct sockaddr *sap) 24239e5d2dfSAndy Adamson { 24339e5d2dfSAndy Adamson struct list_head *head; 24439e5d2dfSAndy Adamson struct rpc_xprt *pos; 24539e5d2dfSAndy Adamson 24639e5d2dfSAndy Adamson if (xps == NULL || sap == NULL) 24739e5d2dfSAndy Adamson return false; 24839e5d2dfSAndy Adamson 24939e5d2dfSAndy Adamson head = &xps->xps_xprt_list; 25039e5d2dfSAndy Adamson list_for_each_entry_rcu(pos, head, xprt_switch) { 25139e5d2dfSAndy Adamson if (rpc_cmp_addr_port(sap, (struct sockaddr *)&pos->addr)) { 25239e5d2dfSAndy Adamson pr_info("RPC: addr %s already in xprt switch\n", 25339e5d2dfSAndy Adamson pos->address_strings[RPC_DISPLAY_ADDR]); 25439e5d2dfSAndy Adamson return true; 25539e5d2dfSAndy Adamson } 25639e5d2dfSAndy Adamson } 25739e5d2dfSAndy Adamson return false; 25839e5d2dfSAndy Adamson } 25939e5d2dfSAndy Adamson 26080b14d5eSTrond Myklebust static 26180b14d5eSTrond Myklebust struct rpc_xprt *xprt_switch_find_next_entry(struct list_head *head, 26280b14d5eSTrond Myklebust const struct rpc_xprt *cur) 26380b14d5eSTrond Myklebust { 26480b14d5eSTrond Myklebust struct rpc_xprt *pos, *prev = NULL; 26580b14d5eSTrond Myklebust 26680b14d5eSTrond Myklebust list_for_each_entry_rcu(pos, head, xprt_switch) { 26780b14d5eSTrond Myklebust if (cur == prev) 26880b14d5eSTrond Myklebust return pos; 26980b14d5eSTrond Myklebust prev = pos; 27080b14d5eSTrond Myklebust } 27180b14d5eSTrond Myklebust return NULL; 27280b14d5eSTrond Myklebust } 27380b14d5eSTrond Myklebust 27480b14d5eSTrond Myklebust static 27580b14d5eSTrond Myklebust struct rpc_xprt *xprt_switch_set_next_cursor(struct list_head *head, 27680b14d5eSTrond Myklebust struct rpc_xprt **cursor, 27780b14d5eSTrond Myklebust xprt_switch_find_xprt_t find_next) 27880b14d5eSTrond Myklebust { 27980b14d5eSTrond Myklebust struct rpc_xprt *cur, *pos, *old; 28080b14d5eSTrond Myklebust 28180b14d5eSTrond Myklebust cur = READ_ONCE(*cursor); 28280b14d5eSTrond Myklebust for (;;) { 28380b14d5eSTrond Myklebust old = cur; 28480b14d5eSTrond Myklebust pos = find_next(head, old); 28580b14d5eSTrond Myklebust if (pos == NULL) 28680b14d5eSTrond Myklebust break; 28780b14d5eSTrond Myklebust cur = cmpxchg_relaxed(cursor, old, pos); 28880b14d5eSTrond Myklebust if (cur == old) 28980b14d5eSTrond Myklebust break; 29080b14d5eSTrond Myklebust } 29180b14d5eSTrond Myklebust return pos; 29280b14d5eSTrond Myklebust } 29380b14d5eSTrond Myklebust 29480b14d5eSTrond Myklebust static 29580b14d5eSTrond Myklebust struct rpc_xprt *xprt_iter_next_entry_multiple(struct rpc_xprt_iter *xpi, 29680b14d5eSTrond Myklebust xprt_switch_find_xprt_t find_next) 29780b14d5eSTrond Myklebust { 29880b14d5eSTrond Myklebust struct rpc_xprt_switch *xps = rcu_dereference(xpi->xpi_xpswitch); 29980b14d5eSTrond Myklebust 30080b14d5eSTrond Myklebust if (xps == NULL) 30180b14d5eSTrond Myklebust return NULL; 302bdc54d8eSTrond Myklebust return xprt_switch_set_next_cursor(&xps->xps_xprt_list, 303bdc54d8eSTrond Myklebust &xpi->xpi_cursor, 304bdc54d8eSTrond Myklebust find_next); 30580b14d5eSTrond Myklebust } 30680b14d5eSTrond Myklebust 30780b14d5eSTrond Myklebust static 30880b14d5eSTrond Myklebust struct rpc_xprt *xprt_switch_find_next_entry_roundrobin(struct list_head *head, 30980b14d5eSTrond Myklebust const struct rpc_xprt *cur) 31080b14d5eSTrond Myklebust { 31180b14d5eSTrond Myklebust struct rpc_xprt *ret; 31280b14d5eSTrond Myklebust 31380b14d5eSTrond Myklebust ret = xprt_switch_find_next_entry(head, cur); 31480b14d5eSTrond Myklebust if (ret != NULL) 31580b14d5eSTrond Myklebust return ret; 31680b14d5eSTrond Myklebust return xprt_switch_find_first_entry(head); 31780b14d5eSTrond Myklebust } 31880b14d5eSTrond Myklebust 31980b14d5eSTrond Myklebust static 32080b14d5eSTrond Myklebust struct rpc_xprt *xprt_iter_next_entry_roundrobin(struct rpc_xprt_iter *xpi) 32180b14d5eSTrond Myklebust { 32221f0ffafSTrond Myklebust struct rpc_xprt_switch *xps = rcu_dereference(xpi->xpi_xpswitch); 32321f0ffafSTrond Myklebust struct rpc_xprt *xprt; 32421f0ffafSTrond Myklebust unsigned long xprt_queuelen; 32521f0ffafSTrond Myklebust unsigned long xps_queuelen; 32621f0ffafSTrond Myklebust unsigned long xps_avglen; 32721f0ffafSTrond Myklebust 32821f0ffafSTrond Myklebust do { 32921f0ffafSTrond Myklebust xprt = xprt_iter_next_entry_multiple(xpi, 33080b14d5eSTrond Myklebust xprt_switch_find_next_entry_roundrobin); 33121f0ffafSTrond Myklebust if (xprt == NULL) 33221f0ffafSTrond Myklebust break; 33321f0ffafSTrond Myklebust xprt_queuelen = atomic_long_read(&xprt->queuelen); 33421f0ffafSTrond Myklebust if (xprt_queuelen <= 2) 33521f0ffafSTrond Myklebust break; 33621f0ffafSTrond Myklebust xps_queuelen = atomic_long_read(&xps->xps_queuelen); 33721f0ffafSTrond Myklebust xps_avglen = DIV_ROUND_UP(xps_queuelen, xps->xps_nactive); 33821f0ffafSTrond Myklebust } while (xprt_queuelen > xps_avglen); 33921f0ffafSTrond Myklebust return xprt; 34080b14d5eSTrond Myklebust } 34180b14d5eSTrond Myklebust 34280b14d5eSTrond Myklebust static 34380b14d5eSTrond Myklebust struct rpc_xprt *xprt_iter_next_entry_all(struct rpc_xprt_iter *xpi) 34480b14d5eSTrond Myklebust { 34580b14d5eSTrond Myklebust return xprt_iter_next_entry_multiple(xpi, xprt_switch_find_next_entry); 34680b14d5eSTrond Myklebust } 34780b14d5eSTrond Myklebust 34880b14d5eSTrond Myklebust /* 34980b14d5eSTrond Myklebust * xprt_iter_rewind - Resets the xprt iterator 35080b14d5eSTrond Myklebust * @xpi: pointer to rpc_xprt_iter 35180b14d5eSTrond Myklebust * 35280b14d5eSTrond Myklebust * Resets xpi to ensure that it points to the first entry in the list 35380b14d5eSTrond Myklebust * of transports. 35480b14d5eSTrond Myklebust */ 35580b14d5eSTrond Myklebust static 35680b14d5eSTrond Myklebust void xprt_iter_rewind(struct rpc_xprt_iter *xpi) 35780b14d5eSTrond Myklebust { 35880b14d5eSTrond Myklebust rcu_read_lock(); 35980b14d5eSTrond Myklebust xprt_iter_ops(xpi)->xpi_rewind(xpi); 36080b14d5eSTrond Myklebust rcu_read_unlock(); 36180b14d5eSTrond Myklebust } 36280b14d5eSTrond Myklebust 36380b14d5eSTrond Myklebust static void __xprt_iter_init(struct rpc_xprt_iter *xpi, 36480b14d5eSTrond Myklebust struct rpc_xprt_switch *xps, 36580b14d5eSTrond Myklebust const struct rpc_xprt_iter_ops *ops) 36680b14d5eSTrond Myklebust { 36780b14d5eSTrond Myklebust rcu_assign_pointer(xpi->xpi_xpswitch, xprt_switch_get(xps)); 36880b14d5eSTrond Myklebust xpi->xpi_cursor = NULL; 36980b14d5eSTrond Myklebust xpi->xpi_ops = ops; 37080b14d5eSTrond Myklebust } 37180b14d5eSTrond Myklebust 37280b14d5eSTrond Myklebust /** 37380b14d5eSTrond Myklebust * xprt_iter_init - Initialise an xprt iterator 37480b14d5eSTrond Myklebust * @xpi: pointer to rpc_xprt_iter 37580b14d5eSTrond Myklebust * @xps: pointer to rpc_xprt_switch 37680b14d5eSTrond Myklebust * 37780b14d5eSTrond Myklebust * Initialises the iterator to use the default iterator ops 37880b14d5eSTrond Myklebust * as set in xps. This function is mainly intended for internal 37980b14d5eSTrond Myklebust * use in the rpc_client. 38080b14d5eSTrond Myklebust */ 38180b14d5eSTrond Myklebust void xprt_iter_init(struct rpc_xprt_iter *xpi, 38280b14d5eSTrond Myklebust struct rpc_xprt_switch *xps) 38380b14d5eSTrond Myklebust { 38480b14d5eSTrond Myklebust __xprt_iter_init(xpi, xps, NULL); 38580b14d5eSTrond Myklebust } 38680b14d5eSTrond Myklebust 38780b14d5eSTrond Myklebust /** 38880b14d5eSTrond Myklebust * xprt_iter_init_listall - Initialise an xprt iterator 38980b14d5eSTrond Myklebust * @xpi: pointer to rpc_xprt_iter 39080b14d5eSTrond Myklebust * @xps: pointer to rpc_xprt_switch 39180b14d5eSTrond Myklebust * 39280b14d5eSTrond Myklebust * Initialises the iterator to iterate once through the entire list 39380b14d5eSTrond Myklebust * of entries in xps. 39480b14d5eSTrond Myklebust */ 39580b14d5eSTrond Myklebust void xprt_iter_init_listall(struct rpc_xprt_iter *xpi, 39680b14d5eSTrond Myklebust struct rpc_xprt_switch *xps) 39780b14d5eSTrond Myklebust { 39880b14d5eSTrond Myklebust __xprt_iter_init(xpi, xps, &rpc_xprt_iter_listall); 39980b14d5eSTrond Myklebust } 40080b14d5eSTrond Myklebust 40180b14d5eSTrond Myklebust /** 40280b14d5eSTrond Myklebust * xprt_iter_xchg_switch - Atomically swap out the rpc_xprt_switch 40380b14d5eSTrond Myklebust * @xpi: pointer to rpc_xprt_iter 404acf0a39fSChuck Lever * @newswitch: pointer to a new rpc_xprt_switch or NULL 40580b14d5eSTrond Myklebust * 40680b14d5eSTrond Myklebust * Swaps out the existing xpi->xpi_xpswitch with a new value. 40780b14d5eSTrond Myklebust */ 40880b14d5eSTrond Myklebust struct rpc_xprt_switch *xprt_iter_xchg_switch(struct rpc_xprt_iter *xpi, 40980b14d5eSTrond Myklebust struct rpc_xprt_switch *newswitch) 41080b14d5eSTrond Myklebust { 41180b14d5eSTrond Myklebust struct rpc_xprt_switch __rcu *oldswitch; 41280b14d5eSTrond Myklebust 41380b14d5eSTrond Myklebust /* Atomically swap out the old xpswitch */ 41480b14d5eSTrond Myklebust oldswitch = xchg(&xpi->xpi_xpswitch, RCU_INITIALIZER(newswitch)); 41580b14d5eSTrond Myklebust if (newswitch != NULL) 41680b14d5eSTrond Myklebust xprt_iter_rewind(xpi); 41780b14d5eSTrond Myklebust return rcu_dereference_protected(oldswitch, true); 41880b14d5eSTrond Myklebust } 41980b14d5eSTrond Myklebust 42080b14d5eSTrond Myklebust /** 42180b14d5eSTrond Myklebust * xprt_iter_destroy - Destroys the xprt iterator 422acf0a39fSChuck Lever * @xpi: pointer to rpc_xprt_iter 42380b14d5eSTrond Myklebust */ 42480b14d5eSTrond Myklebust void xprt_iter_destroy(struct rpc_xprt_iter *xpi) 42580b14d5eSTrond Myklebust { 42680b14d5eSTrond Myklebust xprt_switch_put(xprt_iter_xchg_switch(xpi, NULL)); 42780b14d5eSTrond Myklebust } 42880b14d5eSTrond Myklebust 42980b14d5eSTrond Myklebust /** 43080b14d5eSTrond Myklebust * xprt_iter_xprt - Returns the rpc_xprt pointed to by the cursor 43180b14d5eSTrond Myklebust * @xpi: pointer to rpc_xprt_iter 43280b14d5eSTrond Myklebust * 43380b14d5eSTrond Myklebust * Returns a pointer to the struct rpc_xprt that is currently 43480b14d5eSTrond Myklebust * pointed to by the cursor. 43580b14d5eSTrond Myklebust * Caller must be holding rcu_read_lock(). 43680b14d5eSTrond Myklebust */ 43780b14d5eSTrond Myklebust struct rpc_xprt *xprt_iter_xprt(struct rpc_xprt_iter *xpi) 43880b14d5eSTrond Myklebust { 43980b14d5eSTrond Myklebust WARN_ON_ONCE(!rcu_read_lock_held()); 44080b14d5eSTrond Myklebust return xprt_iter_ops(xpi)->xpi_xprt(xpi); 44180b14d5eSTrond Myklebust } 44280b14d5eSTrond Myklebust 44380b14d5eSTrond Myklebust static 44480b14d5eSTrond Myklebust struct rpc_xprt *xprt_iter_get_helper(struct rpc_xprt_iter *xpi, 44580b14d5eSTrond Myklebust struct rpc_xprt *(*fn)(struct rpc_xprt_iter *)) 44680b14d5eSTrond Myklebust { 44780b14d5eSTrond Myklebust struct rpc_xprt *ret; 44880b14d5eSTrond Myklebust 44980b14d5eSTrond Myklebust do { 45080b14d5eSTrond Myklebust ret = fn(xpi); 45180b14d5eSTrond Myklebust if (ret == NULL) 45280b14d5eSTrond Myklebust break; 45380b14d5eSTrond Myklebust ret = xprt_get(ret); 45480b14d5eSTrond Myklebust } while (ret == NULL); 45580b14d5eSTrond Myklebust return ret; 45680b14d5eSTrond Myklebust } 45780b14d5eSTrond Myklebust 45880b14d5eSTrond Myklebust /** 45980b14d5eSTrond Myklebust * xprt_iter_get_xprt - Returns the rpc_xprt pointed to by the cursor 46080b14d5eSTrond Myklebust * @xpi: pointer to rpc_xprt_iter 46180b14d5eSTrond Myklebust * 46280b14d5eSTrond Myklebust * Returns a reference to the struct rpc_xprt that is currently 46380b14d5eSTrond Myklebust * pointed to by the cursor. 46480b14d5eSTrond Myklebust */ 46580b14d5eSTrond Myklebust struct rpc_xprt *xprt_iter_get_xprt(struct rpc_xprt_iter *xpi) 46680b14d5eSTrond Myklebust { 46780b14d5eSTrond Myklebust struct rpc_xprt *xprt; 46880b14d5eSTrond Myklebust 46980b14d5eSTrond Myklebust rcu_read_lock(); 47080b14d5eSTrond Myklebust xprt = xprt_iter_get_helper(xpi, xprt_iter_ops(xpi)->xpi_xprt); 47180b14d5eSTrond Myklebust rcu_read_unlock(); 47280b14d5eSTrond Myklebust return xprt; 47380b14d5eSTrond Myklebust } 47480b14d5eSTrond Myklebust 47580b14d5eSTrond Myklebust /** 47680b14d5eSTrond Myklebust * xprt_iter_get_next - Returns the next rpc_xprt following the cursor 47780b14d5eSTrond Myklebust * @xpi: pointer to rpc_xprt_iter 47880b14d5eSTrond Myklebust * 47980b14d5eSTrond Myklebust * Returns a reference to the struct rpc_xprt that immediately follows the 48080b14d5eSTrond Myklebust * entry pointed to by the cursor. 48180b14d5eSTrond Myklebust */ 48280b14d5eSTrond Myklebust struct rpc_xprt *xprt_iter_get_next(struct rpc_xprt_iter *xpi) 48380b14d5eSTrond Myklebust { 48480b14d5eSTrond Myklebust struct rpc_xprt *xprt; 48580b14d5eSTrond Myklebust 48680b14d5eSTrond Myklebust rcu_read_lock(); 48780b14d5eSTrond Myklebust xprt = xprt_iter_get_helper(xpi, xprt_iter_ops(xpi)->xpi_next); 48880b14d5eSTrond Myklebust rcu_read_unlock(); 48980b14d5eSTrond Myklebust return xprt; 49080b14d5eSTrond Myklebust } 49180b14d5eSTrond Myklebust 49280b14d5eSTrond Myklebust /* Policy for always returning the first entry in the rpc_xprt_switch */ 49380b14d5eSTrond Myklebust static 49480b14d5eSTrond Myklebust const struct rpc_xprt_iter_ops rpc_xprt_iter_singular = { 49580b14d5eSTrond Myklebust .xpi_rewind = xprt_iter_no_rewind, 49680b14d5eSTrond Myklebust .xpi_xprt = xprt_iter_first_entry, 49780b14d5eSTrond Myklebust .xpi_next = xprt_iter_first_entry, 49880b14d5eSTrond Myklebust }; 49980b14d5eSTrond Myklebust 50080b14d5eSTrond Myklebust /* Policy for round-robin iteration of entries in the rpc_xprt_switch */ 50180b14d5eSTrond Myklebust static 50280b14d5eSTrond Myklebust const struct rpc_xprt_iter_ops rpc_xprt_iter_roundrobin = { 50380b14d5eSTrond Myklebust .xpi_rewind = xprt_iter_default_rewind, 50480b14d5eSTrond Myklebust .xpi_xprt = xprt_iter_current_entry, 50580b14d5eSTrond Myklebust .xpi_next = xprt_iter_next_entry_roundrobin, 50680b14d5eSTrond Myklebust }; 50780b14d5eSTrond Myklebust 50880b14d5eSTrond Myklebust /* Policy for once-through iteration of entries in the rpc_xprt_switch */ 50980b14d5eSTrond Myklebust static 51080b14d5eSTrond Myklebust const struct rpc_xprt_iter_ops rpc_xprt_iter_listall = { 51180b14d5eSTrond Myklebust .xpi_rewind = xprt_iter_default_rewind, 51280b14d5eSTrond Myklebust .xpi_xprt = xprt_iter_current_entry, 51380b14d5eSTrond Myklebust .xpi_next = xprt_iter_next_entry_all, 51480b14d5eSTrond Myklebust }; 515