xprtmultipath.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Multipath support for RPC
  4. *
  5. * Copyright (c) 2015, 2016, Primary Data, Inc. All rights reserved.
  6. *
  7. * Trond Myklebust <[email protected]>
  8. *
  9. */
  10. #include <linux/atomic.h>
  11. #include <linux/types.h>
  12. #include <linux/kref.h>
  13. #include <linux/list.h>
  14. #include <linux/rcupdate.h>
  15. #include <linux/rculist.h>
  16. #include <linux/slab.h>
  17. #include <linux/spinlock.h>
  18. #include <linux/sunrpc/xprt.h>
  19. #include <linux/sunrpc/addr.h>
  20. #include <linux/sunrpc/xprtmultipath.h>
  21. #include "sysfs.h"
  22. typedef struct rpc_xprt *(*xprt_switch_find_xprt_t)(struct rpc_xprt_switch *xps,
  23. const struct rpc_xprt *cur);
  24. static const struct rpc_xprt_iter_ops rpc_xprt_iter_singular;
  25. static const struct rpc_xprt_iter_ops rpc_xprt_iter_roundrobin;
  26. static const struct rpc_xprt_iter_ops rpc_xprt_iter_listall;
  27. static const struct rpc_xprt_iter_ops rpc_xprt_iter_listoffline;
  28. static void xprt_switch_add_xprt_locked(struct rpc_xprt_switch *xps,
  29. struct rpc_xprt *xprt)
  30. {
  31. if (unlikely(xprt_get(xprt) == NULL))
  32. return;
  33. list_add_tail_rcu(&xprt->xprt_switch, &xps->xps_xprt_list);
  34. smp_wmb();
  35. if (xps->xps_nxprts == 0)
  36. xps->xps_net = xprt->xprt_net;
  37. xps->xps_nxprts++;
  38. xps->xps_nactive++;
  39. }
  40. /**
  41. * rpc_xprt_switch_add_xprt - Add a new rpc_xprt to an rpc_xprt_switch
  42. * @xps: pointer to struct rpc_xprt_switch
  43. * @xprt: pointer to struct rpc_xprt
  44. *
  45. * Adds xprt to the end of the list of struct rpc_xprt in xps.
  46. */
  47. void rpc_xprt_switch_add_xprt(struct rpc_xprt_switch *xps,
  48. struct rpc_xprt *xprt)
  49. {
  50. if (xprt == NULL)
  51. return;
  52. spin_lock(&xps->xps_lock);
  53. if (xps->xps_net == xprt->xprt_net || xps->xps_net == NULL)
  54. xprt_switch_add_xprt_locked(xps, xprt);
  55. spin_unlock(&xps->xps_lock);
  56. rpc_sysfs_xprt_setup(xps, xprt, GFP_KERNEL);
  57. }
  58. static void xprt_switch_remove_xprt_locked(struct rpc_xprt_switch *xps,
  59. struct rpc_xprt *xprt, bool offline)
  60. {
  61. if (unlikely(xprt == NULL))
  62. return;
  63. if (!test_bit(XPRT_OFFLINE, &xprt->state) && offline)
  64. xps->xps_nactive--;
  65. xps->xps_nxprts--;
  66. if (xps->xps_nxprts == 0)
  67. xps->xps_net = NULL;
  68. smp_wmb();
  69. list_del_rcu(&xprt->xprt_switch);
  70. }
  71. /**
  72. * rpc_xprt_switch_remove_xprt - Removes an rpc_xprt from a rpc_xprt_switch
  73. * @xps: pointer to struct rpc_xprt_switch
  74. * @xprt: pointer to struct rpc_xprt
  75. * @offline: indicates if the xprt that's being removed is in an offline state
  76. *
  77. * Removes xprt from the list of struct rpc_xprt in xps.
  78. */
  79. void rpc_xprt_switch_remove_xprt(struct rpc_xprt_switch *xps,
  80. struct rpc_xprt *xprt, bool offline)
  81. {
  82. spin_lock(&xps->xps_lock);
  83. xprt_switch_remove_xprt_locked(xps, xprt, offline);
  84. spin_unlock(&xps->xps_lock);
  85. xprt_put(xprt);
  86. }
  87. static DEFINE_IDA(rpc_xprtswitch_ids);
  88. void xprt_multipath_cleanup_ids(void)
  89. {
  90. ida_destroy(&rpc_xprtswitch_ids);
  91. }
  92. static int xprt_switch_alloc_id(struct rpc_xprt_switch *xps, gfp_t gfp_flags)
  93. {
  94. int id;
  95. id = ida_alloc(&rpc_xprtswitch_ids, gfp_flags);
  96. if (id < 0)
  97. return id;
  98. xps->xps_id = id;
  99. return 0;
  100. }
  101. static void xprt_switch_free_id(struct rpc_xprt_switch *xps)
  102. {
  103. ida_free(&rpc_xprtswitch_ids, xps->xps_id);
  104. }
  105. /**
  106. * xprt_switch_alloc - Allocate a new struct rpc_xprt_switch
  107. * @xprt: pointer to struct rpc_xprt
  108. * @gfp_flags: allocation flags
  109. *
  110. * On success, returns an initialised struct rpc_xprt_switch, containing
  111. * the entry xprt. Returns NULL on failure.
  112. */
  113. struct rpc_xprt_switch *xprt_switch_alloc(struct rpc_xprt *xprt,
  114. gfp_t gfp_flags)
  115. {
  116. struct rpc_xprt_switch *xps;
  117. xps = kmalloc(sizeof(*xps), gfp_flags);
  118. if (xps != NULL) {
  119. spin_lock_init(&xps->xps_lock);
  120. kref_init(&xps->xps_kref);
  121. xprt_switch_alloc_id(xps, gfp_flags);
  122. xps->xps_nxprts = xps->xps_nactive = 0;
  123. atomic_long_set(&xps->xps_queuelen, 0);
  124. xps->xps_net = NULL;
  125. INIT_LIST_HEAD(&xps->xps_xprt_list);
  126. xps->xps_iter_ops = &rpc_xprt_iter_singular;
  127. rpc_sysfs_xprt_switch_setup(xps, xprt, gfp_flags);
  128. xprt_switch_add_xprt_locked(xps, xprt);
  129. xps->xps_nunique_destaddr_xprts = 1;
  130. rpc_sysfs_xprt_setup(xps, xprt, gfp_flags);
  131. }
  132. return xps;
  133. }
  134. static void xprt_switch_free_entries(struct rpc_xprt_switch *xps)
  135. {
  136. spin_lock(&xps->xps_lock);
  137. while (!list_empty(&xps->xps_xprt_list)) {
  138. struct rpc_xprt *xprt;
  139. xprt = list_first_entry(&xps->xps_xprt_list,
  140. struct rpc_xprt, xprt_switch);
  141. xprt_switch_remove_xprt_locked(xps, xprt, true);
  142. spin_unlock(&xps->xps_lock);
  143. xprt_put(xprt);
  144. spin_lock(&xps->xps_lock);
  145. }
  146. spin_unlock(&xps->xps_lock);
  147. }
  148. static void xprt_switch_free(struct kref *kref)
  149. {
  150. struct rpc_xprt_switch *xps = container_of(kref,
  151. struct rpc_xprt_switch, xps_kref);
  152. xprt_switch_free_entries(xps);
  153. rpc_sysfs_xprt_switch_destroy(xps);
  154. xprt_switch_free_id(xps);
  155. kfree_rcu(xps, xps_rcu);
  156. }
  157. /**
  158. * xprt_switch_get - Return a reference to a rpc_xprt_switch
  159. * @xps: pointer to struct rpc_xprt_switch
  160. *
  161. * Returns a reference to xps unless the refcount is already zero.
  162. */
  163. struct rpc_xprt_switch *xprt_switch_get(struct rpc_xprt_switch *xps)
  164. {
  165. if (xps != NULL && kref_get_unless_zero(&xps->xps_kref))
  166. return xps;
  167. return NULL;
  168. }
  169. /**
  170. * xprt_switch_put - Release a reference to a rpc_xprt_switch
  171. * @xps: pointer to struct rpc_xprt_switch
  172. *
  173. * Release the reference to xps, and free it once the refcount is zero.
  174. */
  175. void xprt_switch_put(struct rpc_xprt_switch *xps)
  176. {
  177. if (xps != NULL)
  178. kref_put(&xps->xps_kref, xprt_switch_free);
  179. }
  180. /**
  181. * rpc_xprt_switch_set_roundrobin - Set a round-robin policy on rpc_xprt_switch
  182. * @xps: pointer to struct rpc_xprt_switch
  183. *
  184. * Sets a round-robin default policy for iterators acting on xps.
  185. */
  186. void rpc_xprt_switch_set_roundrobin(struct rpc_xprt_switch *xps)
  187. {
  188. if (READ_ONCE(xps->xps_iter_ops) != &rpc_xprt_iter_roundrobin)
  189. WRITE_ONCE(xps->xps_iter_ops, &rpc_xprt_iter_roundrobin);
  190. }
  191. static
  192. const struct rpc_xprt_iter_ops *xprt_iter_ops(const struct rpc_xprt_iter *xpi)
  193. {
  194. if (xpi->xpi_ops != NULL)
  195. return xpi->xpi_ops;
  196. return rcu_dereference(xpi->xpi_xpswitch)->xps_iter_ops;
  197. }
  198. static
  199. void xprt_iter_no_rewind(struct rpc_xprt_iter *xpi)
  200. {
  201. }
  202. static
  203. void xprt_iter_default_rewind(struct rpc_xprt_iter *xpi)
  204. {
  205. WRITE_ONCE(xpi->xpi_cursor, NULL);
  206. }
  207. static
  208. bool xprt_is_active(const struct rpc_xprt *xprt)
  209. {
  210. return (kref_read(&xprt->kref) != 0 &&
  211. !test_bit(XPRT_OFFLINE, &xprt->state));
  212. }
  213. static
  214. struct rpc_xprt *xprt_switch_find_first_entry(struct list_head *head)
  215. {
  216. struct rpc_xprt *pos;
  217. list_for_each_entry_rcu(pos, head, xprt_switch) {
  218. if (xprt_is_active(pos))
  219. return pos;
  220. }
  221. return NULL;
  222. }
  223. static
  224. struct rpc_xprt *xprt_switch_find_first_entry_offline(struct list_head *head)
  225. {
  226. struct rpc_xprt *pos;
  227. list_for_each_entry_rcu(pos, head, xprt_switch) {
  228. if (!xprt_is_active(pos))
  229. return pos;
  230. }
  231. return NULL;
  232. }
  233. static
  234. struct rpc_xprt *xprt_iter_first_entry(struct rpc_xprt_iter *xpi)
  235. {
  236. struct rpc_xprt_switch *xps = rcu_dereference(xpi->xpi_xpswitch);
  237. if (xps == NULL)
  238. return NULL;
  239. return xprt_switch_find_first_entry(&xps->xps_xprt_list);
  240. }
  241. static
  242. struct rpc_xprt *_xprt_switch_find_current_entry(struct list_head *head,
  243. const struct rpc_xprt *cur,
  244. bool find_active)
  245. {
  246. struct rpc_xprt *pos;
  247. bool found = false;
  248. list_for_each_entry_rcu(pos, head, xprt_switch) {
  249. if (cur == pos)
  250. found = true;
  251. if (found && ((find_active && xprt_is_active(pos)) ||
  252. (!find_active && xprt_is_active(pos))))
  253. return pos;
  254. }
  255. return NULL;
  256. }
  257. static
  258. struct rpc_xprt *xprt_switch_find_current_entry(struct list_head *head,
  259. const struct rpc_xprt *cur)
  260. {
  261. return _xprt_switch_find_current_entry(head, cur, true);
  262. }
  263. static
  264. struct rpc_xprt * _xprt_iter_current_entry(struct rpc_xprt_iter *xpi,
  265. struct rpc_xprt *first_entry(struct list_head *head),
  266. struct rpc_xprt *current_entry(struct list_head *head,
  267. const struct rpc_xprt *cur))
  268. {
  269. struct rpc_xprt_switch *xps = rcu_dereference(xpi->xpi_xpswitch);
  270. struct list_head *head;
  271. if (xps == NULL)
  272. return NULL;
  273. head = &xps->xps_xprt_list;
  274. if (xpi->xpi_cursor == NULL || xps->xps_nxprts < 2)
  275. return first_entry(head);
  276. return current_entry(head, xpi->xpi_cursor);
  277. }
  278. static
  279. struct rpc_xprt *xprt_iter_current_entry(struct rpc_xprt_iter *xpi)
  280. {
  281. return _xprt_iter_current_entry(xpi, xprt_switch_find_first_entry,
  282. xprt_switch_find_current_entry);
  283. }
  284. static
  285. struct rpc_xprt *xprt_switch_find_current_entry_offline(struct list_head *head,
  286. const struct rpc_xprt *cur)
  287. {
  288. return _xprt_switch_find_current_entry(head, cur, false);
  289. }
  290. static
  291. struct rpc_xprt *xprt_iter_current_entry_offline(struct rpc_xprt_iter *xpi)
  292. {
  293. return _xprt_iter_current_entry(xpi,
  294. xprt_switch_find_first_entry_offline,
  295. xprt_switch_find_current_entry_offline);
  296. }
  297. bool rpc_xprt_switch_has_addr(struct rpc_xprt_switch *xps,
  298. const struct sockaddr *sap)
  299. {
  300. struct list_head *head;
  301. struct rpc_xprt *pos;
  302. if (xps == NULL || sap == NULL)
  303. return false;
  304. head = &xps->xps_xprt_list;
  305. list_for_each_entry_rcu(pos, head, xprt_switch) {
  306. if (rpc_cmp_addr_port(sap, (struct sockaddr *)&pos->addr)) {
  307. pr_info("RPC: addr %s already in xprt switch\n",
  308. pos->address_strings[RPC_DISPLAY_ADDR]);
  309. return true;
  310. }
  311. }
  312. return false;
  313. }
  314. static
  315. struct rpc_xprt *xprt_switch_find_next_entry(struct list_head *head,
  316. const struct rpc_xprt *cur, bool check_active)
  317. {
  318. struct rpc_xprt *pos, *prev = NULL;
  319. bool found = false;
  320. list_for_each_entry_rcu(pos, head, xprt_switch) {
  321. if (cur == prev)
  322. found = true;
  323. /* for request to return active transports return only
  324. * active, for request to return offline transports
  325. * return only offline
  326. */
  327. if (found && ((check_active && xprt_is_active(pos)) ||
  328. (!check_active && !xprt_is_active(pos))))
  329. return pos;
  330. prev = pos;
  331. }
  332. return NULL;
  333. }
  334. static
  335. struct rpc_xprt *xprt_switch_set_next_cursor(struct rpc_xprt_switch *xps,
  336. struct rpc_xprt **cursor,
  337. xprt_switch_find_xprt_t find_next)
  338. {
  339. struct rpc_xprt *pos, *old;
  340. old = smp_load_acquire(cursor);
  341. pos = find_next(xps, old);
  342. smp_store_release(cursor, pos);
  343. return pos;
  344. }
  345. static
  346. struct rpc_xprt *xprt_iter_next_entry_multiple(struct rpc_xprt_iter *xpi,
  347. xprt_switch_find_xprt_t find_next)
  348. {
  349. struct rpc_xprt_switch *xps = rcu_dereference(xpi->xpi_xpswitch);
  350. if (xps == NULL)
  351. return NULL;
  352. return xprt_switch_set_next_cursor(xps, &xpi->xpi_cursor, find_next);
  353. }
  354. static
  355. struct rpc_xprt *__xprt_switch_find_next_entry_roundrobin(struct list_head *head,
  356. const struct rpc_xprt *cur)
  357. {
  358. struct rpc_xprt *ret;
  359. ret = xprt_switch_find_next_entry(head, cur, true);
  360. if (ret != NULL)
  361. return ret;
  362. return xprt_switch_find_first_entry(head);
  363. }
  364. static
  365. struct rpc_xprt *xprt_switch_find_next_entry_roundrobin(struct rpc_xprt_switch *xps,
  366. const struct rpc_xprt *cur)
  367. {
  368. struct list_head *head = &xps->xps_xprt_list;
  369. struct rpc_xprt *xprt;
  370. unsigned int nactive;
  371. for (;;) {
  372. unsigned long xprt_queuelen, xps_queuelen;
  373. xprt = __xprt_switch_find_next_entry_roundrobin(head, cur);
  374. if (!xprt)
  375. break;
  376. xprt_queuelen = atomic_long_read(&xprt->queuelen);
  377. xps_queuelen = atomic_long_read(&xps->xps_queuelen);
  378. nactive = READ_ONCE(xps->xps_nactive);
  379. /* Exit loop if xprt_queuelen <= average queue length */
  380. if (xprt_queuelen * nactive <= xps_queuelen)
  381. break;
  382. cur = xprt;
  383. }
  384. return xprt;
  385. }
  386. static
  387. struct rpc_xprt *xprt_iter_next_entry_roundrobin(struct rpc_xprt_iter *xpi)
  388. {
  389. return xprt_iter_next_entry_multiple(xpi,
  390. xprt_switch_find_next_entry_roundrobin);
  391. }
  392. static
  393. struct rpc_xprt *xprt_switch_find_next_entry_all(struct rpc_xprt_switch *xps,
  394. const struct rpc_xprt *cur)
  395. {
  396. return xprt_switch_find_next_entry(&xps->xps_xprt_list, cur, true);
  397. }
  398. static
  399. struct rpc_xprt *xprt_switch_find_next_entry_offline(struct rpc_xprt_switch *xps,
  400. const struct rpc_xprt *cur)
  401. {
  402. return xprt_switch_find_next_entry(&xps->xps_xprt_list, cur, false);
  403. }
  404. static
  405. struct rpc_xprt *xprt_iter_next_entry_all(struct rpc_xprt_iter *xpi)
  406. {
  407. return xprt_iter_next_entry_multiple(xpi,
  408. xprt_switch_find_next_entry_all);
  409. }
  410. static
  411. struct rpc_xprt *xprt_iter_next_entry_offline(struct rpc_xprt_iter *xpi)
  412. {
  413. return xprt_iter_next_entry_multiple(xpi,
  414. xprt_switch_find_next_entry_offline);
  415. }
  416. /*
  417. * xprt_iter_rewind - Resets the xprt iterator
  418. * @xpi: pointer to rpc_xprt_iter
  419. *
  420. * Resets xpi to ensure that it points to the first entry in the list
  421. * of transports.
  422. */
  423. void xprt_iter_rewind(struct rpc_xprt_iter *xpi)
  424. {
  425. rcu_read_lock();
  426. xprt_iter_ops(xpi)->xpi_rewind(xpi);
  427. rcu_read_unlock();
  428. }
  429. static void __xprt_iter_init(struct rpc_xprt_iter *xpi,
  430. struct rpc_xprt_switch *xps,
  431. const struct rpc_xprt_iter_ops *ops)
  432. {
  433. rcu_assign_pointer(xpi->xpi_xpswitch, xprt_switch_get(xps));
  434. xpi->xpi_cursor = NULL;
  435. xpi->xpi_ops = ops;
  436. }
  437. /**
  438. * xprt_iter_init - Initialise an xprt iterator
  439. * @xpi: pointer to rpc_xprt_iter
  440. * @xps: pointer to rpc_xprt_switch
  441. *
  442. * Initialises the iterator to use the default iterator ops
  443. * as set in xps. This function is mainly intended for internal
  444. * use in the rpc_client.
  445. */
  446. void xprt_iter_init(struct rpc_xprt_iter *xpi,
  447. struct rpc_xprt_switch *xps)
  448. {
  449. __xprt_iter_init(xpi, xps, NULL);
  450. }
  451. /**
  452. * xprt_iter_init_listall - Initialise an xprt iterator
  453. * @xpi: pointer to rpc_xprt_iter
  454. * @xps: pointer to rpc_xprt_switch
  455. *
  456. * Initialises the iterator to iterate once through the entire list
  457. * of entries in xps.
  458. */
  459. void xprt_iter_init_listall(struct rpc_xprt_iter *xpi,
  460. struct rpc_xprt_switch *xps)
  461. {
  462. __xprt_iter_init(xpi, xps, &rpc_xprt_iter_listall);
  463. }
  464. void xprt_iter_init_listoffline(struct rpc_xprt_iter *xpi,
  465. struct rpc_xprt_switch *xps)
  466. {
  467. __xprt_iter_init(xpi, xps, &rpc_xprt_iter_listoffline);
  468. }
  469. /**
  470. * xprt_iter_xchg_switch - Atomically swap out the rpc_xprt_switch
  471. * @xpi: pointer to rpc_xprt_iter
  472. * @newswitch: pointer to a new rpc_xprt_switch or NULL
  473. *
  474. * Swaps out the existing xpi->xpi_xpswitch with a new value.
  475. */
  476. struct rpc_xprt_switch *xprt_iter_xchg_switch(struct rpc_xprt_iter *xpi,
  477. struct rpc_xprt_switch *newswitch)
  478. {
  479. struct rpc_xprt_switch __rcu *oldswitch;
  480. /* Atomically swap out the old xpswitch */
  481. oldswitch = xchg(&xpi->xpi_xpswitch, RCU_INITIALIZER(newswitch));
  482. if (newswitch != NULL)
  483. xprt_iter_rewind(xpi);
  484. return rcu_dereference_protected(oldswitch, true);
  485. }
  486. /**
  487. * xprt_iter_destroy - Destroys the xprt iterator
  488. * @xpi: pointer to rpc_xprt_iter
  489. */
  490. void xprt_iter_destroy(struct rpc_xprt_iter *xpi)
  491. {
  492. xprt_switch_put(xprt_iter_xchg_switch(xpi, NULL));
  493. }
  494. /**
  495. * xprt_iter_xprt - Returns the rpc_xprt pointed to by the cursor
  496. * @xpi: pointer to rpc_xprt_iter
  497. *
  498. * Returns a pointer to the struct rpc_xprt that is currently
  499. * pointed to by the cursor.
  500. * Caller must be holding rcu_read_lock().
  501. */
  502. struct rpc_xprt *xprt_iter_xprt(struct rpc_xprt_iter *xpi)
  503. {
  504. WARN_ON_ONCE(!rcu_read_lock_held());
  505. return xprt_iter_ops(xpi)->xpi_xprt(xpi);
  506. }
  507. static
  508. struct rpc_xprt *xprt_iter_get_helper(struct rpc_xprt_iter *xpi,
  509. struct rpc_xprt *(*fn)(struct rpc_xprt_iter *))
  510. {
  511. struct rpc_xprt *ret;
  512. do {
  513. ret = fn(xpi);
  514. if (ret == NULL)
  515. break;
  516. ret = xprt_get(ret);
  517. } while (ret == NULL);
  518. return ret;
  519. }
  520. /**
  521. * xprt_iter_get_xprt - Returns the rpc_xprt pointed to by the cursor
  522. * @xpi: pointer to rpc_xprt_iter
  523. *
  524. * Returns a reference to the struct rpc_xprt that is currently
  525. * pointed to by the cursor.
  526. */
  527. struct rpc_xprt *xprt_iter_get_xprt(struct rpc_xprt_iter *xpi)
  528. {
  529. struct rpc_xprt *xprt;
  530. rcu_read_lock();
  531. xprt = xprt_iter_get_helper(xpi, xprt_iter_ops(xpi)->xpi_xprt);
  532. rcu_read_unlock();
  533. return xprt;
  534. }
  535. /**
  536. * xprt_iter_get_next - Returns the next rpc_xprt following the cursor
  537. * @xpi: pointer to rpc_xprt_iter
  538. *
  539. * Returns a reference to the struct rpc_xprt that immediately follows the
  540. * entry pointed to by the cursor.
  541. */
  542. struct rpc_xprt *xprt_iter_get_next(struct rpc_xprt_iter *xpi)
  543. {
  544. struct rpc_xprt *xprt;
  545. rcu_read_lock();
  546. xprt = xprt_iter_get_helper(xpi, xprt_iter_ops(xpi)->xpi_next);
  547. rcu_read_unlock();
  548. return xprt;
  549. }
  550. /* Policy for always returning the first entry in the rpc_xprt_switch */
  551. static
  552. const struct rpc_xprt_iter_ops rpc_xprt_iter_singular = {
  553. .xpi_rewind = xprt_iter_no_rewind,
  554. .xpi_xprt = xprt_iter_first_entry,
  555. .xpi_next = xprt_iter_first_entry,
  556. };
  557. /* Policy for round-robin iteration of entries in the rpc_xprt_switch */
  558. static
  559. const struct rpc_xprt_iter_ops rpc_xprt_iter_roundrobin = {
  560. .xpi_rewind = xprt_iter_default_rewind,
  561. .xpi_xprt = xprt_iter_current_entry,
  562. .xpi_next = xprt_iter_next_entry_roundrobin,
  563. };
  564. /* Policy for once-through iteration of entries in the rpc_xprt_switch */
  565. static
  566. const struct rpc_xprt_iter_ops rpc_xprt_iter_listall = {
  567. .xpi_rewind = xprt_iter_default_rewind,
  568. .xpi_xprt = xprt_iter_current_entry,
  569. .xpi_next = xprt_iter_next_entry_all,
  570. };
  571. static
  572. const struct rpc_xprt_iter_ops rpc_xprt_iter_listoffline = {
  573. .xpi_rewind = xprt_iter_default_rewind,
  574. .xpi_xprt = xprt_iter_current_entry_offline,
  575. .xpi_next = xprt_iter_next_entry_offline,
  576. };