18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Multipath support for RPC
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2015, 2016, Primary Data, Inc. All rights reserved.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Trond Myklebust <trond.myklebust@primarydata.com>
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci#include <linux/types.h>
118c2ecf20Sopenharmony_ci#include <linux/kref.h>
128c2ecf20Sopenharmony_ci#include <linux/list.h>
138c2ecf20Sopenharmony_ci#include <linux/rcupdate.h>
148c2ecf20Sopenharmony_ci#include <linux/rculist.h>
158c2ecf20Sopenharmony_ci#include <linux/slab.h>
168c2ecf20Sopenharmony_ci#include <asm/cmpxchg.h>
178c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
188c2ecf20Sopenharmony_ci#include <linux/sunrpc/xprt.h>
198c2ecf20Sopenharmony_ci#include <linux/sunrpc/addr.h>
208c2ecf20Sopenharmony_ci#include <linux/sunrpc/xprtmultipath.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_citypedef struct rpc_xprt *(*xprt_switch_find_xprt_t)(struct rpc_xprt_switch *xps,
238c2ecf20Sopenharmony_ci		const struct rpc_xprt *cur);
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistatic const struct rpc_xprt_iter_ops rpc_xprt_iter_singular;
268c2ecf20Sopenharmony_cistatic const struct rpc_xprt_iter_ops rpc_xprt_iter_roundrobin;
278c2ecf20Sopenharmony_cistatic const struct rpc_xprt_iter_ops rpc_xprt_iter_listall;
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistatic void xprt_switch_add_xprt_locked(struct rpc_xprt_switch *xps,
308c2ecf20Sopenharmony_ci		struct rpc_xprt *xprt)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	if (unlikely(xprt_get(xprt) == NULL))
338c2ecf20Sopenharmony_ci		return;
348c2ecf20Sopenharmony_ci	list_add_tail_rcu(&xprt->xprt_switch, &xps->xps_xprt_list);
358c2ecf20Sopenharmony_ci	smp_wmb();
368c2ecf20Sopenharmony_ci	if (xps->xps_nxprts == 0)
378c2ecf20Sopenharmony_ci		xps->xps_net = xprt->xprt_net;
388c2ecf20Sopenharmony_ci	xps->xps_nxprts++;
398c2ecf20Sopenharmony_ci	xps->xps_nactive++;
408c2ecf20Sopenharmony_ci}
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci/**
438c2ecf20Sopenharmony_ci * rpc_xprt_switch_add_xprt - Add a new rpc_xprt to an rpc_xprt_switch
448c2ecf20Sopenharmony_ci * @xps: pointer to struct rpc_xprt_switch
458c2ecf20Sopenharmony_ci * @xprt: pointer to struct rpc_xprt
468c2ecf20Sopenharmony_ci *
478c2ecf20Sopenharmony_ci * Adds xprt to the end of the list of struct rpc_xprt in xps.
488c2ecf20Sopenharmony_ci */
498c2ecf20Sopenharmony_civoid rpc_xprt_switch_add_xprt(struct rpc_xprt_switch *xps,
508c2ecf20Sopenharmony_ci		struct rpc_xprt *xprt)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	if (xprt == NULL)
538c2ecf20Sopenharmony_ci		return;
548c2ecf20Sopenharmony_ci	spin_lock(&xps->xps_lock);
558c2ecf20Sopenharmony_ci	if (xps->xps_net == xprt->xprt_net || xps->xps_net == NULL)
568c2ecf20Sopenharmony_ci		xprt_switch_add_xprt_locked(xps, xprt);
578c2ecf20Sopenharmony_ci	spin_unlock(&xps->xps_lock);
588c2ecf20Sopenharmony_ci}
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_cistatic void xprt_switch_remove_xprt_locked(struct rpc_xprt_switch *xps,
618c2ecf20Sopenharmony_ci		struct rpc_xprt *xprt)
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	if (unlikely(xprt == NULL))
648c2ecf20Sopenharmony_ci		return;
658c2ecf20Sopenharmony_ci	xps->xps_nactive--;
668c2ecf20Sopenharmony_ci	xps->xps_nxprts--;
678c2ecf20Sopenharmony_ci	if (xps->xps_nxprts == 0)
688c2ecf20Sopenharmony_ci		xps->xps_net = NULL;
698c2ecf20Sopenharmony_ci	smp_wmb();
708c2ecf20Sopenharmony_ci	list_del_rcu(&xprt->xprt_switch);
718c2ecf20Sopenharmony_ci}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci/**
748c2ecf20Sopenharmony_ci * rpc_xprt_switch_remove_xprt - Removes an rpc_xprt from a rpc_xprt_switch
758c2ecf20Sopenharmony_ci * @xps: pointer to struct rpc_xprt_switch
768c2ecf20Sopenharmony_ci * @xprt: pointer to struct rpc_xprt
778c2ecf20Sopenharmony_ci *
788c2ecf20Sopenharmony_ci * Removes xprt from the list of struct rpc_xprt in xps.
798c2ecf20Sopenharmony_ci */
808c2ecf20Sopenharmony_civoid rpc_xprt_switch_remove_xprt(struct rpc_xprt_switch *xps,
818c2ecf20Sopenharmony_ci		struct rpc_xprt *xprt)
828c2ecf20Sopenharmony_ci{
838c2ecf20Sopenharmony_ci	spin_lock(&xps->xps_lock);
848c2ecf20Sopenharmony_ci	xprt_switch_remove_xprt_locked(xps, xprt);
858c2ecf20Sopenharmony_ci	spin_unlock(&xps->xps_lock);
868c2ecf20Sopenharmony_ci	xprt_put(xprt);
878c2ecf20Sopenharmony_ci}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci/**
908c2ecf20Sopenharmony_ci * xprt_switch_alloc - Allocate a new struct rpc_xprt_switch
918c2ecf20Sopenharmony_ci * @xprt: pointer to struct rpc_xprt
928c2ecf20Sopenharmony_ci * @gfp_flags: allocation flags
938c2ecf20Sopenharmony_ci *
948c2ecf20Sopenharmony_ci * On success, returns an initialised struct rpc_xprt_switch, containing
958c2ecf20Sopenharmony_ci * the entry xprt. Returns NULL on failure.
968c2ecf20Sopenharmony_ci */
978c2ecf20Sopenharmony_cistruct rpc_xprt_switch *xprt_switch_alloc(struct rpc_xprt *xprt,
988c2ecf20Sopenharmony_ci		gfp_t gfp_flags)
998c2ecf20Sopenharmony_ci{
1008c2ecf20Sopenharmony_ci	struct rpc_xprt_switch *xps;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	xps = kmalloc(sizeof(*xps), gfp_flags);
1038c2ecf20Sopenharmony_ci	if (xps != NULL) {
1048c2ecf20Sopenharmony_ci		spin_lock_init(&xps->xps_lock);
1058c2ecf20Sopenharmony_ci		kref_init(&xps->xps_kref);
1068c2ecf20Sopenharmony_ci		xps->xps_nxprts = xps->xps_nactive = 0;
1078c2ecf20Sopenharmony_ci		atomic_long_set(&xps->xps_queuelen, 0);
1088c2ecf20Sopenharmony_ci		xps->xps_net = NULL;
1098c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&xps->xps_xprt_list);
1108c2ecf20Sopenharmony_ci		xps->xps_iter_ops = &rpc_xprt_iter_singular;
1118c2ecf20Sopenharmony_ci		xprt_switch_add_xprt_locked(xps, xprt);
1128c2ecf20Sopenharmony_ci	}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	return xps;
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_cistatic void xprt_switch_free_entries(struct rpc_xprt_switch *xps)
1188c2ecf20Sopenharmony_ci{
1198c2ecf20Sopenharmony_ci	spin_lock(&xps->xps_lock);
1208c2ecf20Sopenharmony_ci	while (!list_empty(&xps->xps_xprt_list)) {
1218c2ecf20Sopenharmony_ci		struct rpc_xprt *xprt;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci		xprt = list_first_entry(&xps->xps_xprt_list,
1248c2ecf20Sopenharmony_ci				struct rpc_xprt, xprt_switch);
1258c2ecf20Sopenharmony_ci		xprt_switch_remove_xprt_locked(xps, xprt);
1268c2ecf20Sopenharmony_ci		spin_unlock(&xps->xps_lock);
1278c2ecf20Sopenharmony_ci		xprt_put(xprt);
1288c2ecf20Sopenharmony_ci		spin_lock(&xps->xps_lock);
1298c2ecf20Sopenharmony_ci	}
1308c2ecf20Sopenharmony_ci	spin_unlock(&xps->xps_lock);
1318c2ecf20Sopenharmony_ci}
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_cistatic void xprt_switch_free(struct kref *kref)
1348c2ecf20Sopenharmony_ci{
1358c2ecf20Sopenharmony_ci	struct rpc_xprt_switch *xps = container_of(kref,
1368c2ecf20Sopenharmony_ci			struct rpc_xprt_switch, xps_kref);
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	xprt_switch_free_entries(xps);
1398c2ecf20Sopenharmony_ci	kfree_rcu(xps, xps_rcu);
1408c2ecf20Sopenharmony_ci}
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci/**
1438c2ecf20Sopenharmony_ci * xprt_switch_get - Return a reference to a rpc_xprt_switch
1448c2ecf20Sopenharmony_ci * @xps: pointer to struct rpc_xprt_switch
1458c2ecf20Sopenharmony_ci *
1468c2ecf20Sopenharmony_ci * Returns a reference to xps unless the refcount is already zero.
1478c2ecf20Sopenharmony_ci */
1488c2ecf20Sopenharmony_cistruct rpc_xprt_switch *xprt_switch_get(struct rpc_xprt_switch *xps)
1498c2ecf20Sopenharmony_ci{
1508c2ecf20Sopenharmony_ci	if (xps != NULL && kref_get_unless_zero(&xps->xps_kref))
1518c2ecf20Sopenharmony_ci		return xps;
1528c2ecf20Sopenharmony_ci	return NULL;
1538c2ecf20Sopenharmony_ci}
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci/**
1568c2ecf20Sopenharmony_ci * xprt_switch_put - Release a reference to a rpc_xprt_switch
1578c2ecf20Sopenharmony_ci * @xps: pointer to struct rpc_xprt_switch
1588c2ecf20Sopenharmony_ci *
1598c2ecf20Sopenharmony_ci * Release the reference to xps, and free it once the refcount is zero.
1608c2ecf20Sopenharmony_ci */
1618c2ecf20Sopenharmony_civoid xprt_switch_put(struct rpc_xprt_switch *xps)
1628c2ecf20Sopenharmony_ci{
1638c2ecf20Sopenharmony_ci	if (xps != NULL)
1648c2ecf20Sopenharmony_ci		kref_put(&xps->xps_kref, xprt_switch_free);
1658c2ecf20Sopenharmony_ci}
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci/**
1688c2ecf20Sopenharmony_ci * rpc_xprt_switch_set_roundrobin - Set a round-robin policy on rpc_xprt_switch
1698c2ecf20Sopenharmony_ci * @xps: pointer to struct rpc_xprt_switch
1708c2ecf20Sopenharmony_ci *
1718c2ecf20Sopenharmony_ci * Sets a round-robin default policy for iterators acting on xps.
1728c2ecf20Sopenharmony_ci */
1738c2ecf20Sopenharmony_civoid rpc_xprt_switch_set_roundrobin(struct rpc_xprt_switch *xps)
1748c2ecf20Sopenharmony_ci{
1758c2ecf20Sopenharmony_ci	if (READ_ONCE(xps->xps_iter_ops) != &rpc_xprt_iter_roundrobin)
1768c2ecf20Sopenharmony_ci		WRITE_ONCE(xps->xps_iter_ops, &rpc_xprt_iter_roundrobin);
1778c2ecf20Sopenharmony_ci}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_cistatic
1808c2ecf20Sopenharmony_ciconst struct rpc_xprt_iter_ops *xprt_iter_ops(const struct rpc_xprt_iter *xpi)
1818c2ecf20Sopenharmony_ci{
1828c2ecf20Sopenharmony_ci	if (xpi->xpi_ops != NULL)
1838c2ecf20Sopenharmony_ci		return xpi->xpi_ops;
1848c2ecf20Sopenharmony_ci	return rcu_dereference(xpi->xpi_xpswitch)->xps_iter_ops;
1858c2ecf20Sopenharmony_ci}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_cistatic
1888c2ecf20Sopenharmony_civoid xprt_iter_no_rewind(struct rpc_xprt_iter *xpi)
1898c2ecf20Sopenharmony_ci{
1908c2ecf20Sopenharmony_ci}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_cistatic
1938c2ecf20Sopenharmony_civoid xprt_iter_default_rewind(struct rpc_xprt_iter *xpi)
1948c2ecf20Sopenharmony_ci{
1958c2ecf20Sopenharmony_ci	WRITE_ONCE(xpi->xpi_cursor, NULL);
1968c2ecf20Sopenharmony_ci}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_cistatic
1998c2ecf20Sopenharmony_cibool xprt_is_active(const struct rpc_xprt *xprt)
2008c2ecf20Sopenharmony_ci{
2018c2ecf20Sopenharmony_ci	return kref_read(&xprt->kref) != 0;
2028c2ecf20Sopenharmony_ci}
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_cistatic
2058c2ecf20Sopenharmony_cistruct rpc_xprt *xprt_switch_find_first_entry(struct list_head *head)
2068c2ecf20Sopenharmony_ci{
2078c2ecf20Sopenharmony_ci	struct rpc_xprt *pos;
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(pos, head, xprt_switch) {
2108c2ecf20Sopenharmony_ci		if (xprt_is_active(pos))
2118c2ecf20Sopenharmony_ci			return pos;
2128c2ecf20Sopenharmony_ci	}
2138c2ecf20Sopenharmony_ci	return NULL;
2148c2ecf20Sopenharmony_ci}
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_cistatic
2178c2ecf20Sopenharmony_cistruct rpc_xprt *xprt_iter_first_entry(struct rpc_xprt_iter *xpi)
2188c2ecf20Sopenharmony_ci{
2198c2ecf20Sopenharmony_ci	struct rpc_xprt_switch *xps = rcu_dereference(xpi->xpi_xpswitch);
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	if (xps == NULL)
2228c2ecf20Sopenharmony_ci		return NULL;
2238c2ecf20Sopenharmony_ci	return xprt_switch_find_first_entry(&xps->xps_xprt_list);
2248c2ecf20Sopenharmony_ci}
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_cistatic
2278c2ecf20Sopenharmony_cistruct rpc_xprt *xprt_switch_find_current_entry(struct list_head *head,
2288c2ecf20Sopenharmony_ci		const struct rpc_xprt *cur)
2298c2ecf20Sopenharmony_ci{
2308c2ecf20Sopenharmony_ci	struct rpc_xprt *pos;
2318c2ecf20Sopenharmony_ci	bool found = false;
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(pos, head, xprt_switch) {
2348c2ecf20Sopenharmony_ci		if (cur == pos)
2358c2ecf20Sopenharmony_ci			found = true;
2368c2ecf20Sopenharmony_ci		if (found && xprt_is_active(pos))
2378c2ecf20Sopenharmony_ci			return pos;
2388c2ecf20Sopenharmony_ci	}
2398c2ecf20Sopenharmony_ci	return NULL;
2408c2ecf20Sopenharmony_ci}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_cistatic
2438c2ecf20Sopenharmony_cistruct rpc_xprt *xprt_iter_current_entry(struct rpc_xprt_iter *xpi)
2448c2ecf20Sopenharmony_ci{
2458c2ecf20Sopenharmony_ci	struct rpc_xprt_switch *xps = rcu_dereference(xpi->xpi_xpswitch);
2468c2ecf20Sopenharmony_ci	struct list_head *head;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	if (xps == NULL)
2498c2ecf20Sopenharmony_ci		return NULL;
2508c2ecf20Sopenharmony_ci	head = &xps->xps_xprt_list;
2518c2ecf20Sopenharmony_ci	if (xpi->xpi_cursor == NULL || xps->xps_nxprts < 2)
2528c2ecf20Sopenharmony_ci		return xprt_switch_find_first_entry(head);
2538c2ecf20Sopenharmony_ci	return xprt_switch_find_current_entry(head, xpi->xpi_cursor);
2548c2ecf20Sopenharmony_ci}
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_cistatic
2578c2ecf20Sopenharmony_cibool __rpc_xprt_switch_has_addr(struct rpc_xprt_switch *xps,
2588c2ecf20Sopenharmony_ci				const struct sockaddr *sap)
2598c2ecf20Sopenharmony_ci{
2608c2ecf20Sopenharmony_ci	struct list_head *head;
2618c2ecf20Sopenharmony_ci	struct rpc_xprt *pos;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	if (xps == NULL || sap == NULL)
2648c2ecf20Sopenharmony_ci		return false;
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	head = &xps->xps_xprt_list;
2678c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(pos, head, xprt_switch) {
2688c2ecf20Sopenharmony_ci		if (rpc_cmp_addr_port(sap, (struct sockaddr *)&pos->addr)) {
2698c2ecf20Sopenharmony_ci			pr_info("RPC:   addr %s already in xprt switch\n",
2708c2ecf20Sopenharmony_ci				pos->address_strings[RPC_DISPLAY_ADDR]);
2718c2ecf20Sopenharmony_ci			return true;
2728c2ecf20Sopenharmony_ci		}
2738c2ecf20Sopenharmony_ci	}
2748c2ecf20Sopenharmony_ci	return false;
2758c2ecf20Sopenharmony_ci}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_cibool rpc_xprt_switch_has_addr(struct rpc_xprt_switch *xps,
2788c2ecf20Sopenharmony_ci			      const struct sockaddr *sap)
2798c2ecf20Sopenharmony_ci{
2808c2ecf20Sopenharmony_ci	bool res;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	rcu_read_lock();
2838c2ecf20Sopenharmony_ci	res = __rpc_xprt_switch_has_addr(xps, sap);
2848c2ecf20Sopenharmony_ci	rcu_read_unlock();
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	return res;
2878c2ecf20Sopenharmony_ci}
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_cistatic
2908c2ecf20Sopenharmony_cistruct rpc_xprt *xprt_switch_find_next_entry(struct list_head *head,
2918c2ecf20Sopenharmony_ci		const struct rpc_xprt *cur)
2928c2ecf20Sopenharmony_ci{
2938c2ecf20Sopenharmony_ci	struct rpc_xprt *pos, *prev = NULL;
2948c2ecf20Sopenharmony_ci	bool found = false;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(pos, head, xprt_switch) {
2978c2ecf20Sopenharmony_ci		if (cur == prev)
2988c2ecf20Sopenharmony_ci			found = true;
2998c2ecf20Sopenharmony_ci		if (found && xprt_is_active(pos))
3008c2ecf20Sopenharmony_ci			return pos;
3018c2ecf20Sopenharmony_ci		prev = pos;
3028c2ecf20Sopenharmony_ci	}
3038c2ecf20Sopenharmony_ci	return NULL;
3048c2ecf20Sopenharmony_ci}
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_cistatic
3078c2ecf20Sopenharmony_cistruct rpc_xprt *xprt_switch_set_next_cursor(struct rpc_xprt_switch *xps,
3088c2ecf20Sopenharmony_ci		struct rpc_xprt **cursor,
3098c2ecf20Sopenharmony_ci		xprt_switch_find_xprt_t find_next)
3108c2ecf20Sopenharmony_ci{
3118c2ecf20Sopenharmony_ci	struct rpc_xprt *pos, *old;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	old = smp_load_acquire(cursor);
3148c2ecf20Sopenharmony_ci	pos = find_next(xps, old);
3158c2ecf20Sopenharmony_ci	smp_store_release(cursor, pos);
3168c2ecf20Sopenharmony_ci	return pos;
3178c2ecf20Sopenharmony_ci}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_cistatic
3208c2ecf20Sopenharmony_cistruct rpc_xprt *xprt_iter_next_entry_multiple(struct rpc_xprt_iter *xpi,
3218c2ecf20Sopenharmony_ci		xprt_switch_find_xprt_t find_next)
3228c2ecf20Sopenharmony_ci{
3238c2ecf20Sopenharmony_ci	struct rpc_xprt_switch *xps = rcu_dereference(xpi->xpi_xpswitch);
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	if (xps == NULL)
3268c2ecf20Sopenharmony_ci		return NULL;
3278c2ecf20Sopenharmony_ci	return xprt_switch_set_next_cursor(xps, &xpi->xpi_cursor, find_next);
3288c2ecf20Sopenharmony_ci}
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_cistatic
3318c2ecf20Sopenharmony_cistruct rpc_xprt *__xprt_switch_find_next_entry_roundrobin(struct list_head *head,
3328c2ecf20Sopenharmony_ci		const struct rpc_xprt *cur)
3338c2ecf20Sopenharmony_ci{
3348c2ecf20Sopenharmony_ci	struct rpc_xprt *ret;
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	ret = xprt_switch_find_next_entry(head, cur);
3378c2ecf20Sopenharmony_ci	if (ret != NULL)
3388c2ecf20Sopenharmony_ci		return ret;
3398c2ecf20Sopenharmony_ci	return xprt_switch_find_first_entry(head);
3408c2ecf20Sopenharmony_ci}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_cistatic
3438c2ecf20Sopenharmony_cistruct rpc_xprt *xprt_switch_find_next_entry_roundrobin(struct rpc_xprt_switch *xps,
3448c2ecf20Sopenharmony_ci		const struct rpc_xprt *cur)
3458c2ecf20Sopenharmony_ci{
3468c2ecf20Sopenharmony_ci	struct list_head *head = &xps->xps_xprt_list;
3478c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt;
3488c2ecf20Sopenharmony_ci	unsigned int nactive;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	for (;;) {
3518c2ecf20Sopenharmony_ci		unsigned long xprt_queuelen, xps_queuelen;
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci		xprt = __xprt_switch_find_next_entry_roundrobin(head, cur);
3548c2ecf20Sopenharmony_ci		if (!xprt)
3558c2ecf20Sopenharmony_ci			break;
3568c2ecf20Sopenharmony_ci		xprt_queuelen = atomic_long_read(&xprt->queuelen);
3578c2ecf20Sopenharmony_ci		xps_queuelen = atomic_long_read(&xps->xps_queuelen);
3588c2ecf20Sopenharmony_ci		nactive = READ_ONCE(xps->xps_nactive);
3598c2ecf20Sopenharmony_ci		/* Exit loop if xprt_queuelen <= average queue length */
3608c2ecf20Sopenharmony_ci		if (xprt_queuelen * nactive <= xps_queuelen)
3618c2ecf20Sopenharmony_ci			break;
3628c2ecf20Sopenharmony_ci		cur = xprt;
3638c2ecf20Sopenharmony_ci	}
3648c2ecf20Sopenharmony_ci	return xprt;
3658c2ecf20Sopenharmony_ci}
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_cistatic
3688c2ecf20Sopenharmony_cistruct rpc_xprt *xprt_iter_next_entry_roundrobin(struct rpc_xprt_iter *xpi)
3698c2ecf20Sopenharmony_ci{
3708c2ecf20Sopenharmony_ci	return xprt_iter_next_entry_multiple(xpi,
3718c2ecf20Sopenharmony_ci			xprt_switch_find_next_entry_roundrobin);
3728c2ecf20Sopenharmony_ci}
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_cistatic
3758c2ecf20Sopenharmony_cistruct rpc_xprt *xprt_switch_find_next_entry_all(struct rpc_xprt_switch *xps,
3768c2ecf20Sopenharmony_ci		const struct rpc_xprt *cur)
3778c2ecf20Sopenharmony_ci{
3788c2ecf20Sopenharmony_ci	return xprt_switch_find_next_entry(&xps->xps_xprt_list, cur);
3798c2ecf20Sopenharmony_ci}
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_cistatic
3828c2ecf20Sopenharmony_cistruct rpc_xprt *xprt_iter_next_entry_all(struct rpc_xprt_iter *xpi)
3838c2ecf20Sopenharmony_ci{
3848c2ecf20Sopenharmony_ci	return xprt_iter_next_entry_multiple(xpi,
3858c2ecf20Sopenharmony_ci			xprt_switch_find_next_entry_all);
3868c2ecf20Sopenharmony_ci}
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci/*
3898c2ecf20Sopenharmony_ci * xprt_iter_rewind - Resets the xprt iterator
3908c2ecf20Sopenharmony_ci * @xpi: pointer to rpc_xprt_iter
3918c2ecf20Sopenharmony_ci *
3928c2ecf20Sopenharmony_ci * Resets xpi to ensure that it points to the first entry in the list
3938c2ecf20Sopenharmony_ci * of transports.
3948c2ecf20Sopenharmony_ci */
3958c2ecf20Sopenharmony_cistatic
3968c2ecf20Sopenharmony_civoid xprt_iter_rewind(struct rpc_xprt_iter *xpi)
3978c2ecf20Sopenharmony_ci{
3988c2ecf20Sopenharmony_ci	rcu_read_lock();
3998c2ecf20Sopenharmony_ci	xprt_iter_ops(xpi)->xpi_rewind(xpi);
4008c2ecf20Sopenharmony_ci	rcu_read_unlock();
4018c2ecf20Sopenharmony_ci}
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_cistatic void __xprt_iter_init(struct rpc_xprt_iter *xpi,
4048c2ecf20Sopenharmony_ci		struct rpc_xprt_switch *xps,
4058c2ecf20Sopenharmony_ci		const struct rpc_xprt_iter_ops *ops)
4068c2ecf20Sopenharmony_ci{
4078c2ecf20Sopenharmony_ci	rcu_assign_pointer(xpi->xpi_xpswitch, xprt_switch_get(xps));
4088c2ecf20Sopenharmony_ci	xpi->xpi_cursor = NULL;
4098c2ecf20Sopenharmony_ci	xpi->xpi_ops = ops;
4108c2ecf20Sopenharmony_ci}
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci/**
4138c2ecf20Sopenharmony_ci * xprt_iter_init - Initialise an xprt iterator
4148c2ecf20Sopenharmony_ci * @xpi: pointer to rpc_xprt_iter
4158c2ecf20Sopenharmony_ci * @xps: pointer to rpc_xprt_switch
4168c2ecf20Sopenharmony_ci *
4178c2ecf20Sopenharmony_ci * Initialises the iterator to use the default iterator ops
4188c2ecf20Sopenharmony_ci * as set in xps. This function is mainly intended for internal
4198c2ecf20Sopenharmony_ci * use in the rpc_client.
4208c2ecf20Sopenharmony_ci */
4218c2ecf20Sopenharmony_civoid xprt_iter_init(struct rpc_xprt_iter *xpi,
4228c2ecf20Sopenharmony_ci		struct rpc_xprt_switch *xps)
4238c2ecf20Sopenharmony_ci{
4248c2ecf20Sopenharmony_ci	__xprt_iter_init(xpi, xps, NULL);
4258c2ecf20Sopenharmony_ci}
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci/**
4288c2ecf20Sopenharmony_ci * xprt_iter_init_listall - Initialise an xprt iterator
4298c2ecf20Sopenharmony_ci * @xpi: pointer to rpc_xprt_iter
4308c2ecf20Sopenharmony_ci * @xps: pointer to rpc_xprt_switch
4318c2ecf20Sopenharmony_ci *
4328c2ecf20Sopenharmony_ci * Initialises the iterator to iterate once through the entire list
4338c2ecf20Sopenharmony_ci * of entries in xps.
4348c2ecf20Sopenharmony_ci */
4358c2ecf20Sopenharmony_civoid xprt_iter_init_listall(struct rpc_xprt_iter *xpi,
4368c2ecf20Sopenharmony_ci		struct rpc_xprt_switch *xps)
4378c2ecf20Sopenharmony_ci{
4388c2ecf20Sopenharmony_ci	__xprt_iter_init(xpi, xps, &rpc_xprt_iter_listall);
4398c2ecf20Sopenharmony_ci}
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci/**
4428c2ecf20Sopenharmony_ci * xprt_iter_xchg_switch - Atomically swap out the rpc_xprt_switch
4438c2ecf20Sopenharmony_ci * @xpi: pointer to rpc_xprt_iter
4448c2ecf20Sopenharmony_ci * @newswitch: pointer to a new rpc_xprt_switch or NULL
4458c2ecf20Sopenharmony_ci *
4468c2ecf20Sopenharmony_ci * Swaps out the existing xpi->xpi_xpswitch with a new value.
4478c2ecf20Sopenharmony_ci */
4488c2ecf20Sopenharmony_cistruct rpc_xprt_switch *xprt_iter_xchg_switch(struct rpc_xprt_iter *xpi,
4498c2ecf20Sopenharmony_ci		struct rpc_xprt_switch *newswitch)
4508c2ecf20Sopenharmony_ci{
4518c2ecf20Sopenharmony_ci	struct rpc_xprt_switch __rcu *oldswitch;
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	/* Atomically swap out the old xpswitch */
4548c2ecf20Sopenharmony_ci	oldswitch = xchg(&xpi->xpi_xpswitch, RCU_INITIALIZER(newswitch));
4558c2ecf20Sopenharmony_ci	if (newswitch != NULL)
4568c2ecf20Sopenharmony_ci		xprt_iter_rewind(xpi);
4578c2ecf20Sopenharmony_ci	return rcu_dereference_protected(oldswitch, true);
4588c2ecf20Sopenharmony_ci}
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci/**
4618c2ecf20Sopenharmony_ci * xprt_iter_destroy - Destroys the xprt iterator
4628c2ecf20Sopenharmony_ci * @xpi: pointer to rpc_xprt_iter
4638c2ecf20Sopenharmony_ci */
4648c2ecf20Sopenharmony_civoid xprt_iter_destroy(struct rpc_xprt_iter *xpi)
4658c2ecf20Sopenharmony_ci{
4668c2ecf20Sopenharmony_ci	xprt_switch_put(xprt_iter_xchg_switch(xpi, NULL));
4678c2ecf20Sopenharmony_ci}
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci/**
4708c2ecf20Sopenharmony_ci * xprt_iter_xprt - Returns the rpc_xprt pointed to by the cursor
4718c2ecf20Sopenharmony_ci * @xpi: pointer to rpc_xprt_iter
4728c2ecf20Sopenharmony_ci *
4738c2ecf20Sopenharmony_ci * Returns a pointer to the struct rpc_xprt that is currently
4748c2ecf20Sopenharmony_ci * pointed to by the cursor.
4758c2ecf20Sopenharmony_ci * Caller must be holding rcu_read_lock().
4768c2ecf20Sopenharmony_ci */
4778c2ecf20Sopenharmony_cistruct rpc_xprt *xprt_iter_xprt(struct rpc_xprt_iter *xpi)
4788c2ecf20Sopenharmony_ci{
4798c2ecf20Sopenharmony_ci	WARN_ON_ONCE(!rcu_read_lock_held());
4808c2ecf20Sopenharmony_ci	return xprt_iter_ops(xpi)->xpi_xprt(xpi);
4818c2ecf20Sopenharmony_ci}
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_cistatic
4848c2ecf20Sopenharmony_cistruct rpc_xprt *xprt_iter_get_helper(struct rpc_xprt_iter *xpi,
4858c2ecf20Sopenharmony_ci		struct rpc_xprt *(*fn)(struct rpc_xprt_iter *))
4868c2ecf20Sopenharmony_ci{
4878c2ecf20Sopenharmony_ci	struct rpc_xprt *ret;
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	do {
4908c2ecf20Sopenharmony_ci		ret = fn(xpi);
4918c2ecf20Sopenharmony_ci		if (ret == NULL)
4928c2ecf20Sopenharmony_ci			break;
4938c2ecf20Sopenharmony_ci		ret = xprt_get(ret);
4948c2ecf20Sopenharmony_ci	} while (ret == NULL);
4958c2ecf20Sopenharmony_ci	return ret;
4968c2ecf20Sopenharmony_ci}
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci/**
4998c2ecf20Sopenharmony_ci * xprt_iter_get_xprt - Returns the rpc_xprt pointed to by the cursor
5008c2ecf20Sopenharmony_ci * @xpi: pointer to rpc_xprt_iter
5018c2ecf20Sopenharmony_ci *
5028c2ecf20Sopenharmony_ci * Returns a reference to the struct rpc_xprt that is currently
5038c2ecf20Sopenharmony_ci * pointed to by the cursor.
5048c2ecf20Sopenharmony_ci */
5058c2ecf20Sopenharmony_cistruct rpc_xprt *xprt_iter_get_xprt(struct rpc_xprt_iter *xpi)
5068c2ecf20Sopenharmony_ci{
5078c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt;
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	rcu_read_lock();
5108c2ecf20Sopenharmony_ci	xprt = xprt_iter_get_helper(xpi, xprt_iter_ops(xpi)->xpi_xprt);
5118c2ecf20Sopenharmony_ci	rcu_read_unlock();
5128c2ecf20Sopenharmony_ci	return xprt;
5138c2ecf20Sopenharmony_ci}
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci/**
5168c2ecf20Sopenharmony_ci * xprt_iter_get_next - Returns the next rpc_xprt following the cursor
5178c2ecf20Sopenharmony_ci * @xpi: pointer to rpc_xprt_iter
5188c2ecf20Sopenharmony_ci *
5198c2ecf20Sopenharmony_ci * Returns a reference to the struct rpc_xprt that immediately follows the
5208c2ecf20Sopenharmony_ci * entry pointed to by the cursor.
5218c2ecf20Sopenharmony_ci */
5228c2ecf20Sopenharmony_cistruct rpc_xprt *xprt_iter_get_next(struct rpc_xprt_iter *xpi)
5238c2ecf20Sopenharmony_ci{
5248c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt;
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	rcu_read_lock();
5278c2ecf20Sopenharmony_ci	xprt = xprt_iter_get_helper(xpi, xprt_iter_ops(xpi)->xpi_next);
5288c2ecf20Sopenharmony_ci	rcu_read_unlock();
5298c2ecf20Sopenharmony_ci	return xprt;
5308c2ecf20Sopenharmony_ci}
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci/* Policy for always returning the first entry in the rpc_xprt_switch */
5338c2ecf20Sopenharmony_cistatic
5348c2ecf20Sopenharmony_ciconst struct rpc_xprt_iter_ops rpc_xprt_iter_singular = {
5358c2ecf20Sopenharmony_ci	.xpi_rewind = xprt_iter_no_rewind,
5368c2ecf20Sopenharmony_ci	.xpi_xprt = xprt_iter_first_entry,
5378c2ecf20Sopenharmony_ci	.xpi_next = xprt_iter_first_entry,
5388c2ecf20Sopenharmony_ci};
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci/* Policy for round-robin iteration of entries in the rpc_xprt_switch */
5418c2ecf20Sopenharmony_cistatic
5428c2ecf20Sopenharmony_ciconst struct rpc_xprt_iter_ops rpc_xprt_iter_roundrobin = {
5438c2ecf20Sopenharmony_ci	.xpi_rewind = xprt_iter_default_rewind,
5448c2ecf20Sopenharmony_ci	.xpi_xprt = xprt_iter_current_entry,
5458c2ecf20Sopenharmony_ci	.xpi_next = xprt_iter_next_entry_roundrobin,
5468c2ecf20Sopenharmony_ci};
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci/* Policy for once-through iteration of entries in the rpc_xprt_switch */
5498c2ecf20Sopenharmony_cistatic
5508c2ecf20Sopenharmony_ciconst struct rpc_xprt_iter_ops rpc_xprt_iter_listall = {
5518c2ecf20Sopenharmony_ci	.xpi_rewind = xprt_iter_default_rewind,
5528c2ecf20Sopenharmony_ci	.xpi_xprt = xprt_iter_current_entry,
5538c2ecf20Sopenharmony_ci	.xpi_next = xprt_iter_next_entry_all,
5548c2ecf20Sopenharmony_ci};
555