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