xprtmultipath.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668
  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. 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. static
  298. bool __rpc_xprt_switch_has_addr(struct rpc_xprt_switch *xps,
  299. const struct sockaddr *sap)
  300. {
  301. struct list_head *head;
  302. struct rpc_xprt *pos;
  303. if (xps == NULL || sap == NULL)
  304. return false;
  305. head = &xps->xps_xprt_list;
  306. list_for_each_entry_rcu(pos, head, xprt_switch) {
  307. if (rpc_cmp_addr_port(sap, (struct sockaddr *)&pos->addr)) {
  308. pr_info("RPC: addr %s already in xprt switch\n",
  309. pos->address_strings[RPC_DISPLAY_ADDR]);
  310. return true;
  311. }
  312. }
  313. return false;
  314. }
  315. bool rpc_xprt_switch_has_addr(struct rpc_xprt_switch *xps,
  316. const struct sockaddr *sap)
  317. {
  318. bool res;
  319. rcu_read_lock();
  320. res = __rpc_xprt_switch_has_addr(xps, sap);
  321. rcu_read_unlock();
  322. return res;
  323. }
  324. static
  325. struct rpc_xprt *xprt_switch_find_next_entry(struct list_head *head,
  326. const struct rpc_xprt *cur, bool check_active)
  327. {
  328. struct rpc_xprt *pos, *prev = NULL;
  329. bool found = false;
  330. list_for_each_entry_rcu(pos, head, xprt_switch) {
  331. if (cur == prev)
  332. found = true;
  333. /* for request to return active transports return only
  334. * active, for request to return offline transports
  335. * return only offline
  336. */
  337. if (found && ((check_active && xprt_is_active(pos)) ||
  338. (!check_active && !xprt_is_active(pos))))
  339. return pos;
  340. prev = pos;
  341. }
  342. return NULL;
  343. }
  344. static
  345. struct rpc_xprt *xprt_switch_set_next_cursor(struct rpc_xprt_switch *xps,
  346. struct rpc_xprt **cursor,
  347. xprt_switch_find_xprt_t find_next)
  348. {
  349. struct rpc_xprt *pos, *old;
  350. old = smp_load_acquire(cursor);
  351. pos = find_next(xps, old);
  352. smp_store_release(cursor, pos);
  353. return pos;
  354. }
  355. static
  356. struct rpc_xprt *xprt_iter_next_entry_multiple(struct rpc_xprt_iter *xpi,
  357. xprt_switch_find_xprt_t find_next)
  358. {
  359. struct rpc_xprt_switch *xps = rcu_dereference(xpi->xpi_xpswitch);
  360. if (xps == NULL)
  361. return NULL;
  362. return xprt_switch_set_next_cursor(xps, &xpi->xpi_cursor, find_next);
  363. }
  364. static
  365. struct rpc_xprt *__xprt_switch_find_next_entry_roundrobin(struct list_head *head,
  366. const struct rpc_xprt *cur)
  367. {
  368. struct rpc_xprt *ret;
  369. ret = xprt_switch_find_next_entry(head, cur, true);
  370. if (ret != NULL)
  371. return ret;
  372. return xprt_switch_find_first_entry(head);
  373. }
  374. static
  375. struct rpc_xprt *xprt_switch_find_next_entry_roundrobin(struct rpc_xprt_switch *xps,
  376. const struct rpc_xprt *cur)
  377. {
  378. struct list_head *head = &xps->xps_xprt_list;
  379. struct rpc_xprt *xprt;
  380. unsigned int nactive;
  381. for (;;) {
  382. unsigned long xprt_queuelen, xps_queuelen;
  383. xprt = __xprt_switch_find_next_entry_roundrobin(head, cur);
  384. if (!xprt)
  385. break;
  386. xprt_queuelen = atomic_long_read(&xprt->queuelen);
  387. xps_queuelen = atomic_long_read(&xps->xps_queuelen);
  388. nactive = READ_ONCE(xps->xps_nactive);
  389. /* Exit loop if xprt_queuelen <= average queue length */
  390. if (xprt_queuelen * nactive <= xps_queuelen)
  391. break;
  392. cur = xprt;
  393. }
  394. return xprt;
  395. }
  396. static
  397. struct rpc_xprt *xprt_iter_next_entry_roundrobin(struct rpc_xprt_iter *xpi)
  398. {
  399. return xprt_iter_next_entry_multiple(xpi,
  400. xprt_switch_find_next_entry_roundrobin);
  401. }
  402. static
  403. struct rpc_xprt *xprt_switch_find_next_entry_all(struct rpc_xprt_switch *xps,
  404. const struct rpc_xprt *cur)
  405. {
  406. return xprt_switch_find_next_entry(&xps->xps_xprt_list, cur, true);
  407. }
  408. static
  409. struct rpc_xprt *xprt_switch_find_next_entry_offline(struct rpc_xprt_switch *xps,
  410. const struct rpc_xprt *cur)
  411. {
  412. return xprt_switch_find_next_entry(&xps->xps_xprt_list, cur, false);
  413. }
  414. static
  415. struct rpc_xprt *xprt_iter_next_entry_all(struct rpc_xprt_iter *xpi)
  416. {
  417. return xprt_iter_next_entry_multiple(xpi,
  418. xprt_switch_find_next_entry_all);
  419. }
  420. static
  421. struct rpc_xprt *xprt_iter_next_entry_offline(struct rpc_xprt_iter *xpi)
  422. {
  423. return xprt_iter_next_entry_multiple(xpi,
  424. xprt_switch_find_next_entry_offline);
  425. }
  426. /*
  427. * xprt_iter_rewind - Resets the xprt iterator
  428. * @xpi: pointer to rpc_xprt_iter
  429. *
  430. * Resets xpi to ensure that it points to the first entry in the list
  431. * of transports.
  432. */
  433. void xprt_iter_rewind(struct rpc_xprt_iter *xpi)
  434. {
  435. rcu_read_lock();
  436. xprt_iter_ops(xpi)->xpi_rewind(xpi);
  437. rcu_read_unlock();
  438. }
  439. static void __xprt_iter_init(struct rpc_xprt_iter *xpi,
  440. struct rpc_xprt_switch *xps,
  441. const struct rpc_xprt_iter_ops *ops)
  442. {
  443. rcu_assign_pointer(xpi->xpi_xpswitch, xprt_switch_get(xps));
  444. xpi->xpi_cursor = NULL;
  445. xpi->xpi_ops = ops;
  446. }
  447. /**
  448. * xprt_iter_init - Initialise an xprt iterator
  449. * @xpi: pointer to rpc_xprt_iter
  450. * @xps: pointer to rpc_xprt_switch
  451. *
  452. * Initialises the iterator to use the default iterator ops
  453. * as set in xps. This function is mainly intended for internal
  454. * use in the rpc_client.
  455. */
  456. void xprt_iter_init(struct rpc_xprt_iter *xpi,
  457. struct rpc_xprt_switch *xps)
  458. {
  459. __xprt_iter_init(xpi, xps, NULL);
  460. }
  461. /**
  462. * xprt_iter_init_listall - Initialise an xprt iterator
  463. * @xpi: pointer to rpc_xprt_iter
  464. * @xps: pointer to rpc_xprt_switch
  465. *
  466. * Initialises the iterator to iterate once through the entire list
  467. * of entries in xps.
  468. */
  469. void xprt_iter_init_listall(struct rpc_xprt_iter *xpi,
  470. struct rpc_xprt_switch *xps)
  471. {
  472. __xprt_iter_init(xpi, xps, &rpc_xprt_iter_listall);
  473. }
  474. void xprt_iter_init_listoffline(struct rpc_xprt_iter *xpi,
  475. struct rpc_xprt_switch *xps)
  476. {
  477. __xprt_iter_init(xpi, xps, &rpc_xprt_iter_listoffline);
  478. }
  479. /**
  480. * xprt_iter_xchg_switch - Atomically swap out the rpc_xprt_switch
  481. * @xpi: pointer to rpc_xprt_iter
  482. * @newswitch: pointer to a new rpc_xprt_switch or NULL
  483. *
  484. * Swaps out the existing xpi->xpi_xpswitch with a new value.
  485. */
  486. struct rpc_xprt_switch *xprt_iter_xchg_switch(struct rpc_xprt_iter *xpi,
  487. struct rpc_xprt_switch *newswitch)
  488. {
  489. struct rpc_xprt_switch __rcu *oldswitch;
  490. /* Atomically swap out the old xpswitch */
  491. oldswitch = xchg(&xpi->xpi_xpswitch, RCU_INITIALIZER(newswitch));
  492. if (newswitch != NULL)
  493. xprt_iter_rewind(xpi);
  494. return rcu_dereference_protected(oldswitch, true);
  495. }
  496. /**
  497. * xprt_iter_destroy - Destroys the xprt iterator
  498. * @xpi: pointer to rpc_xprt_iter
  499. */
  500. void xprt_iter_destroy(struct rpc_xprt_iter *xpi)
  501. {
  502. xprt_switch_put(xprt_iter_xchg_switch(xpi, NULL));
  503. }
  504. /**
  505. * xprt_iter_xprt - Returns the rpc_xprt pointed to by the cursor
  506. * @xpi: pointer to rpc_xprt_iter
  507. *
  508. * Returns a pointer to the struct rpc_xprt that is currently
  509. * pointed to by the cursor.
  510. * Caller must be holding rcu_read_lock().
  511. */
  512. struct rpc_xprt *xprt_iter_xprt(struct rpc_xprt_iter *xpi)
  513. {
  514. WARN_ON_ONCE(!rcu_read_lock_held());
  515. return xprt_iter_ops(xpi)->xpi_xprt(xpi);
  516. }
  517. static
  518. struct rpc_xprt *xprt_iter_get_helper(struct rpc_xprt_iter *xpi,
  519. struct rpc_xprt *(*fn)(struct rpc_xprt_iter *))
  520. {
  521. struct rpc_xprt *ret;
  522. do {
  523. ret = fn(xpi);
  524. if (ret == NULL)
  525. break;
  526. ret = xprt_get(ret);
  527. } while (ret == NULL);
  528. return ret;
  529. }
  530. /**
  531. * xprt_iter_get_xprt - Returns the rpc_xprt pointed to by the cursor
  532. * @xpi: pointer to rpc_xprt_iter
  533. *
  534. * Returns a reference to the struct rpc_xprt that is currently
  535. * pointed to by the cursor.
  536. */
  537. struct rpc_xprt *xprt_iter_get_xprt(struct rpc_xprt_iter *xpi)
  538. {
  539. struct rpc_xprt *xprt;
  540. rcu_read_lock();
  541. xprt = xprt_iter_get_helper(xpi, xprt_iter_ops(xpi)->xpi_xprt);
  542. rcu_read_unlock();
  543. return xprt;
  544. }
  545. /**
  546. * xprt_iter_get_next - Returns the next rpc_xprt following the cursor
  547. * @xpi: pointer to rpc_xprt_iter
  548. *
  549. * Returns a reference to the struct rpc_xprt that immediately follows the
  550. * entry pointed to by the cursor.
  551. */
  552. struct rpc_xprt *xprt_iter_get_next(struct rpc_xprt_iter *xpi)
  553. {
  554. struct rpc_xprt *xprt;
  555. rcu_read_lock();
  556. xprt = xprt_iter_get_helper(xpi, xprt_iter_ops(xpi)->xpi_next);
  557. rcu_read_unlock();
  558. return xprt;
  559. }
  560. /* Policy for always returning the first entry in the rpc_xprt_switch */
  561. static
  562. const struct rpc_xprt_iter_ops rpc_xprt_iter_singular = {
  563. .xpi_rewind = xprt_iter_no_rewind,
  564. .xpi_xprt = xprt_iter_first_entry,
  565. .xpi_next = xprt_iter_first_entry,
  566. };
  567. /* Policy for round-robin iteration of entries in the rpc_xprt_switch */
  568. static
  569. const struct rpc_xprt_iter_ops rpc_xprt_iter_roundrobin = {
  570. .xpi_rewind = xprt_iter_default_rewind,
  571. .xpi_xprt = xprt_iter_current_entry,
  572. .xpi_next = xprt_iter_next_entry_roundrobin,
  573. };
  574. /* Policy for once-through iteration of entries in the rpc_xprt_switch */
  575. static
  576. const struct rpc_xprt_iter_ops rpc_xprt_iter_listall = {
  577. .xpi_rewind = xprt_iter_default_rewind,
  578. .xpi_xprt = xprt_iter_current_entry,
  579. .xpi_next = xprt_iter_next_entry_all,
  580. };
  581. static
  582. const struct rpc_xprt_iter_ops rpc_xprt_iter_listoffline = {
  583. .xpi_rewind = xprt_iter_default_rewind,
  584. .xpi_xprt = xprt_iter_current_entry_offline,
  585. .xpi_next = xprt_iter_next_entry_offline,
  586. };