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