LCOV - code coverage report
Current view: top level - spdk/lib/ftl - ftl_band.c (source / functions) Hit Total Coverage
Test: Combined Lines: 216 345 62.6 %
Date: 2024-07-15 12:41:06 Functions: 33 43 76.7 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 66 190 34.7 %

           Branch data     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                 :       8693 : ftl_band_tail_md_offset(const struct ftl_band *band)
      23                 :            : {
      24                 :      17386 :         return ftl_get_num_blocks_in_band(band->dev) -
      25                 :       8693 :                ftl_tail_md_num_blocks(band->dev);
      26                 :            : }
      27                 :            : 
      28                 :            : int
      29                 :       4621 : ftl_band_filled(struct ftl_band *band, size_t offset)
      30                 :            : {
      31                 :       4621 :         return offset == ftl_band_tail_md_offset(band);
      32                 :            : }
      33                 :            : 
      34                 :            : static void
      35                 :         28 : ftl_band_free_p2l_map(struct ftl_band *band)
      36                 :            : {
      37                 :         28 :         struct spdk_ftl_dev *dev = band->dev;
      38                 :         28 :         struct ftl_p2l_map *p2l_map = &band->p2l_map;
      39                 :            : 
      40   [ -  +  -  - ]:         28 :         assert(band->md->state == FTL_BAND_STATE_CLOSED ||
      41                 :            :                band->md->state == FTL_BAND_STATE_FREE);
      42         [ -  + ]:         28 :         assert(p2l_map->ref_cnt == 0);
      43         [ -  + ]:         28 :         assert(p2l_map->band_map != NULL);
      44                 :            : 
      45                 :         28 :         band->md->df_p2l_map = FTL_DF_OBJ_ID_INVALID;
      46                 :         28 :         ftl_mempool_put(dev->p2l_pool, p2l_map->band_map);
      47                 :         28 :         p2l_map->band_map = NULL;
      48                 :         28 : }
      49                 :            : 
      50                 :            : 
      51                 :            : static void
      52                 :         28 : ftl_band_free_md_entry(struct ftl_band *band)
      53                 :            : {
      54                 :         28 :         struct spdk_ftl_dev *dev = band->dev;
      55                 :         28 :         struct ftl_p2l_map *p2l_map = &band->p2l_map;
      56                 :            : 
      57   [ -  +  -  - ]:         28 :         assert(band->md->state == FTL_BAND_STATE_CLOSED ||
      58                 :            :                band->md->state == FTL_BAND_STATE_FREE);
      59         [ -  + ]:         28 :         assert(p2l_map->band_dma_md != NULL);
      60                 :            : 
      61                 :         28 :         ftl_mempool_put(dev->band_md_pool, p2l_map->band_dma_md);
      62                 :         28 :         p2l_map->band_dma_md = NULL;
      63                 :         28 : }
      64                 :            : 
      65                 :            : static void
      66                 :       2029 : _ftl_band_set_free(struct ftl_band *band)
      67                 :            : {
      68                 :       2029 :         struct spdk_ftl_dev *dev = band->dev;
      69                 :            : 
      70                 :            :         /* Add the band to the free band list */
      71                 :       2029 :         TAILQ_INSERT_TAIL(&dev->free_bands, band, queue_entry);
      72                 :       2029 :         band->md->close_seq_id = 0;
      73                 :       2029 :         band->reloc = false;
      74                 :            : 
      75                 :       2029 :         dev->num_free++;
      76                 :       2029 :         ftl_apply_limits(dev);
      77                 :            : 
      78                 :       2029 :         band->md->p2l_map_checksum = 0;
      79                 :       2029 : }
      80                 :            : 
      81                 :            : static void
      82                 :          6 : _ftl_band_set_preparing(struct ftl_band *band)
      83                 :            : {
      84                 :          6 :         struct spdk_ftl_dev *dev = band->dev;
      85                 :            : 
      86                 :            :         /* Remove band from free list */
      87         [ +  - ]:          6 :         TAILQ_REMOVE(&dev->free_bands, band, queue_entry);
      88                 :            : 
      89                 :          6 :         band->md->wr_cnt++;
      90                 :            : 
      91         [ -  + ]:          6 :         assert(dev->num_free > 0);
      92                 :          6 :         dev->num_free--;
      93                 :            : 
      94                 :          6 :         ftl_apply_limits(dev);
      95                 :          6 : }
      96                 :            : 
      97                 :            : static void
      98                 :          4 : _ftl_band_set_closed_cb(struct ftl_band *band, bool valid)
      99                 :            : {
     100                 :          4 :         struct spdk_ftl_dev *dev = band->dev;
     101                 :            : 
     102         [ -  + ]:          4 :         assert(valid == true);
     103                 :            : 
     104                 :            :         /* Set the state as free_md() checks for that */
     105                 :          4 :         band->md->state = FTL_BAND_STATE_CLOSED;
     106         [ +  - ]:          4 :         if (band->owner.state_change_fn) {
     107                 :          4 :                 band->owner.state_change_fn(band);
     108                 :            :         }
     109                 :            : 
     110                 :          4 :         ftl_p2l_validate_ckpt(band);
     111                 :            : 
     112                 :            :         /* Free the P2L map if there are no outstanding IOs */
     113                 :          4 :         ftl_band_release_p2l_map(band);
     114         [ -  + ]:          4 :         assert(band->p2l_map.ref_cnt == 0);
     115                 :            : 
     116                 :          4 :         TAILQ_INSERT_TAIL(&dev->shut_bands, band, queue_entry);
     117                 :          4 : }
     118                 :            : 
     119                 :            : static void
     120                 :          4 : _ftl_band_set_closed(struct ftl_band *band)
     121                 :            : {
     122                 :            :         /* Verify that band's metadata is consistent with l2p */
     123                 :          4 :         ftl_band_validate_md(band, _ftl_band_set_closed_cb);
     124                 :          4 : }
     125                 :            : 
     126                 :            : ftl_addr
     127                 :       2036 : ftl_band_tail_md_addr(struct ftl_band *band)
     128                 :            : {
     129                 :            :         ftl_addr addr;
     130                 :            : 
     131                 :            :         /* Metadata should be aligned to xfer size */
     132   [ -  +  -  + ]:       2036 :         assert(ftl_band_tail_md_offset(band) % band->dev->xfer_size == 0);
     133                 :            : 
     134                 :       2036 :         addr = ftl_band_tail_md_offset(band) + band->start_addr;
     135                 :            : 
     136                 :       2036 :         return addr;
     137                 :            : }
     138                 :            : 
     139                 :            : const char *
     140                 :         54 : 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         [ -  + ]:         54 :         assert(band->md->state < SPDK_COUNTOF(names));
     148         [ +  - ]:         54 :         if (band->md->state < SPDK_COUNTOF(names)) {
     149                 :         54 :                 return names[band->md->state];
     150                 :            :         } else {
     151                 :          0 :                 assert(false);
     152                 :            :                 return "?";
     153                 :            :         }
     154                 :            : }
     155                 :            : 
     156                 :            : void
     157                 :        448 : ftl_band_set_state(struct ftl_band *band, enum ftl_band_state state)
     158                 :            : {
     159   [ +  +  +  +  :        448 :         switch (state) {
                   +  - ]
     160                 :        418 :         case FTL_BAND_STATE_FREE:
     161         [ -  + ]:        418 :                 assert(band->md->state == FTL_BAND_STATE_CLOSED);
     162                 :        418 :                 _ftl_band_set_free(band);
     163                 :        418 :                 break;
     164                 :            : 
     165                 :          6 :         case FTL_BAND_STATE_PREP:
     166         [ -  + ]:          6 :                 assert(band->md->state == FTL_BAND_STATE_FREE);
     167                 :          6 :                 _ftl_band_set_preparing(band);
     168                 :          6 :                 break;
     169                 :            : 
     170                 :          4 :         case FTL_BAND_STATE_CLOSED:
     171         [ +  - ]:          4 :                 if (band->md->state != FTL_BAND_STATE_CLOSED) {
     172         [ -  + ]:          4 :                         assert(band->md->state == FTL_BAND_STATE_CLOSING);
     173                 :          4 :                         _ftl_band_set_closed(band);
     174                 :          4 :                         return; /* state can be changed asynchronously */
     175                 :            :                 }
     176                 :          0 :                 break;
     177                 :            : 
     178                 :          6 :         case FTL_BAND_STATE_OPEN:
     179                 :          6 :                 band->md->p2l_map_checksum = 0;
     180                 :          6 :                 break;
     181                 :         14 :         case FTL_BAND_STATE_OPENING:
     182                 :            :         case FTL_BAND_STATE_FULL:
     183                 :            :         case FTL_BAND_STATE_CLOSING:
     184                 :         14 :                 break;
     185                 :          0 :         default:
     186         [ #  # ]:          0 :                 FTL_ERRLOG(band->dev, "Unknown band state, %u", state);
     187                 :          0 :                 assert(false);
     188                 :            :                 break;
     189                 :            :         }
     190                 :            : 
     191                 :        444 :         band->md->state = state;
     192                 :            : }
     193                 :            : 
     194                 :            : void
     195                 :          6 : ftl_band_set_type(struct ftl_band *band, enum ftl_band_type type)
     196                 :            : {
     197         [ +  - ]:          6 :         switch (type) {
     198                 :          6 :         case FTL_BAND_TYPE_COMPACTION:
     199                 :            :         case FTL_BAND_TYPE_GC:
     200                 :          6 :                 band->md->type = type;
     201                 :          6 :                 break;
     202                 :          0 :         default:
     203                 :          0 :                 assert(false);
     204                 :            :                 break;
     205                 :            :         }
     206                 :          6 : }
     207                 :            : 
     208                 :            : void
     209                 :     922900 : ftl_band_set_p2l(struct ftl_band *band, uint64_t lba, ftl_addr addr, uint64_t seq_id)
     210                 :            : {
     211                 :     922900 :         struct ftl_p2l_map *p2l_map = &band->p2l_map;
     212                 :            :         uint64_t offset;
     213                 :            : 
     214                 :     922900 :         offset = ftl_band_block_offset_from_addr(band, addr);
     215                 :            : 
     216                 :     922900 :         p2l_map->band_map[offset].lba = lba;
     217                 :     922900 :         p2l_map->band_map[offset].seq_id = seq_id;
     218                 :     922900 : }
     219                 :            : 
     220                 :            : void
     221                 :     922900 : ftl_band_set_addr(struct ftl_band *band, uint64_t lba, ftl_addr addr)
     222                 :            : {
     223                 :     922900 :         band->p2l_map.num_valid++;
     224                 :     922900 :         ftl_bitmap_set(band->dev->valid_map, addr);
     225                 :     922900 : }
     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                 :            : }
     238                 :            : 
     239                 :            : size_t
     240                 :       2112 : ftl_band_user_blocks(const struct ftl_band *band)
     241                 :            : {
     242                 :       4224 :         return ftl_get_num_blocks_in_band(band->dev) -
     243                 :       2112 :                ftl_tail_md_num_blocks(band->dev);
     244                 :            : }
     245                 :            : 
     246                 :            : static inline uint64_t
     247                 :    4079942 : ftl_addr_get_band(const struct spdk_ftl_dev *dev, ftl_addr addr)
     248                 :            : {
     249         [ -  + ]:    4079942 :         return (addr - dev->bands->start_addr) / ftl_get_num_blocks_in_band(dev);
     250                 :            : }
     251                 :            : 
     252                 :            : struct ftl_band *
     253                 :     922888 : ftl_band_from_addr(struct spdk_ftl_dev *dev, ftl_addr addr)
     254                 :            : {
     255                 :     922888 :         uint64_t band_id = ftl_addr_get_band(dev, addr);
     256                 :            : 
     257         [ -  + ]:     922888 :         assert(band_id < ftl_get_num_bands(dev));
     258                 :     922888 :         return &dev->bands[band_id];
     259                 :            : }
     260                 :            : 
     261                 :            : uint64_t
     262                 :    3112358 : ftl_band_block_offset_from_addr(struct ftl_band *band, ftl_addr addr)
     263                 :            : {
     264         [ -  + ]:    3112358 :         assert(ftl_addr_get_band(band->dev, addr) == band->id);
     265                 :    3112358 :         return addr - band->start_addr;
     266                 :            : }
     267                 :            : 
     268                 :            : ftl_addr
     269                 :       4636 : ftl_band_next_xfer_addr(struct ftl_band *band, ftl_addr addr, size_t num_blocks)
     270                 :            : {
     271                 :       4636 :         struct spdk_ftl_dev *dev = band->dev;
     272                 :            :         size_t num_xfers;
     273                 :            :         uint64_t offset;
     274                 :            : 
     275         [ -  + ]:       4636 :         assert(ftl_addr_get_band(dev, addr) == band->id);
     276                 :            : 
     277                 :       4636 :         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         [ -  + ]:       4636 :         num_blocks += (offset % dev->xfer_size);
     283         [ -  + ]:       4636 :         offset -= (offset % dev->xfer_size);
     284                 :            : 
     285                 :            :         /* Calculate offset based on xfer_size aligned writes */
     286         [ -  + ]:       4636 :         num_xfers = (num_blocks / dev->xfer_size);
     287                 :       4636 :         offset += num_xfers * dev->xfer_size;
     288                 :       4636 :         num_blocks -= num_xfers * dev->xfer_size;
     289                 :            : 
     290         [ -  + ]:       4636 :         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         [ +  + ]:       4636 :         if (num_blocks) {
     297                 :          8 :                 offset += num_blocks;
     298         [ -  + ]:          8 :                 if (offset > ftl_get_num_blocks_in_band(dev)) {
     299                 :          0 :                         return FTL_ADDR_INVALID;
     300                 :            :                 }
     301                 :            :         }
     302                 :            : 
     303                 :       4636 :         addr = band->start_addr + offset;
     304                 :       4636 :         return addr;
     305                 :            : }
     306                 :            : 
     307                 :            : ftl_addr
     308                 :    2930240 : ftl_band_addr_from_block_offset(struct ftl_band *band, uint64_t block_off)
     309                 :            : {
     310                 :            :         ftl_addr addr;
     311                 :            : 
     312                 :    2930240 :         addr = block_off + band->start_addr;
     313                 :    2930240 :         return addr;
     314                 :            : }
     315                 :            : 
     316                 :            : ftl_addr
     317                 :    2104832 : ftl_band_next_addr(struct ftl_band *band, ftl_addr addr, size_t offset)
     318                 :            : {
     319                 :    2104832 :         uint64_t block_off = ftl_band_block_offset_from_addr(band, addr);
     320                 :            : 
     321                 :    2104832 :         return ftl_band_addr_from_block_offset(band, block_off + offset);
     322                 :            : }
     323                 :            : 
     324                 :            : void
     325                 :         33 : ftl_band_acquire_p2l_map(struct ftl_band *band)
     326                 :            : {
     327         [ -  + ]:         33 :         assert(band->p2l_map.band_map != NULL);
     328                 :         33 :         band->p2l_map.ref_cnt++;
     329                 :         33 : }
     330                 :            : 
     331                 :            : static int
     332                 :         33 : ftl_band_alloc_md_entry(struct ftl_band *band)
     333                 :            : {
     334                 :         33 :         struct spdk_ftl_dev *dev = band->dev;
     335                 :         33 :         struct ftl_p2l_map *p2l_map = &band->p2l_map;
     336                 :         33 :         struct ftl_layout_region *region = ftl_layout_region_get(dev, FTL_LAYOUT_REGION_TYPE_BAND_MD);
     337                 :            : 
     338                 :         33 :         p2l_map->band_dma_md = ftl_mempool_get(dev->band_md_pool);
     339                 :            : 
     340         [ -  + ]:         33 :         if (!p2l_map->band_dma_md) {
     341                 :          0 :                 return -1;
     342                 :            :         }
     343                 :            : 
     344         [ -  + ]:         33 :         memset(p2l_map->band_dma_md, 0, region->entry_size * FTL_BLOCK_SIZE);
     345                 :         33 :         return 0;
     346                 :            : }
     347                 :            : 
     348                 :            : int
     349                 :         33 : ftl_band_alloc_p2l_map(struct ftl_band *band)
     350                 :            : {
     351                 :         33 :         struct spdk_ftl_dev *dev = band->dev;
     352                 :         33 :         struct ftl_p2l_map *p2l_map = &band->p2l_map;
     353                 :            : 
     354         [ -  + ]:         33 :         assert(p2l_map->ref_cnt == 0);
     355         [ -  + ]:         33 :         assert(p2l_map->band_map == NULL);
     356                 :            : 
     357         [ -  + ]:         33 :         assert(band->md->df_p2l_map == FTL_DF_OBJ_ID_INVALID);
     358                 :         33 :         p2l_map->band_map = ftl_mempool_get(dev->p2l_pool);
     359         [ -  + ]:         33 :         if (!p2l_map->band_map) {
     360                 :          0 :                 return -1;
     361                 :            :         }
     362                 :            : 
     363         [ -  + ]:         33 :         if (ftl_band_alloc_md_entry(band)) {
     364                 :          0 :                 ftl_band_free_p2l_map(band);
     365                 :          0 :                 return -1;
     366                 :            :         }
     367                 :            : 
     368                 :         33 :         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         [ -  + ]:         33 :         memset(p2l_map->band_map, -1, FTL_BLOCK_SIZE * ftl_p2l_map_num_blocks(band->dev));
     372                 :            : 
     373                 :         33 :         ftl_band_acquire_p2l_map(band);
     374                 :         33 :         return 0;
     375                 :            : }
     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                 :            : }
     398                 :            : 
     399                 :            : void
     400                 :         28 : ftl_band_release_p2l_map(struct ftl_band *band)
     401                 :            : {
     402                 :         28 :         struct ftl_p2l_map *p2l_map = &band->p2l_map;
     403                 :            : 
     404         [ -  + ]:         28 :         assert(p2l_map->band_map != NULL);
     405         [ -  + ]:         28 :         assert(p2l_map->ref_cnt > 0);
     406                 :         28 :         p2l_map->ref_cnt--;
     407                 :            : 
     408         [ +  - ]:         28 :         if (p2l_map->ref_cnt == 0) {
     409         [ +  + ]:         28 :                 if (p2l_map->p2l_ckpt) {
     410                 :          4 :                         ftl_p2l_ckpt_release(band->dev, p2l_map->p2l_ckpt);
     411                 :          4 :                         p2l_map->p2l_ckpt = NULL;
     412                 :            :                 }
     413                 :         28 :                 ftl_band_free_p2l_map(band);
     414                 :         28 :                 ftl_band_free_md_entry(band);
     415                 :            :         }
     416                 :         28 : }
     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                 :          6 : ftl_band_write_prep(struct ftl_band *band)
     426                 :            : {
     427                 :          6 :         struct spdk_ftl_dev *dev = band->dev;
     428                 :            : 
     429         [ -  + ]:          6 :         if (ftl_band_alloc_p2l_map(band)) {
     430                 :          0 :                 return -1;
     431                 :            :         }
     432                 :            : 
     433                 :          6 :         band->p2l_map.p2l_ckpt = ftl_p2l_ckpt_acquire(dev);
     434                 :          6 :         band->md->p2l_md_region = ftl_p2l_ckpt_region_type(band->p2l_map.p2l_ckpt);
     435                 :          6 :         ftl_band_iter_init(band);
     436                 :            : 
     437                 :          6 :         band->md->seq = ftl_get_next_seq_id(dev);
     438                 :            : 
     439         [ +  - ]:          6 :         FTL_DEBUGLOG(dev, "Band to write, id %u seq %"PRIu64"\n", band->id, band->md->seq);
     440                 :          6 :         return 0;
     441                 :            : }
     442                 :            : 
     443                 :            : size_t
     444                 :         22 : ftl_p2l_map_pool_elem_size(struct spdk_ftl_dev *dev)
     445                 :            : {
     446                 :            :         /* Map pool element holds the whole tail md */
     447                 :         22 :         return ftl_tail_md_num_blocks(dev) * FTL_BLOCK_SIZE;
     448                 :            : }
     449                 :            : 
     450                 :            : double
     451                 :         54 : ftl_band_invalidity(struct ftl_band *band)
     452                 :            : {
     453                 :         54 :         double valid = band->p2l_map.num_valid;
     454                 :         54 :         double count = ftl_band_user_blocks(band);
     455                 :            : 
     456                 :         54 :         return 1.0 - (valid / count);
     457                 :            : }
     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                 :            :         }
     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                 :            : }
     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                 :            :         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                 :            :         }
     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                 :            :         }
     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                 :            : }
     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                 :            :         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                 :            : }
     576                 :            : 
     577                 :            : static void
     578                 :         10 : ftl_band_reset_gc_iter(struct spdk_ftl_dev *dev)
     579                 :            : {
     580                 :         10 :         dev->sb->gc_info.is_valid = 0;
     581                 :         10 :         dev->sb->gc_info.current_band_id = FTL_BAND_ID_INVALID;
     582                 :         10 :         dev->sb->gc_info.band_id_high_prio = FTL_BAND_ID_INVALID;
     583                 :         10 :         dev->sb->gc_info.band_phys_id = FTL_BAND_PHYS_ID_INVALID;
     584                 :            : 
     585                 :         10 :         dev->sb_shm->gc_info = dev->sb->gc_info;
     586                 :         10 : }
     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                 :            :         struct ftl_band *band;
     595                 :            :         uint64_t i, band_count;
     596                 :            :         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                 :            :                                 }
     637                 :            :                         }
     638                 :            :                 }
     639                 :            :         }
     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                 :            : }
     655                 :            : 
     656                 :            : void
     657                 :         27 : ftl_band_init_gc_iter(struct spdk_ftl_dev *dev)
     658                 :            : {
     659         [ +  + ]:         27 :         if (dev->conf.mode & SPDK_FTL_MODE_CREATE) {
     660                 :         10 :                 ftl_band_reset_gc_iter(dev);
     661                 :         10 :                 return;
     662                 :            :         }
     663                 :            : 
     664         [ +  + ]:         17 :         if (dev->sb->clean) {
     665                 :         16 :                 dev->sb_shm->gc_info = dev->sb->gc_info;
     666                 :         16 :                 return;
     667                 :            :         }
     668                 :            : 
     669   [ +  -  +  - ]:          1 :         if (ftl_fast_startup(dev) || ftl_fast_recovery(dev)) {
     670                 :          1 :                 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                 :            : }
     676                 :            : 
     677                 :            : void
     678                 :         17 : ftl_valid_map_load_state(struct spdk_ftl_dev *dev)
     679                 :            : {
     680                 :            :         uint64_t i;
     681                 :            :         struct ftl_band *band;
     682                 :            : 
     683         [ +  + ]:       1635 :         for (i = 0; i < dev->num_bands; i++) {
     684                 :       1618 :                 band = &dev->bands[i];
     685                 :       1618 :                 band->p2l_map.num_valid = ftl_bitmap_count_set(band->p2l_map.valid);
     686                 :            :         }
     687                 :         17 : }
     688                 :            : 
     689                 :            : void
     690                 :       1611 : 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         [ +  + ]:       1611 :         TAILQ_REMOVE(&band->dev->shut_bands, band, queue_entry);
     694                 :       1611 :         _ftl_band_set_free(band);
     695                 :       1611 : }
     696                 :            : 
     697                 :            : int
     698                 :         16 : ftl_bands_load_state(struct spdk_ftl_dev *dev)
     699                 :            : {
     700                 :            :         uint64_t i;
     701                 :            :         struct ftl_band *band;
     702                 :            : 
     703         [ +  + ]:       1616 :         for (i = 0; i < dev->num_bands; i++) {
     704                 :       1600 :                 band = &dev->bands[i];
     705                 :            : 
     706         [ -  + ]:       1600 :                 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         [ +  + ]:       1600 :                 if (band->md->state == FTL_BAND_STATE_FREE) {
     713                 :       1596 :                         ftl_band_initialize_free_state(band);
     714                 :            :                 }
     715                 :            :         }
     716                 :            : 
     717                 :         16 :         return 0;
     718                 :            : }

Generated by: LCOV version 1.14