LCOV - code coverage report
Current view: top level - lib/ftl - ftl_band.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 101 383 26.4 %
Date: 2024-12-08 21:44:16 Functions: 13 43 30.2 %

          Line data    Source code
       1             : /*   SPDX-License-Identifier: BSD-3-Clause
       2             :  *   Copyright (C) 2018 Intel Corporation.
       3             :  *   Copyright 2023 Solidigm All Rights Reserved
       4             :  *   All rights reserved.
       5             :  */
       6             : 
       7             : #include "spdk/stdinc.h"
       8             : #include "spdk/crc32.h"
       9             : #include "spdk/likely.h"
      10             : #include "spdk/util.h"
      11             : #include "spdk/ftl.h"
      12             : 
      13             : #include "ftl_band.h"
      14             : #include "ftl_io.h"
      15             : #include "ftl_core.h"
      16             : #include "ftl_debug.h"
      17             : #include "ftl_internal.h"
      18             : #include "utils/ftl_md.h"
      19             : #include "utils/ftl_defs.h"
      20             : 
      21             : static uint64_t
      22           0 : ftl_band_tail_md_offset(const struct ftl_band *band)
      23             : {
      24           0 :         return ftl_get_num_blocks_in_band(band->dev) -
      25           0 :                ftl_tail_md_num_blocks(band->dev);
      26             : }
      27             : 
      28             : int
      29           0 : ftl_band_filled(struct ftl_band *band, size_t offset)
      30             : {
      31           0 :         return offset == ftl_band_tail_md_offset(band);
      32             : }
      33             : 
      34             : static void
      35           6 : ftl_band_free_p2l_map(struct ftl_band *band)
      36             : {
      37           6 :         struct spdk_ftl_dev *dev = band->dev;
      38           6 :         struct ftl_p2l_map *p2l_map = &band->p2l_map;
      39             : 
      40           6 :         assert(band->md->state == FTL_BAND_STATE_CLOSED ||
      41             :                band->md->state == FTL_BAND_STATE_FREE);
      42           6 :         assert(p2l_map->ref_cnt == 0);
      43           6 :         assert(p2l_map->band_map != NULL);
      44             : 
      45           6 :         band->md->df_p2l_map = FTL_DF_OBJ_ID_INVALID;
      46           6 :         ftl_mempool_put(dev->p2l_pool, p2l_map->band_map);
      47           6 :         p2l_map->band_map = NULL;
      48           6 : }
      49             : 
      50             : 
      51             : static void
      52           6 : ftl_band_free_md_entry(struct ftl_band *band)
      53             : {
      54           6 :         struct spdk_ftl_dev *dev = band->dev;
      55           6 :         struct ftl_p2l_map *p2l_map = &band->p2l_map;
      56             : 
      57           6 :         assert(band->md->state == FTL_BAND_STATE_CLOSED ||
      58             :                band->md->state == FTL_BAND_STATE_FREE);
      59           6 :         assert(p2l_map->band_dma_md != NULL);
      60             : 
      61           6 :         ftl_mempool_put(dev->band_md_pool, p2l_map->band_dma_md);
      62           6 :         p2l_map->band_dma_md = NULL;
      63           6 : }
      64             : 
      65             : static void
      66           0 : _ftl_band_set_free(struct ftl_band *band)
      67             : {
      68           0 :         struct spdk_ftl_dev *dev = band->dev;
      69             : 
      70             :         /* Add the band to the free band list */
      71           0 :         TAILQ_INSERT_TAIL(&dev->free_bands, band, queue_entry);
      72           0 :         band->md->close_seq_id = 0;
      73           0 :         band->reloc = false;
      74             : 
      75           0 :         dev->num_free++;
      76           0 :         ftl_apply_limits(dev);
      77             : 
      78           0 :         band->md->p2l_map_checksum = 0;
      79           0 : }
      80             : 
      81             : static void
      82           0 : _ftl_band_set_preparing(struct ftl_band *band)
      83             : {
      84           0 :         struct spdk_ftl_dev *dev = band->dev;
      85             : 
      86             :         /* Remove band from free list */
      87           0 :         TAILQ_REMOVE(&dev->free_bands, band, queue_entry);
      88             : 
      89           0 :         band->md->wr_cnt++;
      90             : 
      91           0 :         assert(dev->num_free > 0);
      92           0 :         dev->num_free--;
      93             : 
      94           0 :         ftl_apply_limits(dev);
      95           0 : }
      96             : 
      97             : static void
      98           0 : _ftl_band_set_closed_cb(struct ftl_band *band, bool valid)
      99             : {
     100           0 :         struct spdk_ftl_dev *dev = band->dev;
     101             : 
     102           0 :         assert(valid == true);
     103             : 
     104             :         /* Set the state as free_md() checks for that */
     105           0 :         band->md->state = FTL_BAND_STATE_CLOSED;
     106           0 :         if (band->owner.state_change_fn) {
     107           0 :                 band->owner.state_change_fn(band);
     108           0 :         }
     109             : 
     110           0 :         ftl_p2l_validate_ckpt(band);
     111             : 
     112             :         /* Free the P2L map if there are no outstanding IOs */
     113           0 :         ftl_band_release_p2l_map(band);
     114           0 :         assert(band->p2l_map.ref_cnt == 0);
     115             : 
     116           0 :         TAILQ_INSERT_TAIL(&dev->shut_bands, band, queue_entry);
     117           0 : }
     118             : 
     119             : static void
     120           0 : _ftl_band_set_closed(struct ftl_band *band)
     121             : {
     122             :         /* Verify that band's metadata is consistent with l2p */
     123           0 :         ftl_band_validate_md(band, _ftl_band_set_closed_cb);
     124           0 : }
     125             : 
     126             : ftl_addr
     127           0 : ftl_band_tail_md_addr(struct ftl_band *band)
     128             : {
     129           0 :         ftl_addr addr;
     130             : 
     131             :         /* Metadata should be aligned to xfer size */
     132           0 :         assert(ftl_band_tail_md_offset(band) % band->dev->xfer_size == 0);
     133             : 
     134           0 :         addr = ftl_band_tail_md_offset(band) + band->start_addr;
     135             : 
     136           0 :         return addr;
     137           0 : }
     138             : 
     139             : const char *
     140           0 : ftl_band_get_state_name(struct ftl_band *band)
     141             : {
     142             :         static const char *names[] = {
     143             :                 "FREE", "PREPARING", "OPENING", "OPEN", "FULL", "CLOSING",
     144             :                 "CLOSED",
     145             :         };
     146             : 
     147           0 :         assert(band->md->state < SPDK_COUNTOF(names));
     148           0 :         if (band->md->state < SPDK_COUNTOF(names)) {
     149           0 :                 return names[band->md->state];
     150             :         } else {
     151           0 :                 assert(false);
     152             :                 return "?";
     153             :         }
     154             : }
     155             : 
     156             : void
     157           0 : ftl_band_set_state(struct ftl_band *band, enum ftl_band_state state)
     158             : {
     159           0 :         switch (state) {
     160             :         case FTL_BAND_STATE_FREE:
     161           0 :                 assert(band->md->state == FTL_BAND_STATE_CLOSED);
     162           0 :                 _ftl_band_set_free(band);
     163           0 :                 break;
     164             : 
     165             :         case FTL_BAND_STATE_PREP:
     166           0 :                 assert(band->md->state == FTL_BAND_STATE_FREE);
     167           0 :                 _ftl_band_set_preparing(band);
     168           0 :                 break;
     169             : 
     170             :         case FTL_BAND_STATE_CLOSED:
     171           0 :                 if (band->md->state != FTL_BAND_STATE_CLOSED) {
     172           0 :                         assert(band->md->state == FTL_BAND_STATE_CLOSING);
     173           0 :                         _ftl_band_set_closed(band);
     174           0 :                         return; /* state can be changed asynchronously */
     175             :                 }
     176           0 :                 break;
     177             : 
     178             :         case FTL_BAND_STATE_OPEN:
     179           0 :                 band->md->p2l_map_checksum = 0;
     180           0 :                 break;
     181             :         case FTL_BAND_STATE_OPENING:
     182             :         case FTL_BAND_STATE_FULL:
     183             :         case FTL_BAND_STATE_CLOSING:
     184           0 :                 break;
     185             :         default:
     186           0 :                 FTL_ERRLOG(band->dev, "Unknown band state, %u", state);
     187           0 :                 assert(false);
     188             :                 break;
     189             :         }
     190             : 
     191           0 :         band->md->state = state;
     192           0 : }
     193             : 
     194             : void
     195           0 : ftl_band_set_type(struct ftl_band *band, enum ftl_band_type type)
     196             : {
     197           0 :         switch (type) {
     198             :         case FTL_BAND_TYPE_COMPACTION:
     199             :         case FTL_BAND_TYPE_GC:
     200           0 :                 band->md->type = type;
     201           0 :                 break;
     202             :         default:
     203           0 :                 assert(false);
     204             :                 break;
     205             :         }
     206           0 : }
     207             : 
     208             : void
     209           5 : ftl_band_set_p2l(struct ftl_band *band, uint64_t lba, ftl_addr addr, uint64_t seq_id)
     210             : {
     211           5 :         struct ftl_p2l_map *p2l_map = &band->p2l_map;
     212           5 :         uint64_t offset;
     213             : 
     214           5 :         offset = ftl_band_block_offset_from_addr(band, addr);
     215             : 
     216           5 :         p2l_map->band_map[offset].lba = lba;
     217           5 :         p2l_map->band_map[offset].seq_id = seq_id;
     218           5 : }
     219             : 
     220             : void
     221           5 : ftl_band_set_addr(struct ftl_band *band, uint64_t lba, ftl_addr addr)
     222             : {
     223           5 :         band->p2l_map.num_valid++;
     224           5 :         ftl_bitmap_set(band->dev->valid_map, addr);
     225           5 : }
     226             : 
     227             : size_t
     228           0 : ftl_band_user_blocks_left(const struct ftl_band *band, size_t offset)
     229             : {
     230           0 :         size_t tail_md_offset = ftl_band_tail_md_offset(band);
     231             : 
     232           0 :         if (spdk_unlikely(offset > tail_md_offset)) {
     233           0 :                 return 0;
     234             :         }
     235             : 
     236           0 :         return tail_md_offset - offset;
     237           0 : }
     238             : 
     239             : size_t
     240           0 : ftl_band_user_blocks(const struct ftl_band *band)
     241             : {
     242           0 :         return ftl_get_num_blocks_in_band(band->dev) -
     243           0 :                ftl_tail_md_num_blocks(band->dev);
     244             : }
     245             : 
     246             : static inline uint64_t
     247       30026 : ftl_addr_get_band(const struct spdk_ftl_dev *dev, ftl_addr addr)
     248             : {
     249       30026 :         return (addr - dev->bands->start_addr) / ftl_get_num_blocks_in_band(dev);
     250             : }
     251             : 
     252             : struct ftl_band *
     253           2 : ftl_band_from_addr(struct spdk_ftl_dev *dev, ftl_addr addr)
     254             : {
     255           2 :         uint64_t band_id = ftl_addr_get_band(dev, addr);
     256             : 
     257           2 :         assert(band_id < ftl_get_num_bands(dev));
     258           2 :         return &dev->bands[band_id];
     259           2 : }
     260             : 
     261             : uint64_t
     262       20006 : ftl_band_block_offset_from_addr(struct ftl_band *band, ftl_addr addr)
     263             : {
     264       20006 :         assert(ftl_addr_get_band(band->dev, addr) == band->id);
     265       20006 :         return addr - band->start_addr;
     266             : }
     267             : 
     268             : ftl_addr
     269           3 : ftl_band_next_xfer_addr(struct ftl_band *band, ftl_addr addr, size_t num_blocks)
     270             : {
     271           3 :         struct spdk_ftl_dev *dev = band->dev;
     272           3 :         size_t num_xfers;
     273           3 :         uint64_t offset;
     274             : 
     275           3 :         assert(ftl_addr_get_band(dev, addr) == band->id);
     276             : 
     277           3 :         offset = addr - band->start_addr;
     278             : 
     279             :         /* In case starting address wasn't aligned to xfer_size, we'll align for consistent calculation
     280             :          * purposes - the unaligned value will be preserved at the end however.
     281             :          */
     282           3 :         num_blocks += (offset % dev->xfer_size);
     283           3 :         offset -= (offset % dev->xfer_size);
     284             : 
     285             :         /* Calculate offset based on xfer_size aligned writes */
     286           3 :         num_xfers = (num_blocks / dev->xfer_size);
     287           3 :         offset += num_xfers * dev->xfer_size;
     288           3 :         num_blocks -= num_xfers * dev->xfer_size;
     289             : 
     290           3 :         if (offset > ftl_get_num_blocks_in_band(dev)) {
     291           0 :                 return FTL_ADDR_INVALID;
     292             :         }
     293             : 
     294             :         /* If there's any unalignment (either starting addr value or num_blocks), reintroduce it to the final address
     295             :          */
     296           3 :         if (num_blocks) {
     297           2 :                 offset += num_blocks;
     298           2 :                 if (offset > ftl_get_num_blocks_in_band(dev)) {
     299           0 :                         return FTL_ADDR_INVALID;
     300             :                 }
     301           2 :         }
     302             : 
     303           3 :         addr = band->start_addr + offset;
     304           3 :         return addr;
     305           3 : }
     306             : 
     307             : ftl_addr
     308       10000 : ftl_band_addr_from_block_offset(struct ftl_band *band, uint64_t block_off)
     309             : {
     310       10000 :         ftl_addr addr;
     311             : 
     312       10000 :         addr = block_off + band->start_addr;
     313       20000 :         return addr;
     314       10000 : }
     315             : 
     316             : ftl_addr
     317           0 : ftl_band_next_addr(struct ftl_band *band, ftl_addr addr, size_t offset)
     318             : {
     319           0 :         uint64_t block_off = ftl_band_block_offset_from_addr(band, addr);
     320             : 
     321           0 :         return ftl_band_addr_from_block_offset(band, block_off + offset);
     322           0 : }
     323             : 
     324             : void
     325           6 : ftl_band_acquire_p2l_map(struct ftl_band *band)
     326             : {
     327           6 :         assert(band->p2l_map.band_map != NULL);
     328           6 :         band->p2l_map.ref_cnt++;
     329           6 : }
     330             : 
     331             : static int
     332           6 : ftl_band_alloc_md_entry(struct ftl_band *band)
     333             : {
     334           6 :         struct spdk_ftl_dev *dev = band->dev;
     335           6 :         struct ftl_p2l_map *p2l_map = &band->p2l_map;
     336           6 :         struct ftl_layout_region *region = ftl_layout_region_get(dev, FTL_LAYOUT_REGION_TYPE_BAND_MD);
     337             : 
     338           6 :         p2l_map->band_dma_md = ftl_mempool_get(dev->band_md_pool);
     339             : 
     340           6 :         if (!p2l_map->band_dma_md) {
     341           0 :                 return -1;
     342             :         }
     343             : 
     344           6 :         memset(p2l_map->band_dma_md, 0, region->entry_size * FTL_BLOCK_SIZE);
     345           6 :         return 0;
     346           6 : }
     347             : 
     348             : int
     349           6 : ftl_band_alloc_p2l_map(struct ftl_band *band)
     350             : {
     351           6 :         struct spdk_ftl_dev *dev = band->dev;
     352           6 :         struct ftl_p2l_map *p2l_map = &band->p2l_map;
     353             : 
     354           6 :         assert(p2l_map->ref_cnt == 0);
     355           6 :         assert(p2l_map->band_map == NULL);
     356             : 
     357           6 :         assert(band->md->df_p2l_map == FTL_DF_OBJ_ID_INVALID);
     358           6 :         p2l_map->band_map = ftl_mempool_get(dev->p2l_pool);
     359           6 :         if (!p2l_map->band_map) {
     360           0 :                 return -1;
     361             :         }
     362             : 
     363           6 :         if (ftl_band_alloc_md_entry(band)) {
     364           0 :                 ftl_band_free_p2l_map(band);
     365           0 :                 return -1;
     366             :         }
     367             : 
     368           6 :         band->md->df_p2l_map = ftl_mempool_get_df_obj_id(dev->p2l_pool, p2l_map->band_map);
     369             : 
     370             :         /* Set the P2L to FTL_LBA_INVALID */
     371           6 :         memset(p2l_map->band_map, -1, FTL_BLOCK_SIZE * ftl_p2l_map_num_blocks(band->dev));
     372             : 
     373           6 :         ftl_band_acquire_p2l_map(band);
     374           6 :         return 0;
     375           6 : }
     376             : 
     377             : int
     378           0 : ftl_band_open_p2l_map(struct ftl_band *band)
     379             : {
     380           0 :         struct spdk_ftl_dev *dev = band->dev;
     381           0 :         struct ftl_p2l_map *p2l_map = &band->p2l_map;
     382             : 
     383           0 :         assert(p2l_map->ref_cnt == 0);
     384           0 :         assert(p2l_map->band_map == NULL);
     385             : 
     386           0 :         assert(band->md->df_p2l_map != FTL_DF_OBJ_ID_INVALID);
     387             : 
     388           0 :         if (ftl_band_alloc_md_entry(band)) {
     389           0 :                 p2l_map->band_map = NULL;
     390           0 :                 return -1;
     391             :         }
     392             : 
     393           0 :         p2l_map->band_map = ftl_mempool_claim_df(dev->p2l_pool, band->md->df_p2l_map);
     394             : 
     395           0 :         ftl_band_acquire_p2l_map(band);
     396           0 :         return 0;
     397           0 : }
     398             : 
     399             : void
     400           6 : ftl_band_release_p2l_map(struct ftl_band *band)
     401             : {
     402           6 :         struct ftl_p2l_map *p2l_map = &band->p2l_map;
     403             : 
     404           6 :         assert(p2l_map->band_map != NULL);
     405           6 :         assert(p2l_map->ref_cnt > 0);
     406           6 :         p2l_map->ref_cnt--;
     407             : 
     408           6 :         if (p2l_map->ref_cnt == 0) {
     409           6 :                 if (p2l_map->p2l_ckpt) {
     410           0 :                         ftl_p2l_ckpt_release(band->dev, p2l_map->p2l_ckpt);
     411           0 :                         p2l_map->p2l_ckpt = NULL;
     412           0 :                 }
     413           6 :                 ftl_band_free_p2l_map(band);
     414           6 :                 ftl_band_free_md_entry(band);
     415           6 :         }
     416           6 : }
     417             : 
     418             : ftl_addr
     419           0 : ftl_band_p2l_map_addr(struct ftl_band *band)
     420             : {
     421           0 :         return band->tail_md_addr;
     422             : }
     423             : 
     424             : int
     425           0 : ftl_band_write_prep(struct ftl_band *band)
     426             : {
     427           0 :         struct spdk_ftl_dev *dev = band->dev;
     428             : 
     429           0 :         if (ftl_band_alloc_p2l_map(band)) {
     430           0 :                 return -1;
     431             :         }
     432             : 
     433           0 :         band->p2l_map.p2l_ckpt = ftl_p2l_ckpt_acquire(dev);
     434           0 :         band->md->p2l_md_region = ftl_p2l_ckpt_region_type(band->p2l_map.p2l_ckpt);
     435           0 :         ftl_band_iter_init(band);
     436             : 
     437           0 :         band->md->seq = ftl_get_next_seq_id(dev);
     438             : 
     439           0 :         FTL_DEBUGLOG(dev, "Band to write, id %u seq %"PRIu64"\n", band->id, band->md->seq);
     440           0 :         return 0;
     441           0 : }
     442             : 
     443             : size_t
     444           0 : ftl_p2l_map_pool_elem_size(struct spdk_ftl_dev *dev)
     445             : {
     446             :         /* Map pool element holds the whole tail md */
     447           0 :         return ftl_tail_md_num_blocks(dev) * FTL_BLOCK_SIZE;
     448             : }
     449             : 
     450             : double
     451           0 : ftl_band_invalidity(struct ftl_band *band)
     452             : {
     453           0 :         double valid = band->p2l_map.num_valid;
     454           0 :         double count = ftl_band_user_blocks(band);
     455             : 
     456           0 :         return 1.0 - (valid / count);
     457           0 : }
     458             : 
     459             : static void
     460           0 : dump_bands_under_relocation(struct spdk_ftl_dev *dev)
     461             : {
     462           0 :         uint64_t i = dev->sb_shm->gc_info.current_band_id;
     463           0 :         uint64_t end = dev->sb_shm->gc_info.current_band_id + dev->num_logical_bands_in_physical;
     464             : 
     465           0 :         for (; i < end; i++) {
     466           0 :                 struct ftl_band *band = &dev->bands[i];
     467             : 
     468           0 :                 FTL_DEBUGLOG(dev, "Band, id %u, phys_is %u, wr cnt = %u, invalidity = %u%%\n",
     469             :                              band->id, band->phys_id, (uint32_t)band->md->wr_cnt,
     470             :                              (uint32_t)(ftl_band_invalidity(band) * 100));
     471           0 :         }
     472           0 : }
     473             : 
     474             : static bool
     475           0 : is_band_relocateable(struct ftl_band *band)
     476             : {
     477             :         /* Can only move data from closed bands */
     478           0 :         if (FTL_BAND_STATE_CLOSED != band->md->state) {
     479           0 :                 return false;
     480             :         }
     481             : 
     482             :         /* Band is already under relocation, skip it */
     483           0 :         if (band->reloc) {
     484           0 :                 return false;
     485             :         }
     486             : 
     487           0 :         return true;
     488           0 : }
     489             : 
     490             : static void
     491           0 : get_band_phys_info(struct spdk_ftl_dev *dev, uint64_t phys_id,
     492             :                    double *invalidity, double *wr_cnt)
     493             : {
     494           0 :         struct ftl_band *band;
     495           0 :         uint64_t band_id = phys_id * dev->num_logical_bands_in_physical;
     496             : 
     497           0 :         *wr_cnt = *invalidity = 0.0L;
     498           0 :         for (; band_id < ftl_get_num_bands(dev); band_id++) {
     499           0 :                 band = &dev->bands[band_id];
     500             : 
     501           0 :                 if (phys_id != band->phys_id) {
     502           0 :                         break;
     503             :                 }
     504             : 
     505           0 :                 *wr_cnt += band->md->wr_cnt;
     506             : 
     507           0 :                 if (!is_band_relocateable(band)) {
     508           0 :                         continue;
     509             :                 }
     510             : 
     511           0 :                 *invalidity += ftl_band_invalidity(band);
     512           0 :         }
     513             : 
     514           0 :         *invalidity /= dev->num_logical_bands_in_physical;
     515           0 :         *wr_cnt /= dev->num_logical_bands_in_physical;
     516           0 : }
     517             : 
     518             : static bool
     519           0 : band_cmp(double a_invalidity, double a_wr_cnt,
     520             :          double b_invalidity, double b_wr_cnt,
     521             :          uint64_t a_id, uint64_t b_id)
     522             : {
     523           0 :         assert(a_id != FTL_BAND_PHYS_ID_INVALID);
     524           0 :         assert(b_id != FTL_BAND_PHYS_ID_INVALID);
     525           0 :         double diff = a_invalidity - b_invalidity;
     526           0 :         if (diff < 0.0L) {
     527           0 :                 diff *= -1.0L;
     528           0 :         }
     529             : 
     530             :         /* Use the following metrics for picking bands for GC (in order):
     531             :          * - relative invalidity
     532             :          * - if invalidity is similar (within 10% points), then their write counts (how many times band was written to)
     533             :          * - if write count is equal, then pick based on their placement on base device (lower LBAs win)
     534             :          */
     535           0 :         if (diff > 0.1L) {
     536           0 :                 return a_invalidity > b_invalidity;
     537             :         }
     538             : 
     539           0 :         if (a_wr_cnt != b_wr_cnt) {
     540           0 :                 return a_wr_cnt < b_wr_cnt;
     541             :         }
     542             : 
     543           0 :         return a_id < b_id;
     544           0 : }
     545             : 
     546             : static void
     547           0 : band_start_gc(struct spdk_ftl_dev *dev, struct ftl_band *band)
     548             : {
     549           0 :         ftl_bug(false == is_band_relocateable(band));
     550             : 
     551           0 :         TAILQ_REMOVE(&dev->shut_bands, band, queue_entry);
     552           0 :         band->reloc = true;
     553             : 
     554           0 :         FTL_DEBUGLOG(dev, "Band to GC, id %u\n", band->id);
     555           0 : }
     556             : 
     557             : static struct ftl_band *
     558           0 : gc_high_priority_band(struct spdk_ftl_dev *dev)
     559             : {
     560           0 :         struct ftl_band *band;
     561           0 :         uint64_t high_prio_id = dev->sb_shm->gc_info.band_id_high_prio;
     562             : 
     563           0 :         if (FTL_BAND_ID_INVALID != high_prio_id) {
     564           0 :                 ftl_bug(high_prio_id >= dev->num_bands);
     565             : 
     566           0 :                 band = &dev->bands[high_prio_id];
     567           0 :                 dev->sb_shm->gc_info.band_id_high_prio = FTL_BAND_ID_INVALID;
     568             : 
     569           0 :                 band_start_gc(dev, band);
     570           0 :                 FTL_NOTICELOG(dev, "GC takes high priority band, id %u\n", band->id);
     571           0 :                 return band;
     572             :         }
     573             : 
     574           0 :         return 0;
     575           0 : }
     576             : 
     577             : static void
     578           0 : ftl_band_reset_gc_iter(struct spdk_ftl_dev *dev)
     579             : {
     580           0 :         dev->sb->gc_info.is_valid = 0;
     581           0 :         dev->sb->gc_info.current_band_id = FTL_BAND_ID_INVALID;
     582           0 :         dev->sb->gc_info.band_id_high_prio = FTL_BAND_ID_INVALID;
     583           0 :         dev->sb->gc_info.band_phys_id = FTL_BAND_PHYS_ID_INVALID;
     584             : 
     585           0 :         dev->sb_shm->gc_info = dev->sb->gc_info;
     586           0 : }
     587             : 
     588             : struct ftl_band *
     589           0 : ftl_band_search_next_to_reloc(struct spdk_ftl_dev *dev)
     590             : {
     591           0 :         double invalidity, max_invalidity = 0.0L;
     592           0 :         double wr_cnt, max_wr_cnt = 0.0L;
     593           0 :         uint64_t phys_id = FTL_BAND_PHYS_ID_INVALID;
     594           0 :         struct ftl_band *band;
     595           0 :         uint64_t i, band_count;
     596           0 :         uint64_t phys_count;
     597             : 
     598           0 :         band = gc_high_priority_band(dev);
     599           0 :         if (spdk_unlikely(NULL != band)) {
     600           0 :                 return band;
     601             :         }
     602             : 
     603           0 :         phys_count = dev->num_logical_bands_in_physical;
     604           0 :         band_count = ftl_get_num_bands(dev);
     605             : 
     606           0 :         for (; dev->sb_shm->gc_info.current_band_id < band_count;) {
     607           0 :                 band = &dev->bands[dev->sb_shm->gc_info.current_band_id];
     608           0 :                 if (band->phys_id != dev->sb_shm->gc_info.band_phys_id) {
     609           0 :                         break;
     610             :                 }
     611             : 
     612           0 :                 if (false == is_band_relocateable(band)) {
     613           0 :                         dev->sb_shm->gc_info.current_band_id++;
     614           0 :                         continue;
     615             :                 }
     616             : 
     617           0 :                 band_start_gc(dev, band);
     618           0 :                 return band;
     619             :         }
     620             : 
     621           0 :         for (i = 0; i < band_count; i += phys_count) {
     622           0 :                 band = &dev->bands[i];
     623             : 
     624             :                 /* Calculate entire band physical group invalidity */
     625           0 :                 get_band_phys_info(dev, band->phys_id, &invalidity, &wr_cnt);
     626             : 
     627           0 :                 if (invalidity != 0.0L) {
     628           0 :                         if (phys_id == FTL_BAND_PHYS_ID_INVALID ||
     629           0 :                             band_cmp(invalidity, wr_cnt, max_invalidity, max_wr_cnt,
     630           0 :                                      band->phys_id, phys_id)) {
     631           0 :                                 max_wr_cnt = wr_cnt;
     632           0 :                                 phys_id = band->phys_id;
     633             : 
     634           0 :                                 if (invalidity > max_invalidity) {
     635           0 :                                         max_invalidity = invalidity;
     636           0 :                                 }
     637           0 :                         }
     638           0 :                 }
     639           0 :         }
     640             : 
     641           0 :         if (FTL_BAND_PHYS_ID_INVALID != phys_id) {
     642           0 :                 FTL_DEBUGLOG(dev, "Band physical id %"PRIu64" to GC\n", phys_id);
     643           0 :                 dev->sb_shm->gc_info.is_valid = 0;
     644           0 :                 dev->sb_shm->gc_info.current_band_id = phys_id * phys_count;
     645           0 :                 dev->sb_shm->gc_info.band_phys_id = phys_id;
     646           0 :                 dev->sb_shm->gc_info.is_valid = 1;
     647           0 :                 dump_bands_under_relocation(dev);
     648           0 :                 return ftl_band_search_next_to_reloc(dev);
     649             :         } else {
     650           0 :                 ftl_band_reset_gc_iter(dev);
     651             :         }
     652             : 
     653           0 :         return NULL;
     654           0 : }
     655             : 
     656             : void
     657           0 : ftl_band_init_gc_iter(struct spdk_ftl_dev *dev)
     658             : {
     659           0 :         if (dev->conf.mode & SPDK_FTL_MODE_CREATE) {
     660           0 :                 ftl_band_reset_gc_iter(dev);
     661           0 :                 return;
     662             :         }
     663             : 
     664           0 :         if (dev->sb->clean) {
     665           0 :                 dev->sb_shm->gc_info = dev->sb->gc_info;
     666           0 :                 return;
     667             :         }
     668             : 
     669           0 :         if (ftl_fast_startup(dev) || ftl_fast_recovery(dev)) {
     670           0 :                 return;
     671             :         }
     672             : 
     673             :         /* We lost GC state due to dirty shutdown, reset GC state to start over */
     674           0 :         ftl_band_reset_gc_iter(dev);
     675           0 : }
     676             : 
     677             : void
     678           0 : ftl_valid_map_load_state(struct spdk_ftl_dev *dev)
     679             : {
     680           0 :         uint64_t i;
     681           0 :         struct ftl_band *band;
     682             : 
     683           0 :         for (i = 0; i < dev->num_bands; i++) {
     684           0 :                 band = &dev->bands[i];
     685           0 :                 band->p2l_map.num_valid = ftl_bitmap_count_set(band->p2l_map.valid);
     686           0 :         }
     687           0 : }
     688             : 
     689             : void
     690           0 : ftl_band_initialize_free_state(struct ftl_band *band)
     691             : {
     692             :         /* All bands start on the shut list during startup, removing it manually here */
     693           0 :         TAILQ_REMOVE(&band->dev->shut_bands, band, queue_entry);
     694           0 :         _ftl_band_set_free(band);
     695           0 : }
     696             : 
     697             : int
     698           0 : ftl_bands_load_state(struct spdk_ftl_dev *dev)
     699             : {
     700           0 :         uint64_t i;
     701           0 :         struct ftl_band *band;
     702             : 
     703           0 :         for (i = 0; i < dev->num_bands; i++) {
     704           0 :                 band = &dev->bands[i];
     705             : 
     706           0 :                 if (band->md->version != FTL_BAND_VERSION_CURRENT) {
     707           0 :                         FTL_ERRLOG(dev, "Invalid band version detected, %"PRIu64" (expected %d)\n",
     708             :                                    band->md->version, FTL_BAND_VERSION_CURRENT);
     709           0 :                         return -1;
     710             :                 }
     711             : 
     712           0 :                 if (band->md->state == FTL_BAND_STATE_FREE) {
     713           0 :                         ftl_band_initialize_free_state(band);
     714           0 :                 }
     715           0 :         }
     716             : 
     717           0 :         return 0;
     718           0 : }

Generated by: LCOV version 1.15