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 #include "ftl_reloc.h" 38 #include "ftl_core.h" 39 #include "ftl_io.h" 40 #include "ftl_rwb.h" 41 #include "ftl_band.h" 42 #include "ftl_debug.h" 43 44 struct ftl_reloc; 45 struct ftl_band_reloc; 46 47 typedef int (*ftl_reloc_fn)(struct ftl_band_reloc *, struct ftl_io *); 48 49 struct ftl_band_reloc { 50 struct ftl_reloc *parent; 51 52 /* Band being relocated */ 53 struct ftl_band *band; 54 55 /* Number of logical blocks to be relocated */ 56 size_t num_lbks; 57 58 /* Bitmap of logical blocks to be relocated */ 59 struct spdk_bit_array *reloc_map; 60 61 /* Indicates band being acitvely processed */ 62 int active; 63 64 /* Reloc map iterator */ 65 struct { 66 /* Array of chunk offsets */ 67 size_t *chk_offset; 68 69 /* Currently chunk */ 70 size_t chk_current; 71 } iter; 72 73 /* Free IO queue */ 74 struct spdk_ring *free_queue; 75 76 /* Queue of IO ready to be written */ 77 struct spdk_ring *write_queue; 78 79 TAILQ_ENTRY(ftl_band_reloc) entry; 80 81 /* TODO: get rid of md_buf */ 82 void *md_buf; 83 }; 84 85 struct ftl_reloc { 86 /* Device associated with relocate */ 87 struct spdk_ftl_dev *dev; 88 89 /* Indicates relocate is about to halt */ 90 bool halt; 91 92 /* Maximum number of IOs per band */ 93 size_t max_qdepth; 94 95 /* IO buffer */ 96 struct ftl_io **io; 97 98 /* Maximum number of active band relocates */ 99 size_t max_active; 100 101 /* Maximum transfer size (in logical blocks) per single IO */ 102 size_t xfer_size; 103 104 /* Array of band relocates */ 105 struct ftl_band_reloc *brelocs; 106 107 /* Number of active/priority band relocates */ 108 size_t num_active; 109 110 /* Priority band relocates queue */ 111 TAILQ_HEAD(, ftl_band_reloc) prio_queue; 112 113 /* Active band relocates queue */ 114 TAILQ_HEAD(, ftl_band_reloc) active_queue; 115 116 /* Pending band relocates queue */ 117 TAILQ_HEAD(, ftl_band_reloc) pending_queue; 118 }; 119 120 static struct ftl_band_reloc * 121 ftl_io_get_band_reloc(struct ftl_io *io) 122 { 123 return &io->dev->reloc->brelocs[io->band->id]; 124 } 125 126 static size_t 127 ftl_reloc_iter_chk_offset(struct ftl_band_reloc *breloc) 128 { 129 size_t chunk = breloc->iter.chk_current; 130 131 return breloc->iter.chk_offset[chunk]; 132 } 133 134 static size_t 135 ftl_reloc_iter_chk_done(struct ftl_band_reloc *breloc) 136 { 137 size_t num_lbks = ftl_dev_lbks_in_chunk(breloc->parent->dev); 138 139 return ftl_reloc_iter_chk_offset(breloc) == num_lbks; 140 } 141 142 static void 143 ftl_reloc_clr_lbk(struct ftl_band_reloc *breloc, size_t lbkoff) 144 { 145 if (!spdk_bit_array_get(breloc->reloc_map, lbkoff)) { 146 return; 147 } 148 149 spdk_bit_array_clear(breloc->reloc_map, lbkoff); 150 assert(breloc->num_lbks); 151 breloc->num_lbks--; 152 } 153 154 static void 155 _ftl_reloc_prep(struct ftl_band_reloc *breloc) 156 { 157 struct ftl_io *io; 158 struct ftl_reloc *reloc = breloc->parent; 159 struct spdk_ftl_dev *dev = reloc->dev; 160 size_t i; 161 162 for (i = 0; i < reloc->max_qdepth; ++i) { 163 io = ftl_io_alloc(dev->ioch); 164 spdk_ring_enqueue(breloc->free_queue, (void **)&io, 1); 165 } 166 } 167 168 static void 169 ftl_reloc_read_lba_map_cb(void *arg, int status) 170 { 171 struct ftl_io *io = arg; 172 struct ftl_band_reloc *breloc = ftl_io_get_band_reloc(io); 173 174 assert(status == 0); 175 spdk_dma_free(breloc->md_buf); 176 _ftl_reloc_prep(breloc); 177 } 178 179 static int 180 ftl_reloc_read_lba_map(struct ftl_band_reloc *breloc) 181 { 182 struct ftl_band *band = breloc->band; 183 struct spdk_ftl_dev *dev = band->dev; 184 struct ftl_io *io = ftl_io_alloc(dev->ioch); 185 186 io->dev = dev; 187 io->band = band; 188 io->cb.ctx = io; 189 io->cb.fn = ftl_reloc_read_lba_map_cb; 190 191 breloc->md_buf = spdk_dma_zmalloc(ftl_lba_map_num_lbks(dev) * FTL_BLOCK_SIZE, 192 FTL_BLOCK_SIZE, NULL); 193 if (!breloc->md_buf) { 194 return -1; 195 } 196 197 if (ftl_band_alloc_md(band)) { 198 assert(false); 199 } 200 201 return ftl_band_read_lba_map(band, &band->md, breloc->md_buf, &io->cb); 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 210 breloc->active = 1; 211 reloc->num_active++; 212 213 if (!band->high_prio) { 214 assert(band->md.lba_map == NULL); 215 ftl_reloc_read_lba_map(breloc); 216 return; 217 } 218 219 _ftl_reloc_prep(breloc); 220 } 221 222 static void 223 ftl_reloc_free_io(struct ftl_band_reloc *breloc, struct ftl_io *io) 224 { 225 spdk_dma_free(io->iov.iov_base); 226 free(io->lbas); 227 spdk_ring_enqueue(breloc->free_queue, (void **)&io, 1); 228 } 229 230 static void 231 ftl_reloc_write_cb(void *arg, int status) 232 { 233 struct ftl_io *io = arg; 234 struct ftl_ppa ppa = io->ppa; 235 struct ftl_band_reloc *breloc = ftl_io_get_band_reloc(io); 236 size_t i; 237 238 if (status) { 239 SPDK_ERRLOG("Reloc write failed with status: %d\n", status); 240 assert(false); 241 return; 242 } 243 244 for (i = 0; i < io->lbk_cnt; ++i) { 245 ppa.lbk = io->ppa.lbk + i; 246 size_t lbkoff = ftl_band_lbkoff_from_ppa(breloc->band, ppa); 247 ftl_reloc_clr_lbk(breloc, lbkoff); 248 } 249 250 ftl_reloc_free_io(breloc, io); 251 } 252 253 static void 254 ftl_reloc_read_cb(void *arg, int status) 255 { 256 struct ftl_io *io = arg; 257 struct ftl_band_reloc *breloc = ftl_io_get_band_reloc(io); 258 259 /* TODO: We should handle fail on relocation read. We need to inform */ 260 /* user that this group of blocks is bad (update l2p with bad block address and */ 261 /* put it to lba_map/sector_lba). Maybe we could also retry read with smaller granularity? */ 262 if (status) { 263 SPDK_ERRLOG("Reloc read failed with status: %d\n", status); 264 assert(false); 265 return; 266 } 267 268 io->flags &= ~FTL_IO_INITIALIZED; 269 spdk_ring_enqueue(breloc->write_queue, (void **)&io, 1); 270 } 271 272 static void 273 ftl_reloc_iter_reset(struct ftl_band_reloc *breloc) 274 { 275 memset(breloc->iter.chk_offset, 0, ftl_dev_num_punits(breloc->band->dev) * 276 sizeof(*breloc->iter.chk_offset)); 277 breloc->iter.chk_current = 0; 278 } 279 280 static size_t 281 ftl_reloc_iter_lbkoff(struct ftl_band_reloc *breloc) 282 { 283 size_t chk_offset = breloc->iter.chk_current * ftl_dev_lbks_in_chunk(breloc->parent->dev); 284 285 return breloc->iter.chk_offset[breloc->iter.chk_current] + chk_offset; 286 } 287 288 static void 289 ftl_reloc_iter_next_chk(struct ftl_band_reloc *breloc) 290 { 291 size_t num_chk = ftl_dev_num_punits(breloc->band->dev); 292 293 breloc->iter.chk_current = (breloc->iter.chk_current + 1) % num_chk; 294 } 295 296 static int 297 ftl_reloc_lbk_valid(struct ftl_band_reloc *breloc, size_t lbkoff) 298 { 299 return spdk_bit_array_get(breloc->reloc_map, lbkoff) && 300 ftl_band_lbkoff_valid(breloc->band, lbkoff); 301 } 302 303 static int 304 ftl_reloc_iter_next(struct ftl_band_reloc *breloc, size_t *lbkoff) 305 { 306 size_t chunk = breloc->iter.chk_current; 307 308 *lbkoff = ftl_reloc_iter_lbkoff(breloc); 309 310 if (ftl_reloc_iter_chk_done(breloc)) { 311 return 0; 312 } 313 314 breloc->iter.chk_offset[chunk]++; 315 316 if (!ftl_reloc_lbk_valid(breloc, *lbkoff)) { 317 ftl_reloc_clr_lbk(breloc, *lbkoff); 318 return 0; 319 } 320 321 return 1; 322 } 323 324 static int 325 ftl_reloc_first_valid_lbk(struct ftl_band_reloc *breloc, size_t *lbkoff) 326 { 327 size_t i, num_lbks = ftl_dev_lbks_in_chunk(breloc->parent->dev); 328 329 for (i = ftl_reloc_iter_chk_offset(breloc); i < num_lbks; ++i) { 330 if (ftl_reloc_iter_next(breloc, lbkoff)) { 331 return 1; 332 } 333 } 334 335 return 0; 336 } 337 338 static int 339 ftl_reloc_iter_done(struct ftl_band_reloc *breloc) 340 { 341 size_t i; 342 size_t num_chks = ftl_dev_num_punits(breloc->band->dev); 343 size_t num_lbks = ftl_dev_lbks_in_chunk(breloc->parent->dev); 344 345 for (i = 0; i < num_chks; ++i) { 346 if (breloc->iter.chk_offset[i] != num_lbks) { 347 return 0; 348 } 349 } 350 351 return 1; 352 } 353 354 static size_t 355 ftl_reloc_find_valid_lbks(struct ftl_band_reloc *breloc, 356 size_t num_lbk, struct ftl_ppa *ppa) 357 { 358 size_t lbkoff, lbk_cnt = 0; 359 360 if (!ftl_reloc_first_valid_lbk(breloc, &lbkoff)) { 361 return 0; 362 } 363 364 *ppa = ftl_band_ppa_from_lbkoff(breloc->band, lbkoff); 365 366 for (lbk_cnt = 1; lbk_cnt < num_lbk; lbk_cnt++) { 367 if (!ftl_reloc_iter_next(breloc, &lbkoff)) { 368 break; 369 } 370 } 371 372 return lbk_cnt; 373 } 374 375 static size_t 376 ftl_reloc_next_lbks(struct ftl_band_reloc *breloc, struct ftl_ppa *ppa) 377 { 378 size_t i, lbk_cnt = 0; 379 struct spdk_ftl_dev *dev = breloc->parent->dev; 380 381 for (i = 0; i < ftl_dev_num_punits(dev); ++i) { 382 lbk_cnt = ftl_reloc_find_valid_lbks(breloc, 383 breloc->parent->xfer_size, ppa); 384 ftl_reloc_iter_next_chk(breloc); 385 386 if (lbk_cnt || ftl_reloc_iter_done(breloc)) { 387 break; 388 } 389 } 390 391 return lbk_cnt; 392 } 393 394 static void 395 ftl_reloc_io_reinit(struct ftl_io *io, struct ftl_band_reloc *breloc, 396 spdk_ftl_fn fn, enum ftl_io_type io_type, int flags) 397 { 398 size_t i; 399 uint64_t lbkoff; 400 struct ftl_ppa ppa = io->ppa; 401 402 ftl_io_reinit(io, fn, io, flags | FTL_IO_INTERNAL, io_type); 403 404 io->ppa = ppa; 405 io->band = breloc->band; 406 io->lbas = calloc(io->lbk_cnt, sizeof(uint64_t)); 407 408 for (i = 0; i < io->lbk_cnt; ++i) { 409 ppa.lbk = io->ppa.lbk + i; 410 lbkoff = ftl_band_lbkoff_from_ppa(breloc->band, ppa); 411 412 if (!ftl_band_lbkoff_valid(breloc->band, lbkoff)) { 413 io->lbas[i] = FTL_LBA_INVALID; 414 continue; 415 } 416 417 io->lbas[i] = breloc->band->md.lba_map[lbkoff]; 418 } 419 420 ftl_trace_lba_io_init(io->dev, io); 421 } 422 423 static int 424 ftl_reloc_write(struct ftl_band_reloc *breloc, struct ftl_io *io) 425 { 426 int rc; 427 428 if (!(io->flags & FTL_IO_INITIALIZED)) { 429 ftl_reloc_io_reinit(io, breloc, ftl_reloc_write_cb, 430 FTL_IO_WRITE, 431 FTL_IO_KEEP_ALIVE | FTL_IO_WEAK | FTL_IO_VECTOR_LBA); 432 } 433 434 rc = ftl_io_write(io); 435 if (rc == -EAGAIN) { 436 spdk_ring_enqueue(breloc->write_queue, (void **)&io, 1); 437 return 0; 438 } 439 440 return rc; 441 } 442 443 static int 444 ftl_reloc_io_init(struct ftl_band_reloc *breloc, struct ftl_io *io, 445 struct ftl_ppa ppa, size_t num_lbks) 446 { 447 struct ftl_io_init_opts opts = { 448 .dev = breloc->parent->dev, 449 .io = io, 450 .rwb_batch = NULL, 451 .band = breloc->band, 452 .size = sizeof(*io), 453 .flags = FTL_IO_KEEP_ALIVE | FTL_IO_INTERNAL | FTL_IO_PPA_MODE, 454 .type = FTL_IO_READ, 455 .iov_cnt = 1, 456 .req_size = num_lbks, 457 .fn = ftl_reloc_read_cb, 458 }; 459 460 opts.data = spdk_dma_malloc(PAGE_SIZE * num_lbks, PAGE_SIZE, NULL); 461 if (!opts.data) { 462 return -1; 463 } 464 465 io = ftl_io_init_internal(&opts); 466 io->ppa = ppa; 467 return 0; 468 } 469 470 static int 471 ftl_reloc_read(struct ftl_band_reloc *breloc, struct ftl_io *io) 472 { 473 struct ftl_ppa ppa; 474 size_t num_lbks; 475 476 num_lbks = ftl_reloc_next_lbks(breloc, &ppa); 477 478 if (!num_lbks) { 479 spdk_ring_enqueue(breloc->free_queue, (void **)&io, 1); 480 return 0; 481 } 482 483 if (ftl_reloc_io_init(breloc, io, ppa, num_lbks)) { 484 SPDK_ERRLOG("Failed to initialize io for relocation."); 485 return -1; 486 } 487 488 return ftl_io_read(io); 489 } 490 491 static void 492 ftl_reloc_process_queue(struct ftl_band_reloc *breloc, struct spdk_ring *queue, 493 ftl_reloc_fn fn) 494 { 495 size_t i, num_ios; 496 struct ftl_reloc *reloc = breloc->parent; 497 498 num_ios = spdk_ring_dequeue(queue, (void **)reloc->io, reloc->max_qdepth); 499 500 for (i = 0; i < num_ios; ++i) { 501 if (fn(breloc, reloc->io[i])) { 502 SPDK_ERRLOG("Reloc queue processing failed\n"); 503 assert(false); 504 } 505 } 506 } 507 508 static void 509 ftl_reloc_process_write_queue(struct ftl_band_reloc *breloc) 510 { 511 ftl_reloc_process_queue(breloc, breloc->write_queue, ftl_reloc_write); 512 } 513 514 static void 515 ftl_reloc_process_free_queue(struct ftl_band_reloc *breloc) 516 { 517 ftl_reloc_process_queue(breloc, breloc->free_queue, ftl_reloc_read); 518 } 519 520 static int 521 ftl_reloc_done(struct ftl_band_reloc *breloc) 522 { 523 struct ftl_reloc *reloc = breloc->parent; 524 525 return spdk_ring_count(breloc->free_queue) == reloc->max_qdepth; 526 } 527 528 static void 529 ftl_reloc_release_io(struct ftl_band_reloc *breloc) 530 { 531 struct ftl_reloc *reloc = breloc->parent; 532 size_t i, num_ios; 533 534 num_ios = spdk_ring_dequeue(breloc->free_queue, (void **)reloc->io, reloc->max_qdepth); 535 536 for (i = 0; i < num_ios; ++i) { 537 ftl_io_free(reloc->io[i]); 538 } 539 } 540 541 static void 542 ftl_reloc_release(struct ftl_band_reloc *breloc) 543 { 544 struct ftl_reloc *reloc = breloc->parent; 545 struct ftl_band *band = breloc->band; 546 547 if (band->high_prio) { 548 band->high_prio = 0; 549 TAILQ_REMOVE(&reloc->prio_queue, breloc, entry); 550 } else { 551 TAILQ_REMOVE(&reloc->active_queue, breloc, entry); 552 } 553 554 ftl_reloc_release_io(breloc); 555 ftl_reloc_iter_reset(breloc); 556 ftl_band_release_md(band); 557 558 breloc->active = 0; 559 reloc->num_active--; 560 561 if (breloc->num_lbks) { 562 TAILQ_INSERT_TAIL(&reloc->pending_queue, breloc, entry); 563 return; 564 } 565 566 if (ftl_band_empty(band)) { 567 ftl_band_set_state(breloc->band, FTL_BAND_STATE_FREE); 568 } 569 } 570 571 static void 572 ftl_process_reloc(struct ftl_band_reloc *breloc) 573 { 574 ftl_reloc_process_write_queue(breloc); 575 576 ftl_reloc_process_free_queue(breloc); 577 578 if (ftl_reloc_done(breloc)) { 579 ftl_reloc_release(breloc); 580 } 581 } 582 583 static int 584 ftl_band_reloc_init(struct ftl_reloc *reloc, struct ftl_band_reloc *breloc, 585 struct ftl_band *band) 586 { 587 breloc->band = band; 588 breloc->parent = reloc; 589 590 breloc->reloc_map = spdk_bit_array_create(ftl_num_band_lbks(reloc->dev)); 591 if (!breloc->reloc_map) { 592 SPDK_ERRLOG("Failed to initialize reloc map"); 593 return -1; 594 } 595 596 breloc->iter.chk_offset = calloc(ftl_dev_num_punits(band->dev), 597 sizeof(*breloc->iter.chk_offset)); 598 if (!breloc->iter.chk_offset) { 599 SPDK_ERRLOG("Failed to initialize reloc iterator"); 600 return -1; 601 } 602 603 breloc->free_queue = spdk_ring_create(SPDK_RING_TYPE_MP_SC, 604 reloc->max_qdepth * 2, 605 SPDK_ENV_SOCKET_ID_ANY); 606 if (!breloc->free_queue) { 607 SPDK_ERRLOG("Failed to initialize reloc free queue"); 608 return -1; 609 } 610 611 breloc->write_queue = spdk_ring_create(SPDK_RING_TYPE_MP_SC, 612 reloc->max_qdepth * 2, 613 SPDK_ENV_SOCKET_ID_ANY); 614 if (!breloc->write_queue) { 615 SPDK_ERRLOG("Failed to initialize reloc write queue"); 616 return -1; 617 } 618 619 return 0; 620 } 621 622 static void 623 ftl_band_reloc_free(struct ftl_band_reloc *breloc) 624 { 625 if (!breloc) { 626 return; 627 } 628 629 spdk_ring_free(breloc->free_queue); 630 spdk_ring_free(breloc->write_queue); 631 spdk_bit_array_free(&breloc->reloc_map); 632 free(breloc->iter.chk_offset); 633 } 634 635 static void 636 ftl_reloc_add_active_queue(struct ftl_band_reloc *breloc) 637 { 638 struct ftl_reloc *reloc = breloc->parent; 639 640 TAILQ_REMOVE(&reloc->pending_queue, breloc, entry); 641 TAILQ_INSERT_HEAD(&reloc->active_queue, breloc, entry); 642 ftl_reloc_prep(breloc); 643 } 644 645 struct ftl_reloc * 646 ftl_reloc_init(struct spdk_ftl_dev *dev) 647 { 648 #define POOL_NAME_LEN 128 649 struct ftl_reloc *reloc; 650 char pool_name[POOL_NAME_LEN]; 651 int rc; 652 size_t i; 653 654 reloc = calloc(1, sizeof(*reloc)); 655 if (!reloc) { 656 return NULL; 657 } 658 659 reloc->dev = dev; 660 reloc->halt = true; 661 reloc->max_qdepth = dev->conf.max_reloc_qdepth; 662 reloc->max_active = dev->conf.max_active_relocs; 663 reloc->xfer_size = dev->xfer_size; 664 665 reloc->brelocs = calloc(ftl_dev_num_bands(dev), sizeof(*reloc->brelocs)); 666 if (!reloc->brelocs) { 667 goto error; 668 } 669 670 reloc->io = calloc(reloc->max_qdepth, sizeof(*reloc->io)); 671 if (!reloc->io) { 672 goto error; 673 } 674 675 for (i = 0; i < ftl_dev_num_bands(reloc->dev); ++i) { 676 if (ftl_band_reloc_init(reloc, &reloc->brelocs[i], &dev->bands[i])) { 677 goto error; 678 } 679 } 680 681 rc = snprintf(pool_name, sizeof(pool_name), "%s-%s", dev->name, "reloc-io-pool"); 682 if (rc < 0 || rc >= POOL_NAME_LEN) { 683 return NULL; 684 } 685 686 TAILQ_INIT(&reloc->pending_queue); 687 TAILQ_INIT(&reloc->active_queue); 688 TAILQ_INIT(&reloc->prio_queue); 689 690 return reloc; 691 error: 692 ftl_reloc_free(reloc); 693 return NULL; 694 } 695 696 void 697 ftl_reloc_free(struct ftl_reloc *reloc) 698 { 699 size_t i; 700 701 if (!reloc) { 702 return; 703 } 704 705 for (i = 0; i < ftl_dev_num_bands(reloc->dev); ++i) { 706 ftl_band_reloc_free(&reloc->brelocs[i]); 707 } 708 709 free(reloc->brelocs); 710 free(reloc->io); 711 free(reloc); 712 } 713 714 bool 715 ftl_reloc_is_halted(const struct ftl_reloc *reloc) 716 { 717 return reloc->halt; 718 } 719 720 void 721 ftl_reloc_halt(struct ftl_reloc *reloc) 722 { 723 reloc->halt = true; 724 } 725 726 void 727 ftl_reloc_resume(struct ftl_reloc *reloc) 728 { 729 reloc->halt = false; 730 } 731 732 void 733 ftl_reloc(struct ftl_reloc *reloc) 734 { 735 struct ftl_band_reloc *breloc, *tbreloc; 736 737 if (ftl_reloc_is_halted(reloc)) { 738 return; 739 } 740 741 /* Process first band from priority queue and return */ 742 breloc = TAILQ_FIRST(&reloc->prio_queue); 743 if (breloc) { 744 if (!breloc->active) { 745 ftl_reloc_prep(breloc); 746 } 747 ftl_process_reloc(breloc); 748 return; 749 } 750 751 TAILQ_FOREACH_SAFE(breloc, &reloc->pending_queue, entry, tbreloc) { 752 if (reloc->num_active == reloc->max_active) { 753 break; 754 } 755 ftl_reloc_add_active_queue(breloc); 756 } 757 758 TAILQ_FOREACH_SAFE(breloc, &reloc->active_queue, entry, tbreloc) { 759 ftl_process_reloc(breloc); 760 } 761 } 762 763 void 764 ftl_reloc_add(struct ftl_reloc *reloc, struct ftl_band *band, size_t offset, 765 size_t num_lbks, int prio) 766 { 767 struct ftl_band_reloc *breloc = &reloc->brelocs[band->id]; 768 size_t i, prev_lbks = breloc->num_lbks; 769 770 for (i = offset; i < offset + num_lbks; ++i) { 771 if (spdk_bit_array_get(breloc->reloc_map, i)) { 772 continue; 773 } 774 spdk_bit_array_set(breloc->reloc_map, i); 775 breloc->num_lbks++; 776 } 777 778 if (!prev_lbks && !prio) { 779 TAILQ_INSERT_HEAD(&reloc->pending_queue, breloc, entry); 780 } 781 782 if (prio) { 783 TAILQ_INSERT_TAIL(&reloc->prio_queue, breloc, entry); 784 ftl_band_acquire_md(breloc->band); 785 } 786 } 787