xref: /openbmc/linux/net/sunrpc/xprtmultipath.c (revision 95d0d30c)
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