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