1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include "spdk/likely.h" 35 #include "spdk_internal/log.h" 36 #include "spdk/ftl.h" 37 38 #include "ftl_reloc.h" 39 #include "ftl_core.h" 40 #include "ftl_io.h" 41 #include "ftl_rwb.h" 42 #include "ftl_band.h" 43 #include "ftl_debug.h" 44 45 /* Maximum active reloc moves */ 46 #define FTL_RELOC_MAX_MOVES 256 47 48 struct ftl_reloc; 49 struct ftl_band_reloc; 50 51 enum ftl_reloc_move_state { 52 FTL_RELOC_STATE_READ_LBA_MAP, 53 FTL_RELOC_STATE_READ, 54 FTL_RELOC_STATE_WRITE, 55 }; 56 57 struct ftl_reloc_move { 58 struct ftl_band_reloc *breloc; 59 60 /* Start ppa */ 61 struct ftl_ppa ppa; 62 63 /* Number of logical blocks */ 64 size_t lbk_cnt; 65 66 /* Data buffer */ 67 void *data; 68 69 /* Move state (read lba_map, read, write) */ 70 enum ftl_reloc_move_state state; 71 72 /* IO associated with move */ 73 struct ftl_io *io; 74 }; 75 76 struct ftl_band_reloc { 77 struct ftl_reloc *parent; 78 79 /* Band being relocated */ 80 struct ftl_band *band; 81 82 /* Number of logical blocks to be relocated */ 83 size_t num_lbks; 84 85 /* Bitmap of logical blocks to be relocated */ 86 struct spdk_bit_array *reloc_map; 87 88 /* Indicates band being acitvely processed */ 89 int active; 90 /* The band is being defragged */ 91 bool defrag; 92 93 /* Reloc map iterator */ 94 struct { 95 /* Array of chunk offsets */ 96 size_t *chk_offset; 97 98 /* Currently chunk */ 99 size_t chk_current; 100 } iter; 101 102 /* Number of outstanding moves */ 103 size_t num_outstanding; 104 105 /* Pool of move objects */ 106 struct ftl_reloc_move *moves; 107 108 /* Move queue */ 109 struct spdk_ring *move_queue; 110 111 TAILQ_ENTRY(ftl_band_reloc) entry; 112 }; 113 114 struct ftl_reloc { 115 /* Device associated with relocate */ 116 struct spdk_ftl_dev *dev; 117 118 /* Indicates relocate is about to halt */ 119 bool halt; 120 121 /* Maximum number of IOs per band */ 122 size_t max_qdepth; 123 124 /* Maximum number of active band relocates */ 125 size_t max_active; 126 127 /* Maximum transfer size (in logical blocks) per single IO */ 128 size_t xfer_size; 129 /* Number of bands being defragged */ 130 size_t num_defrag_bands; 131 132 /* Array of band relocates */ 133 struct ftl_band_reloc *brelocs; 134 135 /* Number of active/priority band relocates */ 136 size_t num_active; 137 138 /* Priority band relocates queue */ 139 TAILQ_HEAD(, ftl_band_reloc) prio_queue; 140 141 /* Active band relocates queue */ 142 TAILQ_HEAD(, ftl_band_reloc) active_queue; 143 144 /* Pending band relocates queue */ 145 TAILQ_HEAD(, ftl_band_reloc) pending_queue; 146 }; 147 148 bool 149 ftl_reloc_is_defrag_active(const struct ftl_reloc *reloc) 150 { 151 return reloc->num_defrag_bands > 0; 152 } 153 154 static size_t 155 ftl_reloc_iter_chk_offset(struct ftl_band_reloc *breloc) 156 { 157 size_t chunk = breloc->iter.chk_current; 158 159 return breloc->iter.chk_offset[chunk]; 160 } 161 162 static size_t 163 ftl_reloc_iter_chk_done(struct ftl_band_reloc *breloc) 164 { 165 size_t num_lbks = ftl_dev_lbks_in_chunk(breloc->parent->dev); 166 167 return ftl_reloc_iter_chk_offset(breloc) == num_lbks; 168 } 169 170 static void 171 ftl_reloc_clr_lbk(struct ftl_band_reloc *breloc, size_t lbkoff) 172 { 173 if (!spdk_bit_array_get(breloc->reloc_map, lbkoff)) { 174 return; 175 } 176 177 spdk_bit_array_clear(breloc->reloc_map, lbkoff); 178 assert(breloc->num_lbks); 179 breloc->num_lbks--; 180 } 181 182 static void 183 ftl_reloc_read_lba_map_cb(struct ftl_io *io, void *arg, int status) 184 { 185 struct ftl_reloc_move *move = arg; 186 struct ftl_band_reloc *breloc = move->breloc; 187 188 breloc->num_outstanding--; 189 assert(status == 0); 190 move->state = FTL_RELOC_STATE_WRITE; 191 spdk_ring_enqueue(breloc->move_queue, (void **)&move, 1, NULL); 192 } 193 194 static int 195 ftl_reloc_read_lba_map(struct ftl_band_reloc *breloc, struct ftl_reloc_move *move) 196 { 197 struct ftl_band *band = breloc->band; 198 199 breloc->num_outstanding++; 200 return ftl_band_read_lba_map(band, ftl_band_lbkoff_from_ppa(band, move->ppa), 201 move->lbk_cnt, ftl_reloc_read_lba_map_cb, move); 202 } 203 204 static void 205 ftl_reloc_prep(struct ftl_band_reloc *breloc) 206 { 207 struct ftl_band *band = breloc->band; 208 struct ftl_reloc *reloc = breloc->parent; 209 struct ftl_reloc_move *move; 210 size_t i; 211 212 breloc->active = 1; 213 reloc->num_active++; 214 215 if (!band->high_prio) { 216 if (band->lba_map.ref_cnt == 0) { 217 if (ftl_band_alloc_lba_map(band)) { 218 assert(false); 219 } 220 } else { 221 ftl_band_acquire_lba_map(band); 222 } 223 } 224 225 for (i = 0; i < reloc->max_qdepth; ++i) { 226 move = &breloc->moves[i]; 227 move->state = FTL_RELOC_STATE_READ; 228 spdk_ring_enqueue(breloc->move_queue, (void **)&move, 1, NULL); 229 } 230 } 231 232 static void 233 ftl_reloc_free_move(struct ftl_band_reloc *breloc, struct ftl_reloc_move *move) 234 { 235 assert(move); 236 spdk_dma_free(move->data); 237 memset(move, 0, sizeof(*move)); 238 move->state = FTL_RELOC_STATE_READ; 239 spdk_ring_enqueue(breloc->move_queue, (void **)&move, 1, NULL); 240 } 241 242 static void 243 ftl_reloc_write_cb(struct ftl_io *io, void *arg, int status) 244 { 245 struct ftl_reloc_move *move = arg; 246 struct ftl_ppa ppa = move->ppa; 247 struct ftl_band_reloc *breloc = move->breloc; 248 size_t i; 249 250 breloc->num_outstanding--; 251 252 if (status) { 253 SPDK_ERRLOG("Reloc write failed with status: %d\n", status); 254 assert(false); 255 return; 256 } 257 258 for (i = 0; i < move->lbk_cnt; ++i) { 259 ppa.lbk = move->ppa.lbk + i; 260 size_t lbkoff = ftl_band_lbkoff_from_ppa(breloc->band, ppa); 261 ftl_reloc_clr_lbk(breloc, lbkoff); 262 } 263 264 ftl_reloc_free_move(breloc, move); 265 } 266 267 static void 268 ftl_reloc_read_cb(struct ftl_io *io, void *arg, int status) 269 { 270 struct ftl_reloc_move *move = arg; 271 struct ftl_band_reloc *breloc = move->breloc; 272 273 breloc->num_outstanding--; 274 275 /* TODO: We should handle fail on relocation read. We need to inform */ 276 /* user that this group of blocks is bad (update l2p with bad block address and */ 277 /* put it to lba_map/sector_lba). Maybe we could also retry read with smaller granularity? */ 278 if (status) { 279 SPDK_ERRLOG("Reloc read failed with status: %d\n", status); 280 assert(false); 281 return; 282 } 283 284 move->state = FTL_RELOC_STATE_READ_LBA_MAP; 285 move->io = NULL; 286 spdk_ring_enqueue(breloc->move_queue, (void **)&move, 1, NULL); 287 } 288 289 static void 290 ftl_reloc_iter_reset(struct ftl_band_reloc *breloc) 291 { 292 memset(breloc->iter.chk_offset, 0, ftl_dev_num_punits(breloc->band->dev) * 293 sizeof(*breloc->iter.chk_offset)); 294 breloc->iter.chk_current = 0; 295 } 296 297 static size_t 298 ftl_reloc_iter_lbkoff(struct ftl_band_reloc *breloc) 299 { 300 size_t chk_offset = breloc->iter.chk_current * ftl_dev_lbks_in_chunk(breloc->parent->dev); 301 302 return breloc->iter.chk_offset[breloc->iter.chk_current] + chk_offset; 303 } 304 305 static void 306 ftl_reloc_iter_next_chk(struct ftl_band_reloc *breloc) 307 { 308 size_t num_chk = ftl_dev_num_punits(breloc->band->dev); 309 310 breloc->iter.chk_current = (breloc->iter.chk_current + 1) % num_chk; 311 } 312 313 static int 314 ftl_reloc_lbk_valid(struct ftl_band_reloc *breloc, size_t lbkoff) 315 { 316 struct ftl_ppa ppa = ftl_band_ppa_from_lbkoff(breloc->band, lbkoff); 317 318 return ftl_ppa_is_written(breloc->band, ppa) && 319 spdk_bit_array_get(breloc->reloc_map, lbkoff) && 320 ftl_band_lbkoff_valid(breloc->band, lbkoff); 321 } 322 323 static int 324 ftl_reloc_iter_next(struct ftl_band_reloc *breloc, size_t *lbkoff) 325 { 326 size_t chunk = breloc->iter.chk_current; 327 328 *lbkoff = ftl_reloc_iter_lbkoff(breloc); 329 330 if (ftl_reloc_iter_chk_done(breloc)) { 331 return 0; 332 } 333 334 breloc->iter.chk_offset[chunk]++; 335 336 if (!ftl_reloc_lbk_valid(breloc, *lbkoff)) { 337 ftl_reloc_clr_lbk(breloc, *lbkoff); 338 return 0; 339 } 340 341 return 1; 342 } 343 344 static int 345 ftl_reloc_first_valid_lbk(struct ftl_band_reloc *breloc, size_t *lbkoff) 346 { 347 size_t i, num_lbks = ftl_dev_lbks_in_chunk(breloc->parent->dev); 348 349 for (i = ftl_reloc_iter_chk_offset(breloc); i < num_lbks; ++i) { 350 if (ftl_reloc_iter_next(breloc, lbkoff)) { 351 return 1; 352 } 353 } 354 355 return 0; 356 } 357 358 static int 359 ftl_reloc_iter_done(struct ftl_band_reloc *breloc) 360 { 361 size_t i; 362 size_t num_chks = ftl_dev_num_punits(breloc->band->dev); 363 size_t num_lbks = ftl_dev_lbks_in_chunk(breloc->parent->dev); 364 365 for (i = 0; i < num_chks; ++i) { 366 if (breloc->iter.chk_offset[i] != num_lbks) { 367 return 0; 368 } 369 } 370 371 return 1; 372 } 373 374 static size_t 375 ftl_reloc_find_valid_lbks(struct ftl_band_reloc *breloc, 376 size_t num_lbk, struct ftl_ppa *ppa) 377 { 378 size_t lbkoff, lbk_cnt = 0; 379 380 if (!ftl_reloc_first_valid_lbk(breloc, &lbkoff)) { 381 return 0; 382 } 383 384 *ppa = ftl_band_ppa_from_lbkoff(breloc->band, lbkoff); 385 386 for (lbk_cnt = 1; lbk_cnt < num_lbk; lbk_cnt++) { 387 if (!ftl_reloc_iter_next(breloc, &lbkoff)) { 388 break; 389 } 390 } 391 392 return lbk_cnt; 393 } 394 395 static size_t 396 ftl_reloc_next_lbks(struct ftl_band_reloc *breloc, struct ftl_ppa *ppa) 397 { 398 size_t i, lbk_cnt = 0; 399 struct spdk_ftl_dev *dev = breloc->parent->dev; 400 401 for (i = 0; i < ftl_dev_num_punits(dev); ++i) { 402 lbk_cnt = ftl_reloc_find_valid_lbks(breloc, breloc->parent->xfer_size, ppa); 403 ftl_reloc_iter_next_chk(breloc); 404 405 if (lbk_cnt || ftl_reloc_iter_done(breloc)) { 406 break; 407 } 408 } 409 410 return lbk_cnt; 411 } 412 413 static struct ftl_io * 414 ftl_reloc_io_init(struct ftl_band_reloc *breloc, struct ftl_reloc_move *move, 415 ftl_io_fn fn, enum ftl_io_type io_type, int flags) 416 { 417 size_t lbkoff, i; 418 struct ftl_ppa ppa = move->ppa; 419 struct ftl_io *io = NULL; 420 struct ftl_io_init_opts opts = { 421 .dev = breloc->parent->dev, 422 .band = breloc->band, 423 .size = sizeof(*io), 424 .flags = flags | FTL_IO_INTERNAL | FTL_IO_PPA_MODE, 425 .type = io_type, 426 .lbk_cnt = move->lbk_cnt, 427 .data = move->data, 428 .cb_fn = fn, 429 }; 430 431 io = ftl_io_init_internal(&opts); 432 if (!io) { 433 return NULL; 434 } 435 436 io->cb_ctx = move; 437 io->ppa = move->ppa; 438 439 if (flags & FTL_IO_VECTOR_LBA) { 440 for (i = 0; i < io->lbk_cnt; ++i, ++ppa.lbk) { 441 lbkoff = ftl_band_lbkoff_from_ppa(breloc->band, ppa); 442 443 if (!ftl_band_lbkoff_valid(breloc->band, lbkoff)) { 444 io->lba.vector[i] = FTL_LBA_INVALID; 445 continue; 446 } 447 448 io->lba.vector[i] = breloc->band->lba_map.map[lbkoff]; 449 } 450 } 451 452 ftl_trace_lba_io_init(io->dev, io); 453 454 return io; 455 } 456 457 static int 458 ftl_reloc_write(struct ftl_band_reloc *breloc, struct ftl_reloc_move *move) 459 { 460 int io_flags = FTL_IO_WEAK | FTL_IO_VECTOR_LBA | FTL_IO_BYPASS_CACHE; 461 462 if (spdk_likely(!move->io)) { 463 move->io = ftl_reloc_io_init(breloc, move, ftl_reloc_write_cb, 464 FTL_IO_WRITE, io_flags); 465 if (!move->io) { 466 ftl_reloc_free_move(breloc, move); 467 return -ENOMEM; 468 } 469 } 470 471 breloc->num_outstanding++; 472 ftl_io_write(move->io); 473 return 0; 474 } 475 476 static int 477 ftl_reloc_read(struct ftl_band_reloc *breloc, struct ftl_reloc_move *move) 478 { 479 struct ftl_ppa ppa = {}; 480 481 move->lbk_cnt = ftl_reloc_next_lbks(breloc, &ppa); 482 move->breloc = breloc; 483 move->ppa = ppa; 484 485 if (!move->lbk_cnt) { 486 return 0; 487 } 488 489 move->data = spdk_dma_malloc(FTL_BLOCK_SIZE * move->lbk_cnt, 4096, NULL); 490 if (!move->data) { 491 return -1; 492 } 493 494 move->io = ftl_reloc_io_init(breloc, move, ftl_reloc_read_cb, FTL_IO_READ, 0); 495 if (!move->io) { 496 ftl_reloc_free_move(breloc, move); 497 SPDK_ERRLOG("Failed to initialize io for relocation."); 498 return -1; 499 } 500 501 breloc->num_outstanding++; 502 ftl_io_read(move->io); 503 return 0; 504 } 505 506 static void 507 ftl_reloc_process_moves(struct ftl_band_reloc *breloc) 508 { 509 int rc = 0; 510 size_t i, num_moves; 511 struct ftl_reloc_move *moves[FTL_RELOC_MAX_MOVES] = {0}; 512 struct ftl_reloc *reloc = breloc->parent; 513 struct ftl_reloc_move *move; 514 515 num_moves = spdk_ring_dequeue(breloc->move_queue, (void **)moves, reloc->max_qdepth); 516 517 for (i = 0; i < num_moves; ++i) { 518 move = moves[i]; 519 assert(move != NULL); 520 switch (move->state) { 521 case FTL_RELOC_STATE_READ_LBA_MAP: 522 rc = ftl_reloc_read_lba_map(breloc, move); 523 break; 524 case FTL_RELOC_STATE_READ: 525 rc = ftl_reloc_read(breloc, move); 526 break; 527 case FTL_RELOC_STATE_WRITE: 528 rc = ftl_reloc_write(breloc, move); 529 break; 530 default: 531 assert(false); 532 break; 533 } 534 535 if (rc) { 536 SPDK_ERRLOG("Move queue processing failed\n"); 537 assert(false); 538 } 539 } 540 } 541 542 static bool 543 ftl_reloc_done(struct ftl_band_reloc *breloc) 544 { 545 return !breloc->num_outstanding && !spdk_ring_count(breloc->move_queue); 546 } 547 548 static void 549 ftl_reloc_release(struct ftl_band_reloc *breloc) 550 { 551 struct ftl_reloc *reloc = breloc->parent; 552 struct ftl_band *band = breloc->band; 553 554 if (band->high_prio && breloc->num_lbks == 0) { 555 band->high_prio = 0; 556 TAILQ_REMOVE(&reloc->prio_queue, breloc, entry); 557 } else if (!band->high_prio) { 558 TAILQ_REMOVE(&reloc->active_queue, breloc, entry); 559 } 560 561 ftl_reloc_iter_reset(breloc); 562 563 ftl_band_release_lba_map(band); 564 565 breloc->active = 0; 566 reloc->num_active--; 567 568 if (!band->high_prio && breloc->num_lbks) { 569 TAILQ_INSERT_TAIL(&reloc->pending_queue, breloc, entry); 570 return; 571 } 572 573 if (ftl_band_empty(band) && band->state == FTL_BAND_STATE_CLOSED) { 574 ftl_band_set_state(breloc->band, FTL_BAND_STATE_FREE); 575 576 if (breloc->defrag) { 577 breloc->defrag = false; 578 assert(reloc->num_defrag_bands > 0); 579 reloc->num_defrag_bands--; 580 } 581 } 582 } 583 584 static void 585 ftl_process_reloc(struct ftl_band_reloc *breloc) 586 { 587 ftl_reloc_process_moves(breloc); 588 589 if (ftl_reloc_done(breloc)) { 590 ftl_reloc_release(breloc); 591 } 592 } 593 594 static int 595 ftl_band_reloc_init(struct ftl_reloc *reloc, struct ftl_band_reloc *breloc, 596 struct ftl_band *band) 597 { 598 breloc->band = band; 599 breloc->parent = reloc; 600 601 breloc->reloc_map = spdk_bit_array_create(ftl_num_band_lbks(reloc->dev)); 602 if (!breloc->reloc_map) { 603 SPDK_ERRLOG("Failed to initialize reloc map"); 604 return -1; 605 } 606 607 breloc->iter.chk_offset = calloc(ftl_dev_num_punits(band->dev), 608 sizeof(*breloc->iter.chk_offset)); 609 if (!breloc->iter.chk_offset) { 610 SPDK_ERRLOG("Failed to initialize reloc iterator"); 611 return -1; 612 } 613 614 breloc->move_queue = spdk_ring_create(SPDK_RING_TYPE_MP_SC, 615 reloc->max_qdepth * 2, 616 SPDK_ENV_SOCKET_ID_ANY); 617 if (!breloc->move_queue) { 618 SPDK_ERRLOG("Failed to initialize reloc write queue"); 619 return -1; 620 } 621 622 breloc->moves = calloc(reloc->max_qdepth, sizeof(*breloc->moves)); 623 if (!breloc->moves) { 624 return -1; 625 } 626 627 return 0; 628 } 629 630 static void 631 ftl_band_reloc_free(struct ftl_band_reloc *breloc) 632 { 633 struct ftl_reloc *reloc; 634 struct ftl_reloc_move *moves[FTL_RELOC_MAX_MOVES] = {}; 635 size_t i, num_moves; 636 637 if (!breloc) { 638 return; 639 } 640 641 assert(breloc->num_outstanding == 0); 642 reloc = breloc->parent; 643 644 /* Drain write queue if there is active band relocation during shutdown */ 645 if (breloc->active) { 646 assert(reloc->halt); 647 num_moves = spdk_ring_dequeue(breloc->move_queue, (void **)&moves, reloc->max_qdepth); 648 for (i = 0; i < num_moves; ++i) { 649 ftl_reloc_free_move(breloc, moves[i]); 650 } 651 } 652 653 spdk_ring_free(breloc->move_queue); 654 spdk_bit_array_free(&breloc->reloc_map); 655 free(breloc->iter.chk_offset); 656 free(breloc->moves); 657 } 658 659 static void 660 ftl_reloc_add_active_queue(struct ftl_band_reloc *breloc) 661 { 662 struct ftl_reloc *reloc = breloc->parent; 663 664 TAILQ_REMOVE(&reloc->pending_queue, breloc, entry); 665 TAILQ_INSERT_HEAD(&reloc->active_queue, breloc, entry); 666 ftl_reloc_prep(breloc); 667 } 668 669 struct ftl_reloc * 670 ftl_reloc_init(struct spdk_ftl_dev *dev) 671 { 672 #define POOL_NAME_LEN 128 673 struct ftl_reloc *reloc; 674 char pool_name[POOL_NAME_LEN]; 675 int rc; 676 size_t i; 677 678 reloc = calloc(1, sizeof(*reloc)); 679 if (!reloc) { 680 return NULL; 681 } 682 683 reloc->dev = dev; 684 reloc->halt = true; 685 reloc->max_qdepth = dev->conf.max_reloc_qdepth; 686 reloc->max_active = dev->conf.max_active_relocs; 687 reloc->xfer_size = dev->xfer_size; 688 reloc->num_defrag_bands = 0; 689 690 if (reloc->max_qdepth > FTL_RELOC_MAX_MOVES) { 691 goto error; 692 } 693 694 reloc->brelocs = calloc(ftl_dev_num_bands(dev), sizeof(*reloc->brelocs)); 695 if (!reloc->brelocs) { 696 goto error; 697 } 698 699 for (i = 0; i < ftl_dev_num_bands(reloc->dev); ++i) { 700 if (ftl_band_reloc_init(reloc, &reloc->brelocs[i], &dev->bands[i])) { 701 goto error; 702 } 703 } 704 705 rc = snprintf(pool_name, sizeof(pool_name), "%s-%s", dev->name, "reloc-io-pool"); 706 if (rc < 0 || rc >= POOL_NAME_LEN) { 707 goto error; 708 } 709 710 TAILQ_INIT(&reloc->pending_queue); 711 TAILQ_INIT(&reloc->active_queue); 712 TAILQ_INIT(&reloc->prio_queue); 713 714 return reloc; 715 error: 716 ftl_reloc_free(reloc); 717 return NULL; 718 } 719 720 void 721 ftl_reloc_free(struct ftl_reloc *reloc) 722 { 723 size_t i; 724 725 if (!reloc) { 726 return; 727 } 728 729 for (i = 0; i < ftl_dev_num_bands(reloc->dev); ++i) { 730 ftl_band_reloc_free(&reloc->brelocs[i]); 731 } 732 733 free(reloc->brelocs); 734 free(reloc); 735 } 736 737 bool 738 ftl_reloc_is_halted(const struct ftl_reloc *reloc) 739 { 740 return reloc->halt; 741 } 742 743 void 744 ftl_reloc_halt(struct ftl_reloc *reloc) 745 { 746 reloc->halt = true; 747 } 748 749 void 750 ftl_reloc_resume(struct ftl_reloc *reloc) 751 { 752 reloc->halt = false; 753 } 754 755 void 756 ftl_reloc(struct ftl_reloc *reloc) 757 { 758 struct ftl_band_reloc *breloc, *tbreloc; 759 760 if (ftl_reloc_is_halted(reloc)) { 761 return; 762 } 763 764 /* Process first band from priority queue and return */ 765 breloc = TAILQ_FIRST(&reloc->prio_queue); 766 if (breloc) { 767 if (!breloc->active) { 768 ftl_reloc_prep(breloc); 769 } 770 ftl_process_reloc(breloc); 771 return; 772 } 773 774 TAILQ_FOREACH_SAFE(breloc, &reloc->pending_queue, entry, tbreloc) { 775 if (reloc->num_active == reloc->max_active) { 776 break; 777 } 778 779 /* TODO: Add handling relocation on open bands */ 780 if (breloc->band->state != FTL_BAND_STATE_CLOSED) { 781 continue; 782 } 783 784 ftl_reloc_add_active_queue(breloc); 785 } 786 787 TAILQ_FOREACH_SAFE(breloc, &reloc->active_queue, entry, tbreloc) { 788 ftl_process_reloc(breloc); 789 } 790 } 791 792 void 793 ftl_reloc_add(struct ftl_reloc *reloc, struct ftl_band *band, size_t offset, 794 size_t num_lbks, int prio, bool is_defrag) 795 { 796 struct ftl_band_reloc *breloc = &reloc->brelocs[band->id]; 797 size_t i, prev_lbks = breloc->num_lbks; 798 799 /* No need to add anything if already at high prio - whole band should be relocated */ 800 if (!prio && band->high_prio) { 801 return; 802 } 803 804 pthread_spin_lock(&band->lba_map.lock); 805 if (band->lba_map.num_vld == 0) { 806 pthread_spin_unlock(&band->lba_map.lock); 807 808 /* If the band is closed and has no valid blocks, free it */ 809 if (band->state == FTL_BAND_STATE_CLOSED) { 810 ftl_band_set_state(band, FTL_BAND_STATE_FREE); 811 } 812 813 return; 814 } 815 pthread_spin_unlock(&band->lba_map.lock); 816 817 for (i = offset; i < offset + num_lbks; ++i) { 818 if (spdk_bit_array_get(breloc->reloc_map, i)) { 819 continue; 820 } 821 spdk_bit_array_set(breloc->reloc_map, i); 822 breloc->num_lbks++; 823 } 824 825 if (!prio && prev_lbks == breloc->num_lbks) { 826 return; 827 } 828 829 /* If the band is coming from the defrag process, mark it appropriately */ 830 if (is_defrag) { 831 assert(offset == 0 && num_lbks == ftl_num_band_lbks(band->dev)); 832 reloc->num_defrag_bands++; 833 breloc->defrag = true; 834 } 835 836 if (!prev_lbks && !prio && !breloc->active) { 837 TAILQ_INSERT_HEAD(&reloc->pending_queue, breloc, entry); 838 } 839 840 if (prio) { 841 struct ftl_band_reloc *iter_breloc; 842 843 /* If priority band is already on pending or active queue, remove it from it */ 844 TAILQ_FOREACH(iter_breloc, &reloc->pending_queue, entry) { 845 if (breloc == iter_breloc) { 846 TAILQ_REMOVE(&reloc->pending_queue, breloc, entry); 847 break; 848 } 849 } 850 851 TAILQ_FOREACH(iter_breloc, &reloc->active_queue, entry) { 852 if (breloc == iter_breloc) { 853 TAILQ_REMOVE(&reloc->active_queue, breloc, entry); 854 break; 855 } 856 } 857 858 TAILQ_INSERT_TAIL(&reloc->prio_queue, breloc, entry); 859 ftl_band_acquire_lba_map(breloc->band); 860 } 861 } 862