162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Multipath support for RPC
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2015, 2016, Primary Data, Inc. All rights reserved.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Trond Myklebust <trond.myklebust@primarydata.com>
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci#include <linux/atomic.h>
1162306a36Sopenharmony_ci#include <linux/types.h>
1262306a36Sopenharmony_ci#include <linux/kref.h>
1362306a36Sopenharmony_ci#include <linux/list.h>
1462306a36Sopenharmony_ci#include <linux/rcupdate.h>
1562306a36Sopenharmony_ci#include <linux/rculist.h>
1662306a36Sopenharmony_ci#include <linux/slab.h>
1762306a36Sopenharmony_ci#include <linux/spinlock.h>
1862306a36Sopenharmony_ci#include <linux/sunrpc/xprt.h>
1962306a36Sopenharmony_ci#include <linux/sunrpc/addr.h>
2062306a36Sopenharmony_ci#include <linux/sunrpc/xprtmultipath.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#include "sysfs.h"
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_citypedef struct rpc_xprt *(*xprt_switch_find_xprt_t)(struct rpc_xprt_switch *xps,
2562306a36Sopenharmony_ci		const struct rpc_xprt *cur);
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistatic const struct rpc_xprt_iter_ops rpc_xprt_iter_singular;
2862306a36Sopenharmony_cistatic const struct rpc_xprt_iter_ops rpc_xprt_iter_roundrobin;
2962306a36Sopenharmony_cistatic const struct rpc_xprt_iter_ops rpc_xprt_iter_listall;
3062306a36Sopenharmony_cistatic const struct rpc_xprt_iter_ops rpc_xprt_iter_listoffline;
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistatic void xprt_switch_add_xprt_locked(struct rpc_xprt_switch *xps,
3362306a36Sopenharmony_ci		struct rpc_xprt *xprt)
3462306a36Sopenharmony_ci{
3562306a36Sopenharmony_ci	if (unlikely(xprt_get(xprt) == NULL))
3662306a36Sopenharmony_ci		return;
3762306a36Sopenharmony_ci	list_add_tail_rcu(&xprt->xprt_switch, &xps->xps_xprt_list);
3862306a36Sopenharmony_ci	smp_wmb();
3962306a36Sopenharmony_ci	if (xps->xps_nxprts == 0)
4062306a36Sopenharmony_ci		xps->xps_net = xprt->xprt_net;
4162306a36Sopenharmony_ci	xps->xps_nxprts++;
4262306a36Sopenharmony_ci	xps->xps_nactive++;
4362306a36Sopenharmony_ci}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci/**
4662306a36Sopenharmony_ci * rpc_xprt_switch_add_xprt - Add a new rpc_xprt to an rpc_xprt_switch
4762306a36Sopenharmony_ci * @xps: pointer to struct rpc_xprt_switch
4862306a36Sopenharmony_ci * @xprt: pointer to struct rpc_xprt
4962306a36Sopenharmony_ci *
5062306a36Sopenharmony_ci * Adds xprt to the end of the list of struct rpc_xprt in xps.
5162306a36Sopenharmony_ci */
5262306a36Sopenharmony_civoid rpc_xprt_switch_add_xprt(struct rpc_xprt_switch *xps,
5362306a36Sopenharmony_ci		struct rpc_xprt *xprt)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	if (xprt == NULL)
5662306a36Sopenharmony_ci		return;
5762306a36Sopenharmony_ci	spin_lock(&xps->xps_lock);
5862306a36Sopenharmony_ci	if (xps->xps_net == xprt->xprt_net || xps->xps_net == NULL)
5962306a36Sopenharmony_ci		xprt_switch_add_xprt_locked(xps, xprt);
6062306a36Sopenharmony_ci	spin_unlock(&xps->xps_lock);
6162306a36Sopenharmony_ci	rpc_sysfs_xprt_setup(xps, xprt, GFP_KERNEL);
6262306a36Sopenharmony_ci}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic void xprt_switch_remove_xprt_locked(struct rpc_xprt_switch *xps,
6562306a36Sopenharmony_ci		struct rpc_xprt *xprt, bool offline)
6662306a36Sopenharmony_ci{
6762306a36Sopenharmony_ci	if (unlikely(xprt == NULL))
6862306a36Sopenharmony_ci		return;
6962306a36Sopenharmony_ci	if (!test_bit(XPRT_OFFLINE, &xprt->state) && offline)
7062306a36Sopenharmony_ci		xps->xps_nactive--;
7162306a36Sopenharmony_ci	xps->xps_nxprts--;
7262306a36Sopenharmony_ci	if (xps->xps_nxprts == 0)
7362306a36Sopenharmony_ci		xps->xps_net = NULL;
7462306a36Sopenharmony_ci	smp_wmb();
7562306a36Sopenharmony_ci	list_del_rcu(&xprt->xprt_switch);
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci/**
7962306a36Sopenharmony_ci * rpc_xprt_switch_remove_xprt - Removes an rpc_xprt from a rpc_xprt_switch
8062306a36Sopenharmony_ci * @xps: pointer to struct rpc_xprt_switch
8162306a36Sopenharmony_ci * @xprt: pointer to struct rpc_xprt
8262306a36Sopenharmony_ci * @offline: indicates if the xprt that's being removed is in an offline state
8362306a36Sopenharmony_ci *
8462306a36Sopenharmony_ci * Removes xprt from the list of struct rpc_xprt in xps.
8562306a36Sopenharmony_ci */
8662306a36Sopenharmony_civoid rpc_xprt_switch_remove_xprt(struct rpc_xprt_switch *xps,
8762306a36Sopenharmony_ci		struct rpc_xprt *xprt, bool offline)
8862306a36Sopenharmony_ci{
8962306a36Sopenharmony_ci	spin_lock(&xps->xps_lock);
9062306a36Sopenharmony_ci	xprt_switch_remove_xprt_locked(xps, xprt, offline);
9162306a36Sopenharmony_ci	spin_unlock(&xps->xps_lock);
9262306a36Sopenharmony_ci	xprt_put(xprt);
9362306a36Sopenharmony_ci}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistatic DEFINE_IDA(rpc_xprtswitch_ids);
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_civoid xprt_multipath_cleanup_ids(void)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	ida_destroy(&rpc_xprtswitch_ids);
10062306a36Sopenharmony_ci}
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistatic int xprt_switch_alloc_id(struct rpc_xprt_switch *xps, gfp_t gfp_flags)
10362306a36Sopenharmony_ci{
10462306a36Sopenharmony_ci	int id;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	id = ida_alloc(&rpc_xprtswitch_ids, gfp_flags);
10762306a36Sopenharmony_ci	if (id < 0)
10862306a36Sopenharmony_ci		return id;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	xps->xps_id = id;
11162306a36Sopenharmony_ci	return 0;
11262306a36Sopenharmony_ci}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_cistatic void xprt_switch_free_id(struct rpc_xprt_switch *xps)
11562306a36Sopenharmony_ci{
11662306a36Sopenharmony_ci	ida_free(&rpc_xprtswitch_ids, xps->xps_id);
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci/**
12062306a36Sopenharmony_ci * xprt_switch_alloc - Allocate a new struct rpc_xprt_switch
12162306a36Sopenharmony_ci * @xprt: pointer to struct rpc_xprt
12262306a36Sopenharmony_ci * @gfp_flags: allocation flags
12362306a36Sopenharmony_ci *
12462306a36Sopenharmony_ci * On success, returns an initialised struct rpc_xprt_switch, containing
12562306a36Sopenharmony_ci * the entry xprt. Returns NULL on failure.
12662306a36Sopenharmony_ci */
12762306a36Sopenharmony_cistruct rpc_xprt_switch *xprt_switch_alloc(struct rpc_xprt *xprt,
12862306a36Sopenharmony_ci		gfp_t gfp_flags)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	struct rpc_xprt_switch *xps;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	xps = kmalloc(sizeof(*xps), gfp_flags);
13362306a36Sopenharmony_ci	if (xps != NULL) {
13462306a36Sopenharmony_ci		spin_lock_init(&xps->xps_lock);
13562306a36Sopenharmony_ci		kref_init(&xps->xps_kref);
13662306a36Sopenharmony_ci		xprt_switch_alloc_id(xps, gfp_flags);
13762306a36Sopenharmony_ci		xps->xps_nxprts = xps->xps_nactive = 0;
13862306a36Sopenharmony_ci		atomic_long_set(&xps->xps_queuelen, 0);
13962306a36Sopenharmony_ci		xps->xps_net = NULL;
14062306a36Sopenharmony_ci		INIT_LIST_HEAD(&xps->xps_xprt_list);
14162306a36Sopenharmony_ci		xps->xps_iter_ops = &rpc_xprt_iter_singular;
14262306a36Sopenharmony_ci		rpc_sysfs_xprt_switch_setup(xps, xprt, gfp_flags);
14362306a36Sopenharmony_ci		xprt_switch_add_xprt_locked(xps, xprt);
14462306a36Sopenharmony_ci		xps->xps_nunique_destaddr_xprts = 1;
14562306a36Sopenharmony_ci		rpc_sysfs_xprt_setup(xps, xprt, gfp_flags);
14662306a36Sopenharmony_ci	}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	return xps;
14962306a36Sopenharmony_ci}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cistatic void xprt_switch_free_entries(struct rpc_xprt_switch *xps)
15262306a36Sopenharmony_ci{
15362306a36Sopenharmony_ci	spin_lock(&xps->xps_lock);
15462306a36Sopenharmony_ci	while (!list_empty(&xps->xps_xprt_list)) {
15562306a36Sopenharmony_ci		struct rpc_xprt *xprt;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci		xprt = list_first_entry(&xps->xps_xprt_list,
15862306a36Sopenharmony_ci				struct rpc_xprt, xprt_switch);
15962306a36Sopenharmony_ci		xprt_switch_remove_xprt_locked(xps, xprt, true);
16062306a36Sopenharmony_ci		spin_unlock(&xps->xps_lock);
16162306a36Sopenharmony_ci		xprt_put(xprt);
16262306a36Sopenharmony_ci		spin_lock(&xps->xps_lock);
16362306a36Sopenharmony_ci	}
16462306a36Sopenharmony_ci	spin_unlock(&xps->xps_lock);
16562306a36Sopenharmony_ci}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_cistatic void xprt_switch_free(struct kref *kref)
16862306a36Sopenharmony_ci{
16962306a36Sopenharmony_ci	struct rpc_xprt_switch *xps = container_of(kref,
17062306a36Sopenharmony_ci			struct rpc_xprt_switch, xps_kref);
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	xprt_switch_free_entries(xps);
17362306a36Sopenharmony_ci	rpc_sysfs_xprt_switch_destroy(xps);
17462306a36Sopenharmony_ci	xprt_switch_free_id(xps);
17562306a36Sopenharmony_ci	kfree_rcu(xps, xps_rcu);
17662306a36Sopenharmony_ci}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci/**
17962306a36Sopenharmony_ci * xprt_switch_get - Return a reference to a rpc_xprt_switch
18062306a36Sopenharmony_ci * @xps: pointer to struct rpc_xprt_switch
18162306a36Sopenharmony_ci *
18262306a36Sopenharmony_ci * Returns a reference to xps unless the refcount is already zero.
18362306a36Sopenharmony_ci */
18462306a36Sopenharmony_cistruct rpc_xprt_switch *xprt_switch_get(struct rpc_xprt_switch *xps)
18562306a36Sopenharmony_ci{
18662306a36Sopenharmony_ci	if (xps != NULL && kref_get_unless_zero(&xps->xps_kref))
18762306a36Sopenharmony_ci		return xps;
18862306a36Sopenharmony_ci	return NULL;
18962306a36Sopenharmony_ci}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci/**
19262306a36Sopenharmony_ci * xprt_switch_put - Release a reference to a rpc_xprt_switch
19362306a36Sopenharmony_ci * @xps: pointer to struct rpc_xprt_switch
19462306a36Sopenharmony_ci *
19562306a36Sopenharmony_ci * Release the reference to xps, and free it once the refcount is zero.
19662306a36Sopenharmony_ci */
19762306a36Sopenharmony_civoid xprt_switch_put(struct rpc_xprt_switch *xps)
19862306a36Sopenharmony_ci{
19962306a36Sopenharmony_ci	if (xps != NULL)
20062306a36Sopenharmony_ci		kref_put(&xps->xps_kref, xprt_switch_free);
20162306a36Sopenharmony_ci}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci/**
20462306a36Sopenharmony_ci * rpc_xprt_switch_set_roundrobin - Set a round-robin policy on rpc_xprt_switch
20562306a36Sopenharmony_ci * @xps: pointer to struct rpc_xprt_switch
20662306a36Sopenharmony_ci *
20762306a36Sopenharmony_ci * Sets a round-robin default policy for iterators acting on xps.
20862306a36Sopenharmony_ci */
20962306a36Sopenharmony_civoid rpc_xprt_switch_set_roundrobin(struct rpc_xprt_switch *xps)
21062306a36Sopenharmony_ci{
21162306a36Sopenharmony_ci	if (READ_ONCE(xps->xps_iter_ops) != &rpc_xprt_iter_roundrobin)
21262306a36Sopenharmony_ci		WRITE_ONCE(xps->xps_iter_ops, &rpc_xprt_iter_roundrobin);
21362306a36Sopenharmony_ci}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_cistatic
21662306a36Sopenharmony_ciconst struct rpc_xprt_iter_ops *xprt_iter_ops(const struct rpc_xprt_iter *xpi)
21762306a36Sopenharmony_ci{
21862306a36Sopenharmony_ci	if (xpi->xpi_ops != NULL)
21962306a36Sopenharmony_ci		return xpi->xpi_ops;
22062306a36Sopenharmony_ci	return rcu_dereference(xpi->xpi_xpswitch)->xps_iter_ops;
22162306a36Sopenharmony_ci}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_cistatic
22462306a36Sopenharmony_civoid xprt_iter_no_rewind(struct rpc_xprt_iter *xpi)
22562306a36Sopenharmony_ci{
22662306a36Sopenharmony_ci}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_cistatic
22962306a36Sopenharmony_civoid xprt_iter_default_rewind(struct rpc_xprt_iter *xpi)
23062306a36Sopenharmony_ci{
23162306a36Sopenharmony_ci	WRITE_ONCE(xpi->xpi_cursor, NULL);
23262306a36Sopenharmony_ci}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_cistatic
23562306a36Sopenharmony_cibool xprt_is_active(const struct rpc_xprt *xprt)
23662306a36Sopenharmony_ci{
23762306a36Sopenharmony_ci	return (kref_read(&xprt->kref) != 0 &&
23862306a36Sopenharmony_ci		!test_bit(XPRT_OFFLINE, &xprt->state));
23962306a36Sopenharmony_ci}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_cistatic
24262306a36Sopenharmony_cistruct rpc_xprt *xprt_switch_find_first_entry(struct list_head *head)
24362306a36Sopenharmony_ci{
24462306a36Sopenharmony_ci	struct rpc_xprt *pos;
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	list_for_each_entry_rcu(pos, head, xprt_switch) {
24762306a36Sopenharmony_ci		if (xprt_is_active(pos))
24862306a36Sopenharmony_ci			return pos;
24962306a36Sopenharmony_ci	}
25062306a36Sopenharmony_ci	return NULL;
25162306a36Sopenharmony_ci}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_cistatic
25462306a36Sopenharmony_cistruct rpc_xprt *xprt_switch_find_first_entry_offline(struct list_head *head)
25562306a36Sopenharmony_ci{
25662306a36Sopenharmony_ci	struct rpc_xprt *pos;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	list_for_each_entry_rcu(pos, head, xprt_switch) {
25962306a36Sopenharmony_ci		if (!xprt_is_active(pos))
26062306a36Sopenharmony_ci			return pos;
26162306a36Sopenharmony_ci	}
26262306a36Sopenharmony_ci	return NULL;
26362306a36Sopenharmony_ci}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_cistatic
26662306a36Sopenharmony_cistruct rpc_xprt *xprt_iter_first_entry(struct rpc_xprt_iter *xpi)
26762306a36Sopenharmony_ci{
26862306a36Sopenharmony_ci	struct rpc_xprt_switch *xps = rcu_dereference(xpi->xpi_xpswitch);
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	if (xps == NULL)
27162306a36Sopenharmony_ci		return NULL;
27262306a36Sopenharmony_ci	return xprt_switch_find_first_entry(&xps->xps_xprt_list);
27362306a36Sopenharmony_ci}
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_cistatic
27662306a36Sopenharmony_cistruct rpc_xprt *_xprt_switch_find_current_entry(struct list_head *head,
27762306a36Sopenharmony_ci						 const struct rpc_xprt *cur,
27862306a36Sopenharmony_ci						 bool find_active)
27962306a36Sopenharmony_ci{
28062306a36Sopenharmony_ci	struct rpc_xprt *pos;
28162306a36Sopenharmony_ci	bool found = false;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	list_for_each_entry_rcu(pos, head, xprt_switch) {
28462306a36Sopenharmony_ci		if (cur == pos)
28562306a36Sopenharmony_ci			found = true;
28662306a36Sopenharmony_ci		if (found && ((find_active && xprt_is_active(pos)) ||
28762306a36Sopenharmony_ci			      (!find_active && !xprt_is_active(pos))))
28862306a36Sopenharmony_ci			return pos;
28962306a36Sopenharmony_ci	}
29062306a36Sopenharmony_ci	return NULL;
29162306a36Sopenharmony_ci}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_cistatic
29462306a36Sopenharmony_cistruct rpc_xprt *xprt_switch_find_current_entry(struct list_head *head,
29562306a36Sopenharmony_ci						const struct rpc_xprt *cur)
29662306a36Sopenharmony_ci{
29762306a36Sopenharmony_ci	return _xprt_switch_find_current_entry(head, cur, true);
29862306a36Sopenharmony_ci}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_cistatic
30162306a36Sopenharmony_cistruct rpc_xprt * _xprt_iter_current_entry(struct rpc_xprt_iter *xpi,
30262306a36Sopenharmony_ci		struct rpc_xprt *first_entry(struct list_head *head),
30362306a36Sopenharmony_ci		struct rpc_xprt *current_entry(struct list_head *head,
30462306a36Sopenharmony_ci					       const struct rpc_xprt *cur))
30562306a36Sopenharmony_ci{
30662306a36Sopenharmony_ci	struct rpc_xprt_switch *xps = rcu_dereference(xpi->xpi_xpswitch);
30762306a36Sopenharmony_ci	struct list_head *head;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	if (xps == NULL)
31062306a36Sopenharmony_ci		return NULL;
31162306a36Sopenharmony_ci	head = &xps->xps_xprt_list;
31262306a36Sopenharmony_ci	if (xpi->xpi_cursor == NULL || xps->xps_nxprts < 2)
31362306a36Sopenharmony_ci		return first_entry(head);
31462306a36Sopenharmony_ci	return current_entry(head, xpi->xpi_cursor);
31562306a36Sopenharmony_ci}
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_cistatic
31862306a36Sopenharmony_cistruct rpc_xprt *xprt_iter_current_entry(struct rpc_xprt_iter *xpi)
31962306a36Sopenharmony_ci{
32062306a36Sopenharmony_ci	return _xprt_iter_current_entry(xpi, xprt_switch_find_first_entry,
32162306a36Sopenharmony_ci			xprt_switch_find_current_entry);
32262306a36Sopenharmony_ci}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_cistatic
32562306a36Sopenharmony_cistruct rpc_xprt *xprt_switch_find_current_entry_offline(struct list_head *head,
32662306a36Sopenharmony_ci		const struct rpc_xprt *cur)
32762306a36Sopenharmony_ci{
32862306a36Sopenharmony_ci	return _xprt_switch_find_current_entry(head, cur, false);
32962306a36Sopenharmony_ci}
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_cistatic
33262306a36Sopenharmony_cistruct rpc_xprt *xprt_iter_current_entry_offline(struct rpc_xprt_iter *xpi)
33362306a36Sopenharmony_ci{
33462306a36Sopenharmony_ci	return _xprt_iter_current_entry(xpi,
33562306a36Sopenharmony_ci			xprt_switch_find_first_entry_offline,
33662306a36Sopenharmony_ci			xprt_switch_find_current_entry_offline);
33762306a36Sopenharmony_ci}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_cistatic
34062306a36Sopenharmony_cibool __rpc_xprt_switch_has_addr(struct rpc_xprt_switch *xps,
34162306a36Sopenharmony_ci				const struct sockaddr *sap)
34262306a36Sopenharmony_ci{
34362306a36Sopenharmony_ci	struct list_head *head;
34462306a36Sopenharmony_ci	struct rpc_xprt *pos;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	if (xps == NULL || sap == NULL)
34762306a36Sopenharmony_ci		return false;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	head = &xps->xps_xprt_list;
35062306a36Sopenharmony_ci	list_for_each_entry_rcu(pos, head, xprt_switch) {
35162306a36Sopenharmony_ci		if (rpc_cmp_addr_port(sap, (struct sockaddr *)&pos->addr)) {
35262306a36Sopenharmony_ci			pr_info("RPC:   addr %s already in xprt switch\n",
35362306a36Sopenharmony_ci				pos->address_strings[RPC_DISPLAY_ADDR]);
35462306a36Sopenharmony_ci			return true;
35562306a36Sopenharmony_ci		}
35662306a36Sopenharmony_ci	}
35762306a36Sopenharmony_ci	return false;
35862306a36Sopenharmony_ci}
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_cibool rpc_xprt_switch_has_addr(struct rpc_xprt_switch *xps,
36162306a36Sopenharmony_ci			      const struct sockaddr *sap)
36262306a36Sopenharmony_ci{
36362306a36Sopenharmony_ci	bool res;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	rcu_read_lock();
36662306a36Sopenharmony_ci	res = __rpc_xprt_switch_has_addr(xps, sap);
36762306a36Sopenharmony_ci	rcu_read_unlock();
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	return res;
37062306a36Sopenharmony_ci}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_cistatic
37362306a36Sopenharmony_cistruct rpc_xprt *xprt_switch_find_next_entry(struct list_head *head,
37462306a36Sopenharmony_ci		const struct rpc_xprt *cur, bool check_active)
37562306a36Sopenharmony_ci{
37662306a36Sopenharmony_ci	struct rpc_xprt *pos, *prev = NULL;
37762306a36Sopenharmony_ci	bool found = false;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	list_for_each_entry_rcu(pos, head, xprt_switch) {
38062306a36Sopenharmony_ci		if (cur == prev)
38162306a36Sopenharmony_ci			found = true;
38262306a36Sopenharmony_ci		/* for request to return active transports return only
38362306a36Sopenharmony_ci		 * active, for request to return offline transports
38462306a36Sopenharmony_ci		 * return only offline
38562306a36Sopenharmony_ci		 */
38662306a36Sopenharmony_ci		if (found && ((check_active && xprt_is_active(pos)) ||
38762306a36Sopenharmony_ci			      (!check_active && !xprt_is_active(pos))))
38862306a36Sopenharmony_ci			return pos;
38962306a36Sopenharmony_ci		prev = pos;
39062306a36Sopenharmony_ci	}
39162306a36Sopenharmony_ci	return NULL;
39262306a36Sopenharmony_ci}
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_cistatic
39562306a36Sopenharmony_cistruct rpc_xprt *xprt_switch_set_next_cursor(struct rpc_xprt_switch *xps,
39662306a36Sopenharmony_ci		struct rpc_xprt **cursor,
39762306a36Sopenharmony_ci		xprt_switch_find_xprt_t find_next)
39862306a36Sopenharmony_ci{
39962306a36Sopenharmony_ci	struct rpc_xprt *pos, *old;
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	old = smp_load_acquire(cursor);
40262306a36Sopenharmony_ci	pos = find_next(xps, old);
40362306a36Sopenharmony_ci	smp_store_release(cursor, pos);
40462306a36Sopenharmony_ci	return pos;
40562306a36Sopenharmony_ci}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_cistatic
40862306a36Sopenharmony_cistruct rpc_xprt *xprt_iter_next_entry_multiple(struct rpc_xprt_iter *xpi,
40962306a36Sopenharmony_ci		xprt_switch_find_xprt_t find_next)
41062306a36Sopenharmony_ci{
41162306a36Sopenharmony_ci	struct rpc_xprt_switch *xps = rcu_dereference(xpi->xpi_xpswitch);
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	if (xps == NULL)
41462306a36Sopenharmony_ci		return NULL;
41562306a36Sopenharmony_ci	return xprt_switch_set_next_cursor(xps, &xpi->xpi_cursor, find_next);
41662306a36Sopenharmony_ci}
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_cistatic
41962306a36Sopenharmony_cistruct rpc_xprt *__xprt_switch_find_next_entry_roundrobin(struct list_head *head,
42062306a36Sopenharmony_ci		const struct rpc_xprt *cur)
42162306a36Sopenharmony_ci{
42262306a36Sopenharmony_ci	struct rpc_xprt *ret;
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	ret = xprt_switch_find_next_entry(head, cur, true);
42562306a36Sopenharmony_ci	if (ret != NULL)
42662306a36Sopenharmony_ci		return ret;
42762306a36Sopenharmony_ci	return xprt_switch_find_first_entry(head);
42862306a36Sopenharmony_ci}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_cistatic
43162306a36Sopenharmony_cistruct rpc_xprt *xprt_switch_find_next_entry_roundrobin(struct rpc_xprt_switch *xps,
43262306a36Sopenharmony_ci		const struct rpc_xprt *cur)
43362306a36Sopenharmony_ci{
43462306a36Sopenharmony_ci	struct list_head *head = &xps->xps_xprt_list;
43562306a36Sopenharmony_ci	struct rpc_xprt *xprt;
43662306a36Sopenharmony_ci	unsigned int nactive;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	for (;;) {
43962306a36Sopenharmony_ci		unsigned long xprt_queuelen, xps_queuelen;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci		xprt = __xprt_switch_find_next_entry_roundrobin(head, cur);
44262306a36Sopenharmony_ci		if (!xprt)
44362306a36Sopenharmony_ci			break;
44462306a36Sopenharmony_ci		xprt_queuelen = atomic_long_read(&xprt->queuelen);
44562306a36Sopenharmony_ci		xps_queuelen = atomic_long_read(&xps->xps_queuelen);
44662306a36Sopenharmony_ci		nactive = READ_ONCE(xps->xps_nactive);
44762306a36Sopenharmony_ci		/* Exit loop if xprt_queuelen <= average queue length */
44862306a36Sopenharmony_ci		if (xprt_queuelen * nactive <= xps_queuelen)
44962306a36Sopenharmony_ci			break;
45062306a36Sopenharmony_ci		cur = xprt;
45162306a36Sopenharmony_ci	}
45262306a36Sopenharmony_ci	return xprt;
45362306a36Sopenharmony_ci}
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_cistatic
45662306a36Sopenharmony_cistruct rpc_xprt *xprt_iter_next_entry_roundrobin(struct rpc_xprt_iter *xpi)
45762306a36Sopenharmony_ci{
45862306a36Sopenharmony_ci	return xprt_iter_next_entry_multiple(xpi,
45962306a36Sopenharmony_ci			xprt_switch_find_next_entry_roundrobin);
46062306a36Sopenharmony_ci}
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_cistatic
46362306a36Sopenharmony_cistruct rpc_xprt *xprt_switch_find_next_entry_all(struct rpc_xprt_switch *xps,
46462306a36Sopenharmony_ci		const struct rpc_xprt *cur)
46562306a36Sopenharmony_ci{
46662306a36Sopenharmony_ci	return xprt_switch_find_next_entry(&xps->xps_xprt_list, cur, true);
46762306a36Sopenharmony_ci}
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_cistatic
47062306a36Sopenharmony_cistruct rpc_xprt *xprt_switch_find_next_entry_offline(struct rpc_xprt_switch *xps,
47162306a36Sopenharmony_ci		const struct rpc_xprt *cur)
47262306a36Sopenharmony_ci{
47362306a36Sopenharmony_ci	return xprt_switch_find_next_entry(&xps->xps_xprt_list, cur, false);
47462306a36Sopenharmony_ci}
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_cistatic
47762306a36Sopenharmony_cistruct rpc_xprt *xprt_iter_next_entry_all(struct rpc_xprt_iter *xpi)
47862306a36Sopenharmony_ci{
47962306a36Sopenharmony_ci	return xprt_iter_next_entry_multiple(xpi,
48062306a36Sopenharmony_ci			xprt_switch_find_next_entry_all);
48162306a36Sopenharmony_ci}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_cistatic
48462306a36Sopenharmony_cistruct rpc_xprt *xprt_iter_next_entry_offline(struct rpc_xprt_iter *xpi)
48562306a36Sopenharmony_ci{
48662306a36Sopenharmony_ci	return xprt_iter_next_entry_multiple(xpi,
48762306a36Sopenharmony_ci			xprt_switch_find_next_entry_offline);
48862306a36Sopenharmony_ci}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci/*
49162306a36Sopenharmony_ci * xprt_iter_rewind - Resets the xprt iterator
49262306a36Sopenharmony_ci * @xpi: pointer to rpc_xprt_iter
49362306a36Sopenharmony_ci *
49462306a36Sopenharmony_ci * Resets xpi to ensure that it points to the first entry in the list
49562306a36Sopenharmony_ci * of transports.
49662306a36Sopenharmony_ci */
49762306a36Sopenharmony_civoid xprt_iter_rewind(struct rpc_xprt_iter *xpi)
49862306a36Sopenharmony_ci{
49962306a36Sopenharmony_ci	rcu_read_lock();
50062306a36Sopenharmony_ci	xprt_iter_ops(xpi)->xpi_rewind(xpi);
50162306a36Sopenharmony_ci	rcu_read_unlock();
50262306a36Sopenharmony_ci}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_cistatic void __xprt_iter_init(struct rpc_xprt_iter *xpi,
50562306a36Sopenharmony_ci		struct rpc_xprt_switch *xps,
50662306a36Sopenharmony_ci		const struct rpc_xprt_iter_ops *ops)
50762306a36Sopenharmony_ci{
50862306a36Sopenharmony_ci	rcu_assign_pointer(xpi->xpi_xpswitch, xprt_switch_get(xps));
50962306a36Sopenharmony_ci	xpi->xpi_cursor = NULL;
51062306a36Sopenharmony_ci	xpi->xpi_ops = ops;
51162306a36Sopenharmony_ci}
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci/**
51462306a36Sopenharmony_ci * xprt_iter_init - Initialise an xprt iterator
51562306a36Sopenharmony_ci * @xpi: pointer to rpc_xprt_iter
51662306a36Sopenharmony_ci * @xps: pointer to rpc_xprt_switch
51762306a36Sopenharmony_ci *
51862306a36Sopenharmony_ci * Initialises the iterator to use the default iterator ops
51962306a36Sopenharmony_ci * as set in xps. This function is mainly intended for internal
52062306a36Sopenharmony_ci * use in the rpc_client.
52162306a36Sopenharmony_ci */
52262306a36Sopenharmony_civoid xprt_iter_init(struct rpc_xprt_iter *xpi,
52362306a36Sopenharmony_ci		struct rpc_xprt_switch *xps)
52462306a36Sopenharmony_ci{
52562306a36Sopenharmony_ci	__xprt_iter_init(xpi, xps, NULL);
52662306a36Sopenharmony_ci}
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci/**
52962306a36Sopenharmony_ci * xprt_iter_init_listall - Initialise an xprt iterator
53062306a36Sopenharmony_ci * @xpi: pointer to rpc_xprt_iter
53162306a36Sopenharmony_ci * @xps: pointer to rpc_xprt_switch
53262306a36Sopenharmony_ci *
53362306a36Sopenharmony_ci * Initialises the iterator to iterate once through the entire list
53462306a36Sopenharmony_ci * of entries in xps.
53562306a36Sopenharmony_ci */
53662306a36Sopenharmony_civoid xprt_iter_init_listall(struct rpc_xprt_iter *xpi,
53762306a36Sopenharmony_ci		struct rpc_xprt_switch *xps)
53862306a36Sopenharmony_ci{
53962306a36Sopenharmony_ci	__xprt_iter_init(xpi, xps, &rpc_xprt_iter_listall);
54062306a36Sopenharmony_ci}
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_civoid xprt_iter_init_listoffline(struct rpc_xprt_iter *xpi,
54362306a36Sopenharmony_ci		struct rpc_xprt_switch *xps)
54462306a36Sopenharmony_ci{
54562306a36Sopenharmony_ci	__xprt_iter_init(xpi, xps, &rpc_xprt_iter_listoffline);
54662306a36Sopenharmony_ci}
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci/**
54962306a36Sopenharmony_ci * xprt_iter_xchg_switch - Atomically swap out the rpc_xprt_switch
55062306a36Sopenharmony_ci * @xpi: pointer to rpc_xprt_iter
55162306a36Sopenharmony_ci * @newswitch: pointer to a new rpc_xprt_switch or NULL
55262306a36Sopenharmony_ci *
55362306a36Sopenharmony_ci * Swaps out the existing xpi->xpi_xpswitch with a new value.
55462306a36Sopenharmony_ci */
55562306a36Sopenharmony_cistruct rpc_xprt_switch *xprt_iter_xchg_switch(struct rpc_xprt_iter *xpi,
55662306a36Sopenharmony_ci		struct rpc_xprt_switch *newswitch)
55762306a36Sopenharmony_ci{
55862306a36Sopenharmony_ci	struct rpc_xprt_switch __rcu *oldswitch;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	/* Atomically swap out the old xpswitch */
56162306a36Sopenharmony_ci	oldswitch = xchg(&xpi->xpi_xpswitch, RCU_INITIALIZER(newswitch));
56262306a36Sopenharmony_ci	if (newswitch != NULL)
56362306a36Sopenharmony_ci		xprt_iter_rewind(xpi);
56462306a36Sopenharmony_ci	return rcu_dereference_protected(oldswitch, true);
56562306a36Sopenharmony_ci}
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci/**
56862306a36Sopenharmony_ci * xprt_iter_destroy - Destroys the xprt iterator
56962306a36Sopenharmony_ci * @xpi: pointer to rpc_xprt_iter
57062306a36Sopenharmony_ci */
57162306a36Sopenharmony_civoid xprt_iter_destroy(struct rpc_xprt_iter *xpi)
57262306a36Sopenharmony_ci{
57362306a36Sopenharmony_ci	xprt_switch_put(xprt_iter_xchg_switch(xpi, NULL));
57462306a36Sopenharmony_ci}
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci/**
57762306a36Sopenharmony_ci * xprt_iter_xprt - Returns the rpc_xprt pointed to by the cursor
57862306a36Sopenharmony_ci * @xpi: pointer to rpc_xprt_iter
57962306a36Sopenharmony_ci *
58062306a36Sopenharmony_ci * Returns a pointer to the struct rpc_xprt that is currently
58162306a36Sopenharmony_ci * pointed to by the cursor.
58262306a36Sopenharmony_ci * Caller must be holding rcu_read_lock().
58362306a36Sopenharmony_ci */
58462306a36Sopenharmony_cistruct rpc_xprt *xprt_iter_xprt(struct rpc_xprt_iter *xpi)
58562306a36Sopenharmony_ci{
58662306a36Sopenharmony_ci	WARN_ON_ONCE(!rcu_read_lock_held());
58762306a36Sopenharmony_ci	return xprt_iter_ops(xpi)->xpi_xprt(xpi);
58862306a36Sopenharmony_ci}
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_cistatic
59162306a36Sopenharmony_cistruct rpc_xprt *xprt_iter_get_helper(struct rpc_xprt_iter *xpi,
59262306a36Sopenharmony_ci		struct rpc_xprt *(*fn)(struct rpc_xprt_iter *))
59362306a36Sopenharmony_ci{
59462306a36Sopenharmony_ci	struct rpc_xprt *ret;
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	do {
59762306a36Sopenharmony_ci		ret = fn(xpi);
59862306a36Sopenharmony_ci		if (ret == NULL)
59962306a36Sopenharmony_ci			break;
60062306a36Sopenharmony_ci		ret = xprt_get(ret);
60162306a36Sopenharmony_ci	} while (ret == NULL);
60262306a36Sopenharmony_ci	return ret;
60362306a36Sopenharmony_ci}
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci/**
60662306a36Sopenharmony_ci * xprt_iter_get_xprt - Returns the rpc_xprt pointed to by the cursor
60762306a36Sopenharmony_ci * @xpi: pointer to rpc_xprt_iter
60862306a36Sopenharmony_ci *
60962306a36Sopenharmony_ci * Returns a reference to the struct rpc_xprt that is currently
61062306a36Sopenharmony_ci * pointed to by the cursor.
61162306a36Sopenharmony_ci */
61262306a36Sopenharmony_cistruct rpc_xprt *xprt_iter_get_xprt(struct rpc_xprt_iter *xpi)
61362306a36Sopenharmony_ci{
61462306a36Sopenharmony_ci	struct rpc_xprt *xprt;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	rcu_read_lock();
61762306a36Sopenharmony_ci	xprt = xprt_iter_get_helper(xpi, xprt_iter_ops(xpi)->xpi_xprt);
61862306a36Sopenharmony_ci	rcu_read_unlock();
61962306a36Sopenharmony_ci	return xprt;
62062306a36Sopenharmony_ci}
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci/**
62362306a36Sopenharmony_ci * xprt_iter_get_next - Returns the next rpc_xprt following the cursor
62462306a36Sopenharmony_ci * @xpi: pointer to rpc_xprt_iter
62562306a36Sopenharmony_ci *
62662306a36Sopenharmony_ci * Returns a reference to the struct rpc_xprt that immediately follows the
62762306a36Sopenharmony_ci * entry pointed to by the cursor.
62862306a36Sopenharmony_ci */
62962306a36Sopenharmony_cistruct rpc_xprt *xprt_iter_get_next(struct rpc_xprt_iter *xpi)
63062306a36Sopenharmony_ci{
63162306a36Sopenharmony_ci	struct rpc_xprt *xprt;
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	rcu_read_lock();
63462306a36Sopenharmony_ci	xprt = xprt_iter_get_helper(xpi, xprt_iter_ops(xpi)->xpi_next);
63562306a36Sopenharmony_ci	rcu_read_unlock();
63662306a36Sopenharmony_ci	return xprt;
63762306a36Sopenharmony_ci}
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci/* Policy for always returning the first entry in the rpc_xprt_switch */
64062306a36Sopenharmony_cistatic
64162306a36Sopenharmony_ciconst struct rpc_xprt_iter_ops rpc_xprt_iter_singular = {
64262306a36Sopenharmony_ci	.xpi_rewind = xprt_iter_no_rewind,
64362306a36Sopenharmony_ci	.xpi_xprt = xprt_iter_first_entry,
64462306a36Sopenharmony_ci	.xpi_next = xprt_iter_first_entry,
64562306a36Sopenharmony_ci};
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci/* Policy for round-robin iteration of entries in the rpc_xprt_switch */
64862306a36Sopenharmony_cistatic
64962306a36Sopenharmony_ciconst struct rpc_xprt_iter_ops rpc_xprt_iter_roundrobin = {
65062306a36Sopenharmony_ci	.xpi_rewind = xprt_iter_default_rewind,
65162306a36Sopenharmony_ci	.xpi_xprt = xprt_iter_current_entry,
65262306a36Sopenharmony_ci	.xpi_next = xprt_iter_next_entry_roundrobin,
65362306a36Sopenharmony_ci};
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci/* Policy for once-through iteration of entries in the rpc_xprt_switch */
65662306a36Sopenharmony_cistatic
65762306a36Sopenharmony_ciconst struct rpc_xprt_iter_ops rpc_xprt_iter_listall = {
65862306a36Sopenharmony_ci	.xpi_rewind = xprt_iter_default_rewind,
65962306a36Sopenharmony_ci	.xpi_xprt = xprt_iter_current_entry,
66062306a36Sopenharmony_ci	.xpi_next = xprt_iter_next_entry_all,
66162306a36Sopenharmony_ci};
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_cistatic
66462306a36Sopenharmony_ciconst struct rpc_xprt_iter_ops rpc_xprt_iter_listoffline = {
66562306a36Sopenharmony_ci	.xpi_rewind = xprt_iter_default_rewind,
66662306a36Sopenharmony_ci	.xpi_xprt = xprt_iter_current_entry_offline,
66762306a36Sopenharmony_ci	.xpi_next = xprt_iter_next_entry_offline,
66862306a36Sopenharmony_ci};
669