xprtmultipath.c 17 KB

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