xref: /openbmc/linux/net/sunrpc/xprtmultipath.c (revision 69c7eeb4)
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;
3095d0d30cSOlga Kornievskaia static const struct rpc_xprt_iter_ops rpc_xprt_iter_listoffline;
3180b14d5eSTrond Myklebust 
xprt_switch_add_xprt_locked(struct rpc_xprt_switch * xps,struct rpc_xprt * xprt)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  */
rpc_xprt_switch_add_xprt(struct rpc_xprt_switch * xps,struct rpc_xprt * xprt)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 
xprt_switch_remove_xprt_locked(struct rpc_xprt_switch * xps,struct rpc_xprt * xprt,bool offline)6480b14d5eSTrond Myklebust static void xprt_switch_remove_xprt_locked(struct rpc_xprt_switch *xps,
65497e6464SOlga Kornievskaia 		struct rpc_xprt *xprt, bool offline)
6680b14d5eSTrond Myklebust {
6780b14d5eSTrond Myklebust 	if (unlikely(xprt == NULL))
6880b14d5eSTrond Myklebust 		return;
69497e6464SOlga Kornievskaia 	if (!test_bit(XPRT_OFFLINE, &xprt->state) && offline)
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
82497e6464SOlga Kornievskaia  * @offline: indicates if the xprt that's being removed is in an offline state
8380b14d5eSTrond Myklebust  *
8480b14d5eSTrond Myklebust  * Removes xprt from the list of struct rpc_xprt in xps.
8580b14d5eSTrond Myklebust  */
rpc_xprt_switch_remove_xprt(struct rpc_xprt_switch * xps,struct rpc_xprt * xprt,bool offline)8680b14d5eSTrond Myklebust void rpc_xprt_switch_remove_xprt(struct rpc_xprt_switch *xps,
87497e6464SOlga Kornievskaia 		struct rpc_xprt *xprt, bool offline)
8880b14d5eSTrond Myklebust {
8980b14d5eSTrond Myklebust 	spin_lock(&xps->xps_lock);
90497e6464SOlga Kornievskaia 	xprt_switch_remove_xprt_locked(xps, xprt, offline);
9180b14d5eSTrond Myklebust 	spin_unlock(&xps->xps_lock);
9280b14d5eSTrond Myklebust 	xprt_put(xprt);
9380b14d5eSTrond Myklebust }
9480b14d5eSTrond Myklebust 
955b926872SOlga Kornievskaia static DEFINE_IDA(rpc_xprtswitch_ids);
965b926872SOlga Kornievskaia 
xprt_multipath_cleanup_ids(void)975b926872SOlga Kornievskaia void xprt_multipath_cleanup_ids(void)
985b926872SOlga Kornievskaia {
995b926872SOlga Kornievskaia 	ida_destroy(&rpc_xprtswitch_ids);
1005b926872SOlga Kornievskaia }
1015b926872SOlga Kornievskaia 
xprt_switch_alloc_id(struct rpc_xprt_switch * xps,gfp_t gfp_flags)1025b926872SOlga Kornievskaia static int xprt_switch_alloc_id(struct rpc_xprt_switch *xps, gfp_t gfp_flags)
1035b926872SOlga Kornievskaia {
1045b926872SOlga Kornievskaia 	int id;
1055b926872SOlga Kornievskaia 
1069947e57bSBo Liu 	id = ida_alloc(&rpc_xprtswitch_ids, gfp_flags);
1075b926872SOlga Kornievskaia 	if (id < 0)
1085b926872SOlga Kornievskaia 		return id;
1095b926872SOlga Kornievskaia 
1105b926872SOlga Kornievskaia 	xps->xps_id = id;
1115b926872SOlga Kornievskaia 	return 0;
1125b926872SOlga Kornievskaia }
1135b926872SOlga Kornievskaia 
xprt_switch_free_id(struct rpc_xprt_switch * xps)1145b926872SOlga Kornievskaia static void xprt_switch_free_id(struct rpc_xprt_switch *xps)
1155b926872SOlga Kornievskaia {
1169947e57bSBo Liu 	ida_free(&rpc_xprtswitch_ids, xps->xps_id);
1175b926872SOlga Kornievskaia }
1185b926872SOlga Kornievskaia 
11980b14d5eSTrond Myklebust /**
12080b14d5eSTrond Myklebust  * xprt_switch_alloc - Allocate a new struct rpc_xprt_switch
12180b14d5eSTrond Myklebust  * @xprt: pointer to struct rpc_xprt
12280b14d5eSTrond Myklebust  * @gfp_flags: allocation flags
12380b14d5eSTrond Myklebust  *
12480b14d5eSTrond Myklebust  * On success, returns an initialised struct rpc_xprt_switch, containing
12580b14d5eSTrond Myklebust  * the entry xprt. Returns NULL on failure.
12680b14d5eSTrond Myklebust  */
xprt_switch_alloc(struct rpc_xprt * xprt,gfp_t gfp_flags)12780b14d5eSTrond Myklebust struct rpc_xprt_switch *xprt_switch_alloc(struct rpc_xprt *xprt,
12880b14d5eSTrond Myklebust 		gfp_t gfp_flags)
12980b14d5eSTrond Myklebust {
13080b14d5eSTrond Myklebust 	struct rpc_xprt_switch *xps;
13180b14d5eSTrond Myklebust 
13280b14d5eSTrond Myklebust 	xps = kmalloc(sizeof(*xps), gfp_flags);
13380b14d5eSTrond Myklebust 	if (xps != NULL) {
13480b14d5eSTrond Myklebust 		spin_lock_init(&xps->xps_lock);
13580b14d5eSTrond Myklebust 		kref_init(&xps->xps_kref);
1365b926872SOlga Kornievskaia 		xprt_switch_alloc_id(xps, gfp_flags);
1379f98effcSTrond Myklebust 		xps->xps_nxprts = xps->xps_nactive = 0;
1389f98effcSTrond Myklebust 		atomic_long_set(&xps->xps_queuelen, 0);
1399f98effcSTrond Myklebust 		xps->xps_net = NULL;
14080b14d5eSTrond Myklebust 		INIT_LIST_HEAD(&xps->xps_xprt_list);
14180b14d5eSTrond Myklebust 		xps->xps_iter_ops = &rpc_xprt_iter_singular;
142baea9944SOlga Kornievskaia 		rpc_sysfs_xprt_switch_setup(xps, xprt, gfp_flags);
14380b14d5eSTrond Myklebust 		xprt_switch_add_xprt_locked(xps, xprt);
1443a3f9766SOlga Kornievskaia 		xps->xps_nunique_destaddr_xprts = 1;
145d408ebe0SOlga Kornievskaia 		rpc_sysfs_xprt_setup(xps, xprt, gfp_flags);
14680b14d5eSTrond Myklebust 	}
14780b14d5eSTrond Myklebust 
14880b14d5eSTrond Myklebust 	return xps;
14980b14d5eSTrond Myklebust }
15080b14d5eSTrond Myklebust 
xprt_switch_free_entries(struct rpc_xprt_switch * xps)15180b14d5eSTrond Myklebust static void xprt_switch_free_entries(struct rpc_xprt_switch *xps)
15280b14d5eSTrond Myklebust {
15380b14d5eSTrond Myklebust 	spin_lock(&xps->xps_lock);
15480b14d5eSTrond Myklebust 	while (!list_empty(&xps->xps_xprt_list)) {
15580b14d5eSTrond Myklebust 		struct rpc_xprt *xprt;
15680b14d5eSTrond Myklebust 
15780b14d5eSTrond Myklebust 		xprt = list_first_entry(&xps->xps_xprt_list,
15880b14d5eSTrond Myklebust 				struct rpc_xprt, xprt_switch);
159497e6464SOlga Kornievskaia 		xprt_switch_remove_xprt_locked(xps, xprt, true);
16080b14d5eSTrond Myklebust 		spin_unlock(&xps->xps_lock);
16180b14d5eSTrond Myklebust 		xprt_put(xprt);
16280b14d5eSTrond Myklebust 		spin_lock(&xps->xps_lock);
16380b14d5eSTrond Myklebust 	}
16480b14d5eSTrond Myklebust 	spin_unlock(&xps->xps_lock);
16580b14d5eSTrond Myklebust }
16680b14d5eSTrond Myklebust 
xprt_switch_free(struct kref * kref)16780b14d5eSTrond Myklebust static void xprt_switch_free(struct kref *kref)
16880b14d5eSTrond Myklebust {
16980b14d5eSTrond Myklebust 	struct rpc_xprt_switch *xps = container_of(kref,
17080b14d5eSTrond Myklebust 			struct rpc_xprt_switch, xps_kref);
17180b14d5eSTrond Myklebust 
17280b14d5eSTrond Myklebust 	xprt_switch_free_entries(xps);
173baea9944SOlga Kornievskaia 	rpc_sysfs_xprt_switch_destroy(xps);
1745b926872SOlga Kornievskaia 	xprt_switch_free_id(xps);
17580b14d5eSTrond Myklebust 	kfree_rcu(xps, xps_rcu);
17680b14d5eSTrond Myklebust }
17780b14d5eSTrond Myklebust 
17880b14d5eSTrond Myklebust /**
17980b14d5eSTrond Myklebust  * xprt_switch_get - Return a reference to a rpc_xprt_switch
18080b14d5eSTrond Myklebust  * @xps: pointer to struct rpc_xprt_switch
18180b14d5eSTrond Myklebust  *
18280b14d5eSTrond Myklebust  * Returns a reference to xps unless the refcount is already zero.
18380b14d5eSTrond Myklebust  */
xprt_switch_get(struct rpc_xprt_switch * xps)18480b14d5eSTrond Myklebust struct rpc_xprt_switch *xprt_switch_get(struct rpc_xprt_switch *xps)
18580b14d5eSTrond Myklebust {
18680b14d5eSTrond Myklebust 	if (xps != NULL && kref_get_unless_zero(&xps->xps_kref))
18780b14d5eSTrond Myklebust 		return xps;
18880b14d5eSTrond Myklebust 	return NULL;
18980b14d5eSTrond Myklebust }
19080b14d5eSTrond Myklebust 
19180b14d5eSTrond Myklebust /**
19280b14d5eSTrond Myklebust  * xprt_switch_put - Release a reference to a rpc_xprt_switch
19380b14d5eSTrond Myklebust  * @xps: pointer to struct rpc_xprt_switch
19480b14d5eSTrond Myklebust  *
19580b14d5eSTrond Myklebust  * Release the reference to xps, and free it once the refcount is zero.
19680b14d5eSTrond Myklebust  */
xprt_switch_put(struct rpc_xprt_switch * xps)19780b14d5eSTrond Myklebust void xprt_switch_put(struct rpc_xprt_switch *xps)
19880b14d5eSTrond Myklebust {
19980b14d5eSTrond Myklebust 	if (xps != NULL)
20080b14d5eSTrond Myklebust 		kref_put(&xps->xps_kref, xprt_switch_free);
20180b14d5eSTrond Myklebust }
20280b14d5eSTrond Myklebust 
20380b14d5eSTrond Myklebust /**
20480b14d5eSTrond Myklebust  * rpc_xprt_switch_set_roundrobin - Set a round-robin policy on rpc_xprt_switch
20580b14d5eSTrond Myklebust  * @xps: pointer to struct rpc_xprt_switch
20680b14d5eSTrond Myklebust  *
20780b14d5eSTrond Myklebust  * Sets a round-robin default policy for iterators acting on xps.
20880b14d5eSTrond Myklebust  */
rpc_xprt_switch_set_roundrobin(struct rpc_xprt_switch * xps)20980b14d5eSTrond Myklebust void rpc_xprt_switch_set_roundrobin(struct rpc_xprt_switch *xps)
21080b14d5eSTrond Myklebust {
21180b14d5eSTrond Myklebust 	if (READ_ONCE(xps->xps_iter_ops) != &rpc_xprt_iter_roundrobin)
21280b14d5eSTrond Myklebust 		WRITE_ONCE(xps->xps_iter_ops, &rpc_xprt_iter_roundrobin);
21380b14d5eSTrond Myklebust }
21480b14d5eSTrond Myklebust 
21580b14d5eSTrond Myklebust static
xprt_iter_ops(const struct rpc_xprt_iter * xpi)21680b14d5eSTrond Myklebust const struct rpc_xprt_iter_ops *xprt_iter_ops(const struct rpc_xprt_iter *xpi)
21780b14d5eSTrond Myklebust {
21880b14d5eSTrond Myklebust 	if (xpi->xpi_ops != NULL)
21980b14d5eSTrond Myklebust 		return xpi->xpi_ops;
22080b14d5eSTrond Myklebust 	return rcu_dereference(xpi->xpi_xpswitch)->xps_iter_ops;
22180b14d5eSTrond Myklebust }
22280b14d5eSTrond Myklebust 
22380b14d5eSTrond Myklebust static
xprt_iter_no_rewind(struct rpc_xprt_iter * xpi)22480b14d5eSTrond Myklebust void xprt_iter_no_rewind(struct rpc_xprt_iter *xpi)
22580b14d5eSTrond Myklebust {
22680b14d5eSTrond Myklebust }
22780b14d5eSTrond Myklebust 
22880b14d5eSTrond Myklebust static
xprt_iter_default_rewind(struct rpc_xprt_iter * xpi)22980b14d5eSTrond Myklebust void xprt_iter_default_rewind(struct rpc_xprt_iter *xpi)
23080b14d5eSTrond Myklebust {
23180b14d5eSTrond Myklebust 	WRITE_ONCE(xpi->xpi_cursor, NULL);
23280b14d5eSTrond Myklebust }
23380b14d5eSTrond Myklebust 
23480b14d5eSTrond Myklebust static
xprt_is_active(const struct rpc_xprt * xprt)235163f8821STrond Myklebust bool xprt_is_active(const struct rpc_xprt *xprt)
236163f8821STrond Myklebust {
2375b7eb784SOlga Kornievskaia 	return (kref_read(&xprt->kref) != 0 &&
2385b7eb784SOlga Kornievskaia 		!test_bit(XPRT_OFFLINE, &xprt->state));
239163f8821STrond Myklebust }
240163f8821STrond Myklebust 
241163f8821STrond Myklebust static
xprt_switch_find_first_entry(struct list_head * head)24280b14d5eSTrond Myklebust struct rpc_xprt *xprt_switch_find_first_entry(struct list_head *head)
24380b14d5eSTrond Myklebust {
244163f8821STrond Myklebust 	struct rpc_xprt *pos;
245163f8821STrond Myklebust 
246163f8821STrond Myklebust 	list_for_each_entry_rcu(pos, head, xprt_switch) {
247163f8821STrond Myklebust 		if (xprt_is_active(pos))
248163f8821STrond Myklebust 			return pos;
249163f8821STrond Myklebust 	}
250163f8821STrond Myklebust 	return NULL;
25180b14d5eSTrond Myklebust }
25280b14d5eSTrond Myklebust 
25380b14d5eSTrond Myklebust static
xprt_switch_find_first_entry_offline(struct list_head * head)25495d0d30cSOlga Kornievskaia struct rpc_xprt *xprt_switch_find_first_entry_offline(struct list_head *head)
25595d0d30cSOlga Kornievskaia {
25695d0d30cSOlga Kornievskaia 	struct rpc_xprt *pos;
25795d0d30cSOlga Kornievskaia 
25895d0d30cSOlga Kornievskaia 	list_for_each_entry_rcu(pos, head, xprt_switch) {
25995d0d30cSOlga Kornievskaia 		if (!xprt_is_active(pos))
26095d0d30cSOlga Kornievskaia 			return pos;
26195d0d30cSOlga Kornievskaia 	}
26295d0d30cSOlga Kornievskaia 	return NULL;
26395d0d30cSOlga Kornievskaia }
26495d0d30cSOlga Kornievskaia 
26595d0d30cSOlga Kornievskaia static
xprt_iter_first_entry(struct rpc_xprt_iter * xpi)26680b14d5eSTrond Myklebust struct rpc_xprt *xprt_iter_first_entry(struct rpc_xprt_iter *xpi)
26780b14d5eSTrond Myklebust {
26880b14d5eSTrond Myklebust 	struct rpc_xprt_switch *xps = rcu_dereference(xpi->xpi_xpswitch);
26980b14d5eSTrond Myklebust 
27080b14d5eSTrond Myklebust 	if (xps == NULL)
27180b14d5eSTrond Myklebust 		return NULL;
27280b14d5eSTrond Myklebust 	return xprt_switch_find_first_entry(&xps->xps_xprt_list);
27380b14d5eSTrond Myklebust }
27480b14d5eSTrond Myklebust 
27580b14d5eSTrond Myklebust static
_xprt_switch_find_current_entry(struct list_head * head,const struct rpc_xprt * cur,bool find_active)27695d0d30cSOlga Kornievskaia struct rpc_xprt *_xprt_switch_find_current_entry(struct list_head *head,
27795d0d30cSOlga Kornievskaia 						 const struct rpc_xprt *cur,
27895d0d30cSOlga Kornievskaia 						 bool find_active)
27980b14d5eSTrond Myklebust {
28080b14d5eSTrond Myklebust 	struct rpc_xprt *pos;
281163f8821STrond Myklebust 	bool found = false;
28280b14d5eSTrond Myklebust 
28380b14d5eSTrond Myklebust 	list_for_each_entry_rcu(pos, head, xprt_switch) {
28480b14d5eSTrond Myklebust 		if (cur == pos)
285163f8821STrond Myklebust 			found = true;
28695d0d30cSOlga Kornievskaia 		if (found && ((find_active && xprt_is_active(pos)) ||
287bcdb1622SOlga Kornievskaia 			      (!find_active && !xprt_is_active(pos))))
28880b14d5eSTrond Myklebust 			return pos;
28980b14d5eSTrond Myklebust 	}
29080b14d5eSTrond Myklebust 	return NULL;
29180b14d5eSTrond Myklebust }
29280b14d5eSTrond Myklebust 
29380b14d5eSTrond Myklebust static
xprt_switch_find_current_entry(struct list_head * head,const struct rpc_xprt * cur)29495d0d30cSOlga Kornievskaia struct rpc_xprt *xprt_switch_find_current_entry(struct list_head *head,
29595d0d30cSOlga Kornievskaia 						const struct rpc_xprt *cur)
29695d0d30cSOlga Kornievskaia {
29795d0d30cSOlga Kornievskaia 	return _xprt_switch_find_current_entry(head, cur, true);
29895d0d30cSOlga Kornievskaia }
29995d0d30cSOlga Kornievskaia 
30095d0d30cSOlga Kornievskaia static
_xprt_iter_current_entry(struct rpc_xprt_iter * xpi,struct rpc_xprt * first_entry (struct list_head * head),struct rpc_xprt * current_entry (struct list_head * head,const struct rpc_xprt * cur))30195d0d30cSOlga Kornievskaia struct rpc_xprt * _xprt_iter_current_entry(struct rpc_xprt_iter *xpi,
30295d0d30cSOlga Kornievskaia 		struct rpc_xprt *first_entry(struct list_head *head),
30395d0d30cSOlga Kornievskaia 		struct rpc_xprt *current_entry(struct list_head *head,
30495d0d30cSOlga Kornievskaia 					       const struct rpc_xprt *cur))
30580b14d5eSTrond Myklebust {
30680b14d5eSTrond Myklebust 	struct rpc_xprt_switch *xps = rcu_dereference(xpi->xpi_xpswitch);
30780b14d5eSTrond Myklebust 	struct list_head *head;
30880b14d5eSTrond Myklebust 
30980b14d5eSTrond Myklebust 	if (xps == NULL)
31080b14d5eSTrond Myklebust 		return NULL;
31180b14d5eSTrond Myklebust 	head = &xps->xps_xprt_list;
31280b14d5eSTrond Myklebust 	if (xpi->xpi_cursor == NULL || xps->xps_nxprts < 2)
31395d0d30cSOlga Kornievskaia 		return first_entry(head);
31495d0d30cSOlga Kornievskaia 	return current_entry(head, xpi->xpi_cursor);
31595d0d30cSOlga Kornievskaia }
31695d0d30cSOlga Kornievskaia 
31795d0d30cSOlga Kornievskaia static
xprt_iter_current_entry(struct rpc_xprt_iter * xpi)31895d0d30cSOlga Kornievskaia struct rpc_xprt *xprt_iter_current_entry(struct rpc_xprt_iter *xpi)
31995d0d30cSOlga Kornievskaia {
32095d0d30cSOlga Kornievskaia 	return _xprt_iter_current_entry(xpi, xprt_switch_find_first_entry,
32195d0d30cSOlga Kornievskaia 			xprt_switch_find_current_entry);
32295d0d30cSOlga Kornievskaia }
32395d0d30cSOlga Kornievskaia 
32495d0d30cSOlga Kornievskaia static
xprt_switch_find_current_entry_offline(struct list_head * head,const struct rpc_xprt * cur)32595d0d30cSOlga Kornievskaia struct rpc_xprt *xprt_switch_find_current_entry_offline(struct list_head *head,
32695d0d30cSOlga Kornievskaia 		const struct rpc_xprt *cur)
32795d0d30cSOlga Kornievskaia {
32895d0d30cSOlga Kornievskaia 	return _xprt_switch_find_current_entry(head, cur, false);
32995d0d30cSOlga Kornievskaia }
33095d0d30cSOlga Kornievskaia 
33195d0d30cSOlga Kornievskaia static
xprt_iter_current_entry_offline(struct rpc_xprt_iter * xpi)33295d0d30cSOlga Kornievskaia struct rpc_xprt *xprt_iter_current_entry_offline(struct rpc_xprt_iter *xpi)
33395d0d30cSOlga Kornievskaia {
33495d0d30cSOlga Kornievskaia 	return _xprt_iter_current_entry(xpi,
33595d0d30cSOlga Kornievskaia 			xprt_switch_find_first_entry_offline,
33695d0d30cSOlga Kornievskaia 			xprt_switch_find_current_entry_offline);
33780b14d5eSTrond Myklebust }
33880b14d5eSTrond Myklebust 
339*69c7eeb4SAnna Schumaker static
__rpc_xprt_switch_has_addr(struct rpc_xprt_switch * xps,const struct sockaddr * sap)340*69c7eeb4SAnna Schumaker bool __rpc_xprt_switch_has_addr(struct rpc_xprt_switch *xps,
34139e5d2dfSAndy Adamson 				const struct sockaddr *sap)
34239e5d2dfSAndy Adamson {
34339e5d2dfSAndy Adamson 	struct list_head *head;
34439e5d2dfSAndy Adamson 	struct rpc_xprt *pos;
34539e5d2dfSAndy Adamson 
34639e5d2dfSAndy Adamson 	if (xps == NULL || sap == NULL)
34739e5d2dfSAndy Adamson 		return false;
34839e5d2dfSAndy Adamson 
34939e5d2dfSAndy Adamson 	head = &xps->xps_xprt_list;
35039e5d2dfSAndy Adamson 	list_for_each_entry_rcu(pos, head, xprt_switch) {
35139e5d2dfSAndy Adamson 		if (rpc_cmp_addr_port(sap, (struct sockaddr *)&pos->addr)) {
35239e5d2dfSAndy Adamson 			pr_info("RPC:   addr %s already in xprt switch\n",
35339e5d2dfSAndy Adamson 				pos->address_strings[RPC_DISPLAY_ADDR]);
35439e5d2dfSAndy Adamson 			return true;
35539e5d2dfSAndy Adamson 		}
35639e5d2dfSAndy Adamson 	}
35739e5d2dfSAndy Adamson 	return false;
35839e5d2dfSAndy Adamson }
35939e5d2dfSAndy Adamson 
rpc_xprt_switch_has_addr(struct rpc_xprt_switch * xps,const struct sockaddr * sap)360*69c7eeb4SAnna Schumaker bool rpc_xprt_switch_has_addr(struct rpc_xprt_switch *xps,
361*69c7eeb4SAnna Schumaker 			      const struct sockaddr *sap)
362*69c7eeb4SAnna Schumaker {
363*69c7eeb4SAnna Schumaker 	bool res;
364*69c7eeb4SAnna Schumaker 
365*69c7eeb4SAnna Schumaker 	rcu_read_lock();
366*69c7eeb4SAnna Schumaker 	res = __rpc_xprt_switch_has_addr(xps, sap);
367*69c7eeb4SAnna Schumaker 	rcu_read_unlock();
368*69c7eeb4SAnna Schumaker 
369*69c7eeb4SAnna Schumaker 	return res;
370*69c7eeb4SAnna Schumaker }
371*69c7eeb4SAnna Schumaker 
37280b14d5eSTrond Myklebust static
xprt_switch_find_next_entry(struct list_head * head,const struct rpc_xprt * cur,bool check_active)37380b14d5eSTrond Myklebust struct rpc_xprt *xprt_switch_find_next_entry(struct list_head *head,
37495d0d30cSOlga Kornievskaia 		const struct rpc_xprt *cur, bool check_active)
37580b14d5eSTrond Myklebust {
37680b14d5eSTrond Myklebust 	struct rpc_xprt *pos, *prev = NULL;
377163f8821STrond Myklebust 	bool found = false;
37880b14d5eSTrond Myklebust 
37980b14d5eSTrond Myklebust 	list_for_each_entry_rcu(pos, head, xprt_switch) {
38080b14d5eSTrond Myklebust 		if (cur == prev)
381163f8821STrond Myklebust 			found = true;
38295d0d30cSOlga Kornievskaia 		/* for request to return active transports return only
38395d0d30cSOlga Kornievskaia 		 * active, for request to return offline transports
38495d0d30cSOlga Kornievskaia 		 * return only offline
38595d0d30cSOlga Kornievskaia 		 */
38695d0d30cSOlga Kornievskaia 		if (found && ((check_active && xprt_is_active(pos)) ||
38795d0d30cSOlga Kornievskaia 			      (!check_active && !xprt_is_active(pos))))
38880b14d5eSTrond Myklebust 			return pos;
38980b14d5eSTrond Myklebust 		prev = pos;
39080b14d5eSTrond Myklebust 	}
39180b14d5eSTrond Myklebust 	return NULL;
39280b14d5eSTrond Myklebust }
39380b14d5eSTrond Myklebust 
39480b14d5eSTrond Myklebust static
xprt_switch_set_next_cursor(struct rpc_xprt_switch * xps,struct rpc_xprt ** cursor,xprt_switch_find_xprt_t find_next)395f554af28STrond Myklebust struct rpc_xprt *xprt_switch_set_next_cursor(struct rpc_xprt_switch *xps,
39680b14d5eSTrond Myklebust 		struct rpc_xprt **cursor,
39780b14d5eSTrond Myklebust 		xprt_switch_find_xprt_t find_next)
39880b14d5eSTrond Myklebust {
399f554af28STrond Myklebust 	struct rpc_xprt *pos, *old;
40080b14d5eSTrond Myklebust 
401f554af28STrond Myklebust 	old = smp_load_acquire(cursor);
402f554af28STrond Myklebust 	pos = find_next(xps, old);
403f554af28STrond Myklebust 	smp_store_release(cursor, pos);
40480b14d5eSTrond Myklebust 	return pos;
40580b14d5eSTrond Myklebust }
40680b14d5eSTrond Myklebust 
40780b14d5eSTrond Myklebust static
xprt_iter_next_entry_multiple(struct rpc_xprt_iter * xpi,xprt_switch_find_xprt_t find_next)40880b14d5eSTrond Myklebust struct rpc_xprt *xprt_iter_next_entry_multiple(struct rpc_xprt_iter *xpi,
40980b14d5eSTrond Myklebust 		xprt_switch_find_xprt_t find_next)
41080b14d5eSTrond Myklebust {
41180b14d5eSTrond Myklebust 	struct rpc_xprt_switch *xps = rcu_dereference(xpi->xpi_xpswitch);
41280b14d5eSTrond Myklebust 
41380b14d5eSTrond Myklebust 	if (xps == NULL)
41480b14d5eSTrond Myklebust 		return NULL;
415f554af28STrond Myklebust 	return xprt_switch_set_next_cursor(xps, &xpi->xpi_cursor, find_next);
41680b14d5eSTrond Myklebust }
41780b14d5eSTrond Myklebust 
41880b14d5eSTrond Myklebust static
__xprt_switch_find_next_entry_roundrobin(struct list_head * head,const struct rpc_xprt * cur)419f554af28STrond Myklebust struct rpc_xprt *__xprt_switch_find_next_entry_roundrobin(struct list_head *head,
42080b14d5eSTrond Myklebust 		const struct rpc_xprt *cur)
42180b14d5eSTrond Myklebust {
42280b14d5eSTrond Myklebust 	struct rpc_xprt *ret;
42380b14d5eSTrond Myklebust 
42495d0d30cSOlga Kornievskaia 	ret = xprt_switch_find_next_entry(head, cur, true);
42580b14d5eSTrond Myklebust 	if (ret != NULL)
42680b14d5eSTrond Myklebust 		return ret;
42780b14d5eSTrond Myklebust 	return xprt_switch_find_first_entry(head);
42880b14d5eSTrond Myklebust }
42980b14d5eSTrond Myklebust 
43080b14d5eSTrond Myklebust static
xprt_switch_find_next_entry_roundrobin(struct rpc_xprt_switch * xps,const struct rpc_xprt * cur)431f554af28STrond Myklebust struct rpc_xprt *xprt_switch_find_next_entry_roundrobin(struct rpc_xprt_switch *xps,
432f554af28STrond Myklebust 		const struct rpc_xprt *cur)
43380b14d5eSTrond Myklebust {
434f554af28STrond Myklebust 	struct list_head *head = &xps->xps_xprt_list;
43521f0ffafSTrond Myklebust 	struct rpc_xprt *xprt;
436f554af28STrond Myklebust 	unsigned int nactive;
43721f0ffafSTrond Myklebust 
438f554af28STrond Myklebust 	for (;;) {
439f554af28STrond Myklebust 		unsigned long xprt_queuelen, xps_queuelen;
440f554af28STrond Myklebust 
441f554af28STrond Myklebust 		xprt = __xprt_switch_find_next_entry_roundrobin(head, cur);
442f554af28STrond Myklebust 		if (!xprt)
44321f0ffafSTrond Myklebust 			break;
44421f0ffafSTrond Myklebust 		xprt_queuelen = atomic_long_read(&xprt->queuelen);
44521f0ffafSTrond Myklebust 		xps_queuelen = atomic_long_read(&xps->xps_queuelen);
446f554af28STrond Myklebust 		nactive = READ_ONCE(xps->xps_nactive);
4473cf72922STrond Myklebust 		/* Exit loop if xprt_queuelen <= average queue length */
448f554af28STrond Myklebust 		if (xprt_queuelen * nactive <= xps_queuelen)
449f554af28STrond Myklebust 			break;
450f554af28STrond Myklebust 		cur = xprt;
451f554af28STrond Myklebust 	}
45221f0ffafSTrond Myklebust 	return xprt;
45380b14d5eSTrond Myklebust }
45480b14d5eSTrond Myklebust 
45580b14d5eSTrond Myklebust static
xprt_iter_next_entry_roundrobin(struct rpc_xprt_iter * xpi)456f554af28STrond Myklebust struct rpc_xprt *xprt_iter_next_entry_roundrobin(struct rpc_xprt_iter *xpi)
457f554af28STrond Myklebust {
458f554af28STrond Myklebust 	return xprt_iter_next_entry_multiple(xpi,
459f554af28STrond Myklebust 			xprt_switch_find_next_entry_roundrobin);
460f554af28STrond Myklebust }
461f554af28STrond Myklebust 
462f554af28STrond Myklebust static
xprt_switch_find_next_entry_all(struct rpc_xprt_switch * xps,const struct rpc_xprt * cur)463f554af28STrond Myklebust struct rpc_xprt *xprt_switch_find_next_entry_all(struct rpc_xprt_switch *xps,
464f554af28STrond Myklebust 		const struct rpc_xprt *cur)
465f554af28STrond Myklebust {
46695d0d30cSOlga Kornievskaia 	return xprt_switch_find_next_entry(&xps->xps_xprt_list, cur, true);
46795d0d30cSOlga Kornievskaia }
46895d0d30cSOlga Kornievskaia 
46995d0d30cSOlga Kornievskaia static
xprt_switch_find_next_entry_offline(struct rpc_xprt_switch * xps,const struct rpc_xprt * cur)47095d0d30cSOlga Kornievskaia struct rpc_xprt *xprt_switch_find_next_entry_offline(struct rpc_xprt_switch *xps,
47195d0d30cSOlga Kornievskaia 		const struct rpc_xprt *cur)
47295d0d30cSOlga Kornievskaia {
47395d0d30cSOlga Kornievskaia 	return xprt_switch_find_next_entry(&xps->xps_xprt_list, cur, false);
474f554af28STrond Myklebust }
475f554af28STrond Myklebust 
476f554af28STrond Myklebust static
xprt_iter_next_entry_all(struct rpc_xprt_iter * xpi)47780b14d5eSTrond Myklebust struct rpc_xprt *xprt_iter_next_entry_all(struct rpc_xprt_iter *xpi)
47880b14d5eSTrond Myklebust {
479f554af28STrond Myklebust 	return xprt_iter_next_entry_multiple(xpi,
480f554af28STrond Myklebust 			xprt_switch_find_next_entry_all);
48180b14d5eSTrond Myklebust }
48280b14d5eSTrond Myklebust 
48395d0d30cSOlga Kornievskaia static
xprt_iter_next_entry_offline(struct rpc_xprt_iter * xpi)48495d0d30cSOlga Kornievskaia struct rpc_xprt *xprt_iter_next_entry_offline(struct rpc_xprt_iter *xpi)
48595d0d30cSOlga Kornievskaia {
48695d0d30cSOlga Kornievskaia 	return xprt_iter_next_entry_multiple(xpi,
48795d0d30cSOlga Kornievskaia 			xprt_switch_find_next_entry_offline);
48895d0d30cSOlga Kornievskaia }
48995d0d30cSOlga Kornievskaia 
49080b14d5eSTrond Myklebust /*
49180b14d5eSTrond Myklebust  * xprt_iter_rewind - Resets the xprt iterator
49280b14d5eSTrond Myklebust  * @xpi: pointer to rpc_xprt_iter
49380b14d5eSTrond Myklebust  *
49480b14d5eSTrond Myklebust  * Resets xpi to ensure that it points to the first entry in the list
49580b14d5eSTrond Myklebust  * of transports.
49680b14d5eSTrond Myklebust  */
xprt_iter_rewind(struct rpc_xprt_iter * xpi)49780b14d5eSTrond Myklebust void xprt_iter_rewind(struct rpc_xprt_iter *xpi)
49880b14d5eSTrond Myklebust {
49980b14d5eSTrond Myklebust 	rcu_read_lock();
50080b14d5eSTrond Myklebust 	xprt_iter_ops(xpi)->xpi_rewind(xpi);
50180b14d5eSTrond Myklebust 	rcu_read_unlock();
50280b14d5eSTrond Myklebust }
50380b14d5eSTrond Myklebust 
__xprt_iter_init(struct rpc_xprt_iter * xpi,struct rpc_xprt_switch * xps,const struct rpc_xprt_iter_ops * ops)50480b14d5eSTrond Myklebust static void __xprt_iter_init(struct rpc_xprt_iter *xpi,
50580b14d5eSTrond Myklebust 		struct rpc_xprt_switch *xps,
50680b14d5eSTrond Myklebust 		const struct rpc_xprt_iter_ops *ops)
50780b14d5eSTrond Myklebust {
50880b14d5eSTrond Myklebust 	rcu_assign_pointer(xpi->xpi_xpswitch, xprt_switch_get(xps));
50980b14d5eSTrond Myklebust 	xpi->xpi_cursor = NULL;
51080b14d5eSTrond Myklebust 	xpi->xpi_ops = ops;
51180b14d5eSTrond Myklebust }
51280b14d5eSTrond Myklebust 
51380b14d5eSTrond Myklebust /**
51480b14d5eSTrond Myklebust  * xprt_iter_init - Initialise an xprt iterator
51580b14d5eSTrond Myklebust  * @xpi: pointer to rpc_xprt_iter
51680b14d5eSTrond Myklebust  * @xps: pointer to rpc_xprt_switch
51780b14d5eSTrond Myklebust  *
51880b14d5eSTrond Myklebust  * Initialises the iterator to use the default iterator ops
51980b14d5eSTrond Myklebust  * as set in xps. This function is mainly intended for internal
52080b14d5eSTrond Myklebust  * use in the rpc_client.
52180b14d5eSTrond Myklebust  */
xprt_iter_init(struct rpc_xprt_iter * xpi,struct rpc_xprt_switch * xps)52280b14d5eSTrond Myklebust void xprt_iter_init(struct rpc_xprt_iter *xpi,
52380b14d5eSTrond Myklebust 		struct rpc_xprt_switch *xps)
52480b14d5eSTrond Myklebust {
52580b14d5eSTrond Myklebust 	__xprt_iter_init(xpi, xps, NULL);
52680b14d5eSTrond Myklebust }
52780b14d5eSTrond Myklebust 
52880b14d5eSTrond Myklebust /**
52980b14d5eSTrond Myklebust  * xprt_iter_init_listall - Initialise an xprt iterator
53080b14d5eSTrond Myklebust  * @xpi: pointer to rpc_xprt_iter
53180b14d5eSTrond Myklebust  * @xps: pointer to rpc_xprt_switch
53280b14d5eSTrond Myklebust  *
53380b14d5eSTrond Myklebust  * Initialises the iterator to iterate once through the entire list
53480b14d5eSTrond Myklebust  * of entries in xps.
53580b14d5eSTrond Myklebust  */
xprt_iter_init_listall(struct rpc_xprt_iter * xpi,struct rpc_xprt_switch * xps)53680b14d5eSTrond Myklebust void xprt_iter_init_listall(struct rpc_xprt_iter *xpi,
53780b14d5eSTrond Myklebust 		struct rpc_xprt_switch *xps)
53880b14d5eSTrond Myklebust {
53980b14d5eSTrond Myklebust 	__xprt_iter_init(xpi, xps, &rpc_xprt_iter_listall);
54080b14d5eSTrond Myklebust }
54180b14d5eSTrond Myklebust 
xprt_iter_init_listoffline(struct rpc_xprt_iter * xpi,struct rpc_xprt_switch * xps)54295d0d30cSOlga Kornievskaia void xprt_iter_init_listoffline(struct rpc_xprt_iter *xpi,
54395d0d30cSOlga Kornievskaia 		struct rpc_xprt_switch *xps)
54495d0d30cSOlga Kornievskaia {
54595d0d30cSOlga Kornievskaia 	__xprt_iter_init(xpi, xps, &rpc_xprt_iter_listoffline);
54695d0d30cSOlga Kornievskaia }
54795d0d30cSOlga Kornievskaia 
54880b14d5eSTrond Myklebust /**
54980b14d5eSTrond Myklebust  * xprt_iter_xchg_switch - Atomically swap out the rpc_xprt_switch
55080b14d5eSTrond Myklebust  * @xpi: pointer to rpc_xprt_iter
551acf0a39fSChuck Lever  * @newswitch: pointer to a new rpc_xprt_switch or NULL
55280b14d5eSTrond Myklebust  *
55380b14d5eSTrond Myklebust  * Swaps out the existing xpi->xpi_xpswitch with a new value.
55480b14d5eSTrond Myklebust  */
xprt_iter_xchg_switch(struct rpc_xprt_iter * xpi,struct rpc_xprt_switch * newswitch)55580b14d5eSTrond Myklebust struct rpc_xprt_switch *xprt_iter_xchg_switch(struct rpc_xprt_iter *xpi,
55680b14d5eSTrond Myklebust 		struct rpc_xprt_switch *newswitch)
55780b14d5eSTrond Myklebust {
55880b14d5eSTrond Myklebust 	struct rpc_xprt_switch __rcu *oldswitch;
55980b14d5eSTrond Myklebust 
56080b14d5eSTrond Myklebust 	/* Atomically swap out the old xpswitch */
56180b14d5eSTrond Myklebust 	oldswitch = xchg(&xpi->xpi_xpswitch, RCU_INITIALIZER(newswitch));
56280b14d5eSTrond Myklebust 	if (newswitch != NULL)
56380b14d5eSTrond Myklebust 		xprt_iter_rewind(xpi);
56480b14d5eSTrond Myklebust 	return rcu_dereference_protected(oldswitch, true);
56580b14d5eSTrond Myklebust }
56680b14d5eSTrond Myklebust 
56780b14d5eSTrond Myklebust /**
56880b14d5eSTrond Myklebust  * xprt_iter_destroy - Destroys the xprt iterator
569acf0a39fSChuck Lever  * @xpi: pointer to rpc_xprt_iter
57080b14d5eSTrond Myklebust  */
xprt_iter_destroy(struct rpc_xprt_iter * xpi)57180b14d5eSTrond Myklebust void xprt_iter_destroy(struct rpc_xprt_iter *xpi)
57280b14d5eSTrond Myklebust {
57380b14d5eSTrond Myklebust 	xprt_switch_put(xprt_iter_xchg_switch(xpi, NULL));
57480b14d5eSTrond Myklebust }
57580b14d5eSTrond Myklebust 
57680b14d5eSTrond Myklebust /**
57780b14d5eSTrond Myklebust  * xprt_iter_xprt - Returns the rpc_xprt pointed to by the cursor
57880b14d5eSTrond Myklebust  * @xpi: pointer to rpc_xprt_iter
57980b14d5eSTrond Myklebust  *
58080b14d5eSTrond Myklebust  * Returns a pointer to the struct rpc_xprt that is currently
58180b14d5eSTrond Myklebust  * pointed to by the cursor.
58280b14d5eSTrond Myklebust  * Caller must be holding rcu_read_lock().
58380b14d5eSTrond Myklebust  */
xprt_iter_xprt(struct rpc_xprt_iter * xpi)58480b14d5eSTrond Myklebust struct rpc_xprt *xprt_iter_xprt(struct rpc_xprt_iter *xpi)
58580b14d5eSTrond Myklebust {
58680b14d5eSTrond Myklebust 	WARN_ON_ONCE(!rcu_read_lock_held());
58780b14d5eSTrond Myklebust 	return xprt_iter_ops(xpi)->xpi_xprt(xpi);
58880b14d5eSTrond Myklebust }
58980b14d5eSTrond Myklebust 
59080b14d5eSTrond Myklebust static
xprt_iter_get_helper(struct rpc_xprt_iter * xpi,struct rpc_xprt * (* fn)(struct rpc_xprt_iter *))59180b14d5eSTrond Myklebust struct rpc_xprt *xprt_iter_get_helper(struct rpc_xprt_iter *xpi,
59280b14d5eSTrond Myklebust 		struct rpc_xprt *(*fn)(struct rpc_xprt_iter *))
59380b14d5eSTrond Myklebust {
59480b14d5eSTrond Myklebust 	struct rpc_xprt *ret;
59580b14d5eSTrond Myklebust 
59680b14d5eSTrond Myklebust 	do {
59780b14d5eSTrond Myklebust 		ret = fn(xpi);
59880b14d5eSTrond Myklebust 		if (ret == NULL)
59980b14d5eSTrond Myklebust 			break;
60080b14d5eSTrond Myklebust 		ret = xprt_get(ret);
60180b14d5eSTrond Myklebust 	} while (ret == NULL);
60280b14d5eSTrond Myklebust 	return ret;
60380b14d5eSTrond Myklebust }
60480b14d5eSTrond Myklebust 
60580b14d5eSTrond Myklebust /**
60680b14d5eSTrond Myklebust  * xprt_iter_get_xprt - Returns the rpc_xprt pointed to by the cursor
60780b14d5eSTrond Myklebust  * @xpi: pointer to rpc_xprt_iter
60880b14d5eSTrond Myklebust  *
60980b14d5eSTrond Myklebust  * Returns a reference to the struct rpc_xprt that is currently
61080b14d5eSTrond Myklebust  * pointed to by the cursor.
61180b14d5eSTrond Myklebust  */
xprt_iter_get_xprt(struct rpc_xprt_iter * xpi)61280b14d5eSTrond Myklebust struct rpc_xprt *xprt_iter_get_xprt(struct rpc_xprt_iter *xpi)
61380b14d5eSTrond Myklebust {
61480b14d5eSTrond Myklebust 	struct rpc_xprt *xprt;
61580b14d5eSTrond Myklebust 
61680b14d5eSTrond Myklebust 	rcu_read_lock();
61780b14d5eSTrond Myklebust 	xprt = xprt_iter_get_helper(xpi, xprt_iter_ops(xpi)->xpi_xprt);
61880b14d5eSTrond Myklebust 	rcu_read_unlock();
61980b14d5eSTrond Myklebust 	return xprt;
62080b14d5eSTrond Myklebust }
62180b14d5eSTrond Myklebust 
62280b14d5eSTrond Myklebust /**
62380b14d5eSTrond Myklebust  * xprt_iter_get_next - Returns the next rpc_xprt following the cursor
62480b14d5eSTrond Myklebust  * @xpi: pointer to rpc_xprt_iter
62580b14d5eSTrond Myklebust  *
62680b14d5eSTrond Myklebust  * Returns a reference to the struct rpc_xprt that immediately follows the
62780b14d5eSTrond Myklebust  * entry pointed to by the cursor.
62880b14d5eSTrond Myklebust  */
xprt_iter_get_next(struct rpc_xprt_iter * xpi)62980b14d5eSTrond Myklebust struct rpc_xprt *xprt_iter_get_next(struct rpc_xprt_iter *xpi)
63080b14d5eSTrond Myklebust {
63180b14d5eSTrond Myklebust 	struct rpc_xprt *xprt;
63280b14d5eSTrond Myklebust 
63380b14d5eSTrond Myklebust 	rcu_read_lock();
63480b14d5eSTrond Myklebust 	xprt = xprt_iter_get_helper(xpi, xprt_iter_ops(xpi)->xpi_next);
63580b14d5eSTrond Myklebust 	rcu_read_unlock();
63680b14d5eSTrond Myklebust 	return xprt;
63780b14d5eSTrond Myklebust }
63880b14d5eSTrond Myklebust 
63980b14d5eSTrond Myklebust /* Policy for always returning the first entry in the rpc_xprt_switch */
64080b14d5eSTrond Myklebust static
64180b14d5eSTrond Myklebust const struct rpc_xprt_iter_ops rpc_xprt_iter_singular = {
64280b14d5eSTrond Myklebust 	.xpi_rewind = xprt_iter_no_rewind,
64380b14d5eSTrond Myklebust 	.xpi_xprt = xprt_iter_first_entry,
64480b14d5eSTrond Myklebust 	.xpi_next = xprt_iter_first_entry,
64580b14d5eSTrond Myklebust };
64680b14d5eSTrond Myklebust 
64780b14d5eSTrond Myklebust /* Policy for round-robin iteration of entries in the rpc_xprt_switch */
64880b14d5eSTrond Myklebust static
64980b14d5eSTrond Myklebust const struct rpc_xprt_iter_ops rpc_xprt_iter_roundrobin = {
65080b14d5eSTrond Myklebust 	.xpi_rewind = xprt_iter_default_rewind,
65180b14d5eSTrond Myklebust 	.xpi_xprt = xprt_iter_current_entry,
65280b14d5eSTrond Myklebust 	.xpi_next = xprt_iter_next_entry_roundrobin,
65380b14d5eSTrond Myklebust };
65480b14d5eSTrond Myklebust 
65580b14d5eSTrond Myklebust /* Policy for once-through iteration of entries in the rpc_xprt_switch */
65680b14d5eSTrond Myklebust static
65780b14d5eSTrond Myklebust const struct rpc_xprt_iter_ops rpc_xprt_iter_listall = {
65880b14d5eSTrond Myklebust 	.xpi_rewind = xprt_iter_default_rewind,
65980b14d5eSTrond Myklebust 	.xpi_xprt = xprt_iter_current_entry,
66080b14d5eSTrond Myklebust 	.xpi_next = xprt_iter_next_entry_all,
66180b14d5eSTrond Myklebust };
66295d0d30cSOlga Kornievskaia 
66395d0d30cSOlga Kornievskaia static
66495d0d30cSOlga Kornievskaia const struct rpc_xprt_iter_ops rpc_xprt_iter_listoffline = {
66595d0d30cSOlga Kornievskaia 	.xpi_rewind = xprt_iter_default_rewind,
66695d0d30cSOlga Kornievskaia 	.xpi_xprt = xprt_iter_current_entry_offline,
66795d0d30cSOlga Kornievskaia 	.xpi_next = xprt_iter_next_entry_offline,
66895d0d30cSOlga Kornievskaia };
669