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