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 enum ftl_band_reloc_state { 58 FTL_BAND_RELOC_STATE_INACTIVE, 59 FTL_BAND_RELOC_STATE_PENDING, 60 FTL_BAND_RELOC_STATE_ACTIVE, 61 FTL_BAND_RELOC_STATE_HIGH_PRIO 62 }; 63 64 struct ftl_reloc_move { 65 struct ftl_band_reloc *breloc; 66 67 /* Start addr */ 68 struct ftl_addr addr; 69 70 /* Number of logical blocks */ 71 size_t num_blocks; 72 73 /* Data buffer */ 74 void *data; 75 76 /* Move state (read lba_map, read, write) */ 77 enum ftl_reloc_move_state state; 78 79 /* IO associated with move */ 80 struct ftl_io *io; 81 }; 82 83 struct ftl_band_reloc { 84 struct ftl_reloc *parent; 85 86 /* Band being relocated */ 87 struct ftl_band *band; 88 89 /* Number of logical blocks to be relocated */ 90 size_t num_blocks; 91 92 /* Bitmap of logical blocks to be relocated */ 93 struct spdk_bit_array *reloc_map; 94 95 /* State of the band reloc */ 96 enum ftl_band_reloc_state state; 97 98 /* The band is being defragged */ 99 bool defrag; 100 101 /* Reloc map iterator */ 102 struct { 103 /* Array of zone offsets */ 104 size_t *zone_offset; 105 106 /* Current zone */ 107 size_t zone_current; 108 } iter; 109 110 /* Number of outstanding moves */ 111 size_t num_outstanding; 112 113 /* Pool of move objects */ 114 struct ftl_reloc_move *moves; 115 116 /* Move queue */ 117 struct spdk_ring *move_queue; 118 119 TAILQ_ENTRY(ftl_band_reloc) entry; 120 }; 121 122 struct ftl_reloc { 123 /* Device associated with relocate */ 124 struct spdk_ftl_dev *dev; 125 126 /* Indicates relocate is about to halt */ 127 bool halt; 128 129 /* Maximum number of IOs per band */ 130 size_t max_qdepth; 131 132 /* Maximum number of active band relocates */ 133 size_t max_active; 134 135 /* Maximum transfer size (in logical blocks) per single IO */ 136 size_t xfer_size; 137 /* Number of bands being defragged */ 138 size_t num_defrag_bands; 139 140 /* Array of band relocates */ 141 struct ftl_band_reloc *brelocs; 142 143 /* Number of active/priority band relocates */ 144 size_t num_active; 145 146 /* Priority band relocates queue */ 147 TAILQ_HEAD(, ftl_band_reloc) prio_queue; 148 149 /* Active band relocates queue */ 150 TAILQ_HEAD(, ftl_band_reloc) active_queue; 151 152 /* Pending band relocates queue */ 153 TAILQ_HEAD(, ftl_band_reloc) pending_queue; 154 }; 155 156 bool 157 ftl_reloc_is_defrag_active(const struct ftl_reloc *reloc) 158 { 159 return reloc->num_defrag_bands > 0; 160 } 161 162 static size_t 163 ftl_reloc_iter_zone_offset(struct ftl_band_reloc *breloc) 164 { 165 size_t zone = breloc->iter.zone_current; 166 167 return breloc->iter.zone_offset[zone]; 168 } 169 170 static size_t 171 ftl_reloc_iter_zone_done(struct ftl_band_reloc *breloc) 172 { 173 size_t num_blocks = ftl_get_num_blocks_in_zone(breloc->parent->dev); 174 175 return ftl_reloc_iter_zone_offset(breloc) == num_blocks; 176 } 177 178 static void 179 ftl_reloc_clr_block(struct ftl_band_reloc *breloc, size_t block_off) 180 { 181 if (!spdk_bit_array_get(breloc->reloc_map, block_off)) { 182 return; 183 } 184 185 spdk_bit_array_clear(breloc->reloc_map, block_off); 186 assert(breloc->num_blocks); 187 breloc->num_blocks--; 188 } 189 190 static void 191 ftl_reloc_read_lba_map_cb(struct ftl_io *io, void *arg, int status) 192 { 193 struct ftl_reloc_move *move = arg; 194 struct ftl_band_reloc *breloc = move->breloc; 195 196 breloc->num_outstanding--; 197 assert(status == 0); 198 move->state = FTL_RELOC_STATE_WRITE; 199 spdk_ring_enqueue(breloc->move_queue, (void **)&move, 1, NULL); 200 } 201 202 static int 203 ftl_reloc_read_lba_map(struct ftl_band_reloc *breloc, struct ftl_reloc_move *move) 204 { 205 struct ftl_band *band = breloc->band; 206 207 breloc->num_outstanding++; 208 return ftl_band_read_lba_map(band, ftl_band_block_offset_from_addr(band, move->addr), 209 move->num_blocks, ftl_reloc_read_lba_map_cb, move); 210 } 211 212 static void 213 ftl_reloc_prep(struct ftl_band_reloc *breloc) 214 { 215 struct ftl_band *band = breloc->band; 216 struct ftl_reloc *reloc = breloc->parent; 217 struct ftl_reloc_move *move; 218 size_t i; 219 220 reloc->num_active++; 221 222 if (!band->high_prio) { 223 if (band->lba_map.ref_cnt == 0) { 224 if (ftl_band_alloc_lba_map(band)) { 225 assert(false); 226 } 227 } else { 228 ftl_band_acquire_lba_map(band); 229 } 230 } else { 231 ftl_band_acquire_lba_map(band); 232 } 233 234 for (i = 0; i < reloc->max_qdepth; ++i) { 235 move = &breloc->moves[i]; 236 move->state = FTL_RELOC_STATE_READ; 237 spdk_ring_enqueue(breloc->move_queue, (void **)&move, 1, NULL); 238 } 239 } 240 241 static void 242 ftl_reloc_free_move(struct ftl_band_reloc *breloc, struct ftl_reloc_move *move) 243 { 244 assert(move); 245 spdk_dma_free(move->data); 246 memset(move, 0, sizeof(*move)); 247 move->state = FTL_RELOC_STATE_READ; 248 spdk_ring_enqueue(breloc->move_queue, (void **)&move, 1, NULL); 249 } 250 251 static void 252 ftl_reloc_write_cb(struct ftl_io *io, void *arg, int status) 253 { 254 struct ftl_reloc_move *move = arg; 255 struct ftl_addr addr = move->addr; 256 struct ftl_band_reloc *breloc = move->breloc; 257 size_t i; 258 259 breloc->num_outstanding--; 260 261 if (status) { 262 SPDK_ERRLOG("Reloc write failed with status: %d\n", status); 263 assert(false); 264 return; 265 } 266 267 for (i = 0; i < move->num_blocks; ++i) { 268 addr.offset = move->addr.offset + i; 269 size_t block_off = ftl_band_block_offset_from_addr(breloc->band, addr); 270 ftl_reloc_clr_block(breloc, block_off); 271 } 272 273 ftl_reloc_free_move(breloc, move); 274 } 275 276 static void 277 ftl_reloc_read_cb(struct ftl_io *io, void *arg, int status) 278 { 279 struct ftl_reloc_move *move = arg; 280 struct ftl_band_reloc *breloc = move->breloc; 281 282 breloc->num_outstanding--; 283 284 /* TODO: We should handle fail on relocation read. We need to inform */ 285 /* user that this group of blocks is bad (update l2p with bad block address and */ 286 /* put it to lba_map/sector_lba). Maybe we could also retry read with smaller granularity? */ 287 if (status) { 288 SPDK_ERRLOG("Reloc read failed with status: %d\n", status); 289 assert(false); 290 return; 291 } 292 293 move->state = FTL_RELOC_STATE_READ_LBA_MAP; 294 move->io = NULL; 295 spdk_ring_enqueue(breloc->move_queue, (void **)&move, 1, NULL); 296 } 297 298 static void 299 ftl_reloc_iter_reset(struct ftl_band_reloc *breloc) 300 { 301 memset(breloc->iter.zone_offset, 0, ftl_get_num_punits(breloc->band->dev) * 302 sizeof(*breloc->iter.zone_offset)); 303 breloc->iter.zone_current = 0; 304 } 305 306 static size_t 307 ftl_reloc_iter_block_offset(struct ftl_band_reloc *breloc) 308 { 309 size_t zone_offset = breloc->iter.zone_current * ftl_get_num_blocks_in_zone(breloc->parent->dev); 310 311 return breloc->iter.zone_offset[breloc->iter.zone_current] + zone_offset; 312 } 313 314 static void 315 ftl_reloc_iter_next_zone(struct ftl_band_reloc *breloc) 316 { 317 size_t num_zones = ftl_get_num_punits(breloc->band->dev); 318 319 breloc->iter.zone_current = (breloc->iter.zone_current + 1) % num_zones; 320 } 321 322 static int 323 ftl_reloc_block_valid(struct ftl_band_reloc *breloc, size_t block_off) 324 { 325 struct ftl_addr addr = ftl_band_addr_from_block_offset(breloc->band, block_off); 326 327 return ftl_addr_is_written(breloc->band, addr) && 328 spdk_bit_array_get(breloc->reloc_map, block_off) && 329 ftl_band_block_offset_valid(breloc->band, block_off); 330 } 331 332 static int 333 ftl_reloc_iter_next(struct ftl_band_reloc *breloc, size_t *block_off) 334 { 335 size_t zone = breloc->iter.zone_current; 336 337 *block_off = ftl_reloc_iter_block_offset(breloc); 338 339 if (ftl_reloc_iter_zone_done(breloc)) { 340 return 0; 341 } 342 343 breloc->iter.zone_offset[zone]++; 344 345 if (!ftl_reloc_block_valid(breloc, *block_off)) { 346 ftl_reloc_clr_block(breloc, *block_off); 347 return 0; 348 } 349 350 return 1; 351 } 352 353 static int 354 ftl_reloc_first_valid_block(struct ftl_band_reloc *breloc, size_t *block_off) 355 { 356 size_t i, num_blocks = ftl_get_num_blocks_in_zone(breloc->parent->dev); 357 358 for (i = ftl_reloc_iter_zone_offset(breloc); i < num_blocks; ++i) { 359 if (ftl_reloc_iter_next(breloc, block_off)) { 360 return 1; 361 } 362 } 363 364 return 0; 365 } 366 367 static int 368 ftl_reloc_iter_done(struct ftl_band_reloc *breloc) 369 { 370 size_t i; 371 size_t num_zones = ftl_get_num_punits(breloc->band->dev); 372 size_t num_blocks = ftl_get_num_blocks_in_zone(breloc->parent->dev); 373 374 for (i = 0; i < num_zones; ++i) { 375 if (breloc->iter.zone_offset[i] != num_blocks) { 376 return 0; 377 } 378 } 379 380 return 1; 381 } 382 383 static size_t 384 ftl_reloc_find_valid_blocks(struct ftl_band_reloc *breloc, 385 size_t _num_blocks, struct ftl_addr *addr) 386 { 387 size_t block_off, num_blocks = 0; 388 389 if (!ftl_reloc_first_valid_block(breloc, &block_off)) { 390 return 0; 391 } 392 393 *addr = ftl_band_addr_from_block_offset(breloc->band, block_off); 394 395 for (num_blocks = 1; num_blocks < _num_blocks; num_blocks++) { 396 if (!ftl_reloc_iter_next(breloc, &block_off)) { 397 break; 398 } 399 } 400 401 return num_blocks; 402 } 403 404 static size_t 405 ftl_reloc_next_blocks(struct ftl_band_reloc *breloc, struct ftl_addr *addr) 406 { 407 size_t i, num_blocks = 0; 408 struct spdk_ftl_dev *dev = breloc->parent->dev; 409 410 for (i = 0; i < ftl_get_num_punits(dev); ++i) { 411 num_blocks = ftl_reloc_find_valid_blocks(breloc, breloc->parent->xfer_size, addr); 412 ftl_reloc_iter_next_zone(breloc); 413 414 if (num_blocks || ftl_reloc_iter_done(breloc)) { 415 break; 416 } 417 } 418 419 return num_blocks; 420 } 421 422 static struct ftl_io * 423 ftl_reloc_io_init(struct ftl_band_reloc *breloc, struct ftl_reloc_move *move, 424 ftl_io_fn fn, enum ftl_io_type io_type, int flags) 425 { 426 size_t block_off, i; 427 struct ftl_addr addr = move->addr; 428 struct ftl_io *io = NULL; 429 struct ftl_io_init_opts opts = { 430 .dev = breloc->parent->dev, 431 .band = breloc->band, 432 .size = sizeof(*io), 433 .flags = flags | FTL_IO_INTERNAL | FTL_IO_PHYSICAL_MODE, 434 .type = io_type, 435 .num_blocks = move->num_blocks, 436 .data = move->data, 437 .cb_fn = fn, 438 }; 439 440 io = ftl_io_init_internal(&opts); 441 if (!io) { 442 return NULL; 443 } 444 445 io->cb_ctx = move; 446 io->addr = move->addr; 447 448 if (flags & FTL_IO_VECTOR_LBA) { 449 for (i = 0; i < io->num_blocks; ++i, ++addr.offset) { 450 block_off = ftl_band_block_offset_from_addr(breloc->band, addr); 451 452 if (!ftl_band_block_offset_valid(breloc->band, block_off)) { 453 io->lba.vector[i] = FTL_LBA_INVALID; 454 continue; 455 } 456 457 io->lba.vector[i] = breloc->band->lba_map.map[block_off]; 458 } 459 } 460 461 ftl_trace_lba_io_init(io->dev, io); 462 463 return io; 464 } 465 466 static int 467 ftl_reloc_write(struct ftl_band_reloc *breloc, struct ftl_reloc_move *move) 468 { 469 int io_flags = FTL_IO_WEAK | FTL_IO_VECTOR_LBA | FTL_IO_BYPASS_CACHE; 470 471 if (spdk_likely(!move->io)) { 472 move->io = ftl_reloc_io_init(breloc, move, ftl_reloc_write_cb, 473 FTL_IO_WRITE, io_flags); 474 if (!move->io) { 475 ftl_reloc_free_move(breloc, move); 476 return -ENOMEM; 477 } 478 } 479 480 breloc->num_outstanding++; 481 ftl_io_write(move->io); 482 return 0; 483 } 484 485 static int 486 ftl_reloc_read(struct ftl_band_reloc *breloc, struct ftl_reloc_move *move) 487 { 488 struct ftl_addr addr = {}; 489 490 move->num_blocks = ftl_reloc_next_blocks(breloc, &addr); 491 move->breloc = breloc; 492 move->addr = addr; 493 494 if (!move->num_blocks) { 495 return 0; 496 } 497 498 move->data = spdk_dma_malloc(FTL_BLOCK_SIZE * move->num_blocks, 4096, NULL); 499 if (!move->data) { 500 return -1; 501 } 502 503 move->io = ftl_reloc_io_init(breloc, move, ftl_reloc_read_cb, FTL_IO_READ, 0); 504 if (!move->io) { 505 ftl_reloc_free_move(breloc, move); 506 SPDK_ERRLOG("Failed to initialize io for relocation."); 507 return -1; 508 } 509 510 breloc->num_outstanding++; 511 ftl_io_read(move->io); 512 return 0; 513 } 514 515 static void 516 ftl_reloc_process_moves(struct ftl_band_reloc *breloc) 517 { 518 int rc = 0; 519 size_t i, num_moves; 520 struct ftl_reloc_move *moves[FTL_RELOC_MAX_MOVES] = {0}; 521 struct ftl_reloc *reloc = breloc->parent; 522 struct ftl_reloc_move *move; 523 524 num_moves = spdk_ring_dequeue(breloc->move_queue, (void **)moves, reloc->max_qdepth); 525 526 for (i = 0; i < num_moves; ++i) { 527 move = moves[i]; 528 assert(move != NULL); 529 switch (move->state) { 530 case FTL_RELOC_STATE_READ_LBA_MAP: 531 rc = ftl_reloc_read_lba_map(breloc, move); 532 break; 533 case FTL_RELOC_STATE_READ: 534 rc = ftl_reloc_read(breloc, move); 535 break; 536 case FTL_RELOC_STATE_WRITE: 537 rc = ftl_reloc_write(breloc, move); 538 break; 539 default: 540 assert(false); 541 break; 542 } 543 544 if (rc) { 545 SPDK_ERRLOG("Move queue processing failed\n"); 546 assert(false); 547 } 548 } 549 } 550 551 static bool 552 ftl_reloc_done(struct ftl_band_reloc *breloc) 553 { 554 return !breloc->num_outstanding && !spdk_ring_count(breloc->move_queue); 555 } 556 557 static void 558 ftl_reloc_release(struct ftl_band_reloc *breloc) 559 { 560 struct ftl_reloc *reloc = breloc->parent; 561 struct ftl_band *band = breloc->band; 562 563 ftl_reloc_iter_reset(breloc); 564 ftl_band_release_lba_map(band); 565 reloc->num_active--; 566 567 if (breloc->state == FTL_BAND_RELOC_STATE_HIGH_PRIO) { 568 /* High prio band must be relocated as a whole and ANM events will be ignored */ 569 assert(breloc->num_blocks == 0 && ftl_band_empty(band)); 570 TAILQ_REMOVE(&reloc->prio_queue, breloc, entry); 571 band->high_prio = 0; 572 breloc->state = FTL_BAND_RELOC_STATE_INACTIVE; 573 } else { 574 assert(breloc->state == FTL_BAND_RELOC_STATE_ACTIVE); 575 TAILQ_REMOVE(&reloc->active_queue, breloc, entry); 576 breloc->state = FTL_BAND_RELOC_STATE_INACTIVE; 577 578 /* If we got ANM event during relocation put such band back to pending queue */ 579 if (breloc->num_blocks != 0) { 580 breloc->state = FTL_BAND_RELOC_STATE_PENDING; 581 TAILQ_INSERT_TAIL(&reloc->pending_queue, breloc, entry); 582 return; 583 } 584 } 585 586 if (ftl_band_empty(band) && band->state == FTL_BAND_STATE_CLOSED) { 587 ftl_band_set_state(breloc->band, FTL_BAND_STATE_FREE); 588 589 if (breloc->defrag) { 590 breloc->defrag = false; 591 assert(reloc->num_defrag_bands > 0); 592 reloc->num_defrag_bands--; 593 } 594 } 595 } 596 597 static void 598 ftl_process_reloc(struct ftl_band_reloc *breloc) 599 { 600 ftl_reloc_process_moves(breloc); 601 602 if (ftl_reloc_done(breloc)) { 603 ftl_reloc_release(breloc); 604 } 605 } 606 607 static int 608 ftl_band_reloc_init(struct ftl_reloc *reloc, struct ftl_band_reloc *breloc, 609 struct ftl_band *band) 610 { 611 breloc->band = band; 612 breloc->parent = reloc; 613 614 breloc->reloc_map = spdk_bit_array_create(ftl_get_num_blocks_in_band(reloc->dev)); 615 if (!breloc->reloc_map) { 616 SPDK_ERRLOG("Failed to initialize reloc map"); 617 return -1; 618 } 619 620 breloc->iter.zone_offset = calloc(ftl_get_num_punits(band->dev), 621 sizeof(*breloc->iter.zone_offset)); 622 if (!breloc->iter.zone_offset) { 623 SPDK_ERRLOG("Failed to initialize reloc iterator"); 624 return -1; 625 } 626 627 breloc->move_queue = spdk_ring_create(SPDK_RING_TYPE_MP_SC, 628 reloc->max_qdepth * 2, 629 SPDK_ENV_SOCKET_ID_ANY); 630 if (!breloc->move_queue) { 631 SPDK_ERRLOG("Failed to initialize reloc write queue"); 632 return -1; 633 } 634 635 breloc->moves = calloc(reloc->max_qdepth, sizeof(*breloc->moves)); 636 if (!breloc->moves) { 637 return -1; 638 } 639 640 return 0; 641 } 642 643 static void 644 ftl_band_reloc_free(struct ftl_band_reloc *breloc) 645 { 646 struct ftl_reloc *reloc; 647 struct ftl_reloc_move *moves[FTL_RELOC_MAX_MOVES] = {}; 648 size_t i, num_moves; 649 650 if (!breloc) { 651 return; 652 } 653 654 assert(breloc->num_outstanding == 0); 655 reloc = breloc->parent; 656 657 /* Drain write queue if there is active band relocation during shutdown */ 658 if (breloc->state == FTL_BAND_RELOC_STATE_ACTIVE || 659 breloc->state == FTL_BAND_RELOC_STATE_HIGH_PRIO) { 660 assert(reloc->halt); 661 num_moves = spdk_ring_dequeue(breloc->move_queue, (void **)&moves, reloc->max_qdepth); 662 for (i = 0; i < num_moves; ++i) { 663 ftl_reloc_free_move(breloc, moves[i]); 664 } 665 } 666 667 spdk_ring_free(breloc->move_queue); 668 spdk_bit_array_free(&breloc->reloc_map); 669 free(breloc->iter.zone_offset); 670 free(breloc->moves); 671 } 672 673 struct ftl_reloc * 674 ftl_reloc_init(struct spdk_ftl_dev *dev) 675 { 676 struct ftl_reloc *reloc; 677 size_t i; 678 679 reloc = calloc(1, sizeof(*reloc)); 680 if (!reloc) { 681 return NULL; 682 } 683 684 reloc->dev = dev; 685 reloc->halt = true; 686 reloc->max_qdepth = dev->conf.max_reloc_qdepth; 687 reloc->max_active = dev->conf.max_active_relocs; 688 reloc->xfer_size = dev->xfer_size; 689 reloc->num_defrag_bands = 0; 690 691 if (reloc->max_qdepth > FTL_RELOC_MAX_MOVES) { 692 goto error; 693 } 694 695 reloc->brelocs = calloc(ftl_get_num_bands(dev), sizeof(*reloc->brelocs)); 696 if (!reloc->brelocs) { 697 goto error; 698 } 699 700 for (i = 0; i < ftl_get_num_bands(reloc->dev); ++i) { 701 if (ftl_band_reloc_init(reloc, &reloc->brelocs[i], &dev->bands[i])) { 702 goto error; 703 } 704 } 705 706 TAILQ_INIT(&reloc->pending_queue); 707 TAILQ_INIT(&reloc->active_queue); 708 TAILQ_INIT(&reloc->prio_queue); 709 710 return reloc; 711 error: 712 ftl_reloc_free(reloc); 713 return NULL; 714 } 715 716 void 717 ftl_reloc_free(struct ftl_reloc *reloc) 718 { 719 size_t i; 720 721 if (!reloc) { 722 return; 723 } 724 725 for (i = 0; i < ftl_get_num_bands(reloc->dev); ++i) { 726 ftl_band_reloc_free(&reloc->brelocs[i]); 727 } 728 729 free(reloc->brelocs); 730 free(reloc); 731 } 732 733 bool 734 ftl_reloc_is_halted(const struct ftl_reloc *reloc) 735 { 736 return reloc->halt; 737 } 738 739 void 740 ftl_reloc_halt(struct ftl_reloc *reloc) 741 { 742 reloc->halt = true; 743 } 744 745 void 746 ftl_reloc_resume(struct ftl_reloc *reloc) 747 { 748 reloc->halt = false; 749 } 750 751 void 752 ftl_reloc(struct ftl_reloc *reloc) 753 { 754 struct ftl_band_reloc *breloc, *tbreloc; 755 756 if (ftl_reloc_is_halted(reloc)) { 757 return; 758 } 759 760 /* Process first band from priority queue and return */ 761 breloc = TAILQ_FIRST(&reloc->prio_queue); 762 if (breloc) { 763 ftl_process_reloc(breloc); 764 return; 765 } 766 767 TAILQ_FOREACH_SAFE(breloc, &reloc->pending_queue, entry, tbreloc) { 768 if (reloc->num_active == reloc->max_active) { 769 break; 770 } 771 772 /* TODO: Add handling relocation on open bands */ 773 if (breloc->band->state != FTL_BAND_STATE_CLOSED) { 774 continue; 775 } 776 777 ftl_reloc_prep(breloc); 778 assert(breloc->state == FTL_BAND_RELOC_STATE_PENDING); 779 TAILQ_REMOVE(&reloc->pending_queue, breloc, entry); 780 breloc->state = FTL_BAND_RELOC_STATE_ACTIVE; 781 TAILQ_INSERT_HEAD(&reloc->active_queue, breloc, entry); 782 } 783 784 TAILQ_FOREACH_SAFE(breloc, &reloc->active_queue, entry, tbreloc) { 785 assert(breloc->state == FTL_BAND_RELOC_STATE_ACTIVE); 786 ftl_process_reloc(breloc); 787 } 788 } 789 790 void 791 ftl_reloc_add(struct ftl_reloc *reloc, struct ftl_band *band, size_t offset, 792 size_t num_blocks, int prio, bool is_defrag) 793 { 794 struct ftl_band_reloc *breloc = &reloc->brelocs[band->id]; 795 size_t i; 796 797 /* No need to add anything if already at high prio - whole band should be relocated */ 798 if (!prio && band->high_prio) { 799 return; 800 } 801 802 pthread_spin_lock(&band->lba_map.lock); 803 if (band->lba_map.num_vld == 0) { 804 pthread_spin_unlock(&band->lba_map.lock); 805 806 /* If the band is closed and has no valid blocks, free it */ 807 if (band->state == FTL_BAND_STATE_CLOSED) { 808 ftl_band_set_state(band, FTL_BAND_STATE_FREE); 809 } 810 811 return; 812 } 813 pthread_spin_unlock(&band->lba_map.lock); 814 815 for (i = offset; i < offset + num_blocks; ++i) { 816 if (spdk_bit_array_get(breloc->reloc_map, i)) { 817 continue; 818 } 819 spdk_bit_array_set(breloc->reloc_map, i); 820 breloc->num_blocks++; 821 } 822 823 /* If the band is coming from the defrag process, mark it appropriately */ 824 if (is_defrag) { 825 assert(offset == 0 && num_blocks == ftl_get_num_blocks_in_band(band->dev)); 826 reloc->num_defrag_bands++; 827 breloc->defrag = true; 828 } 829 830 if (!prio) { 831 if (breloc->state == FTL_BAND_RELOC_STATE_INACTIVE) { 832 breloc->state = FTL_BAND_RELOC_STATE_PENDING; 833 TAILQ_INSERT_HEAD(&reloc->pending_queue, breloc, entry); 834 } 835 } else { 836 bool active = false; 837 /* If priority band is already on pending or active queue, remove it from it */ 838 switch (breloc->state) { 839 case FTL_BAND_RELOC_STATE_PENDING: 840 TAILQ_REMOVE(&reloc->pending_queue, breloc, entry); 841 break; 842 case FTL_BAND_RELOC_STATE_ACTIVE: 843 active = true; 844 TAILQ_REMOVE(&reloc->active_queue, breloc, entry); 845 break; 846 default: 847 break; 848 } 849 850 breloc->state = FTL_BAND_RELOC_STATE_HIGH_PRIO; 851 TAILQ_INSERT_TAIL(&reloc->prio_queue, breloc, entry); 852 853 /* 854 * If band has been already on active queue it doesn't need any additional 855 * resources 856 */ 857 if (!active) { 858 ftl_reloc_prep(breloc); 859 } 860 } 861 } 862