LCOV - code coverage report
Current view: top level - spdk/lib/ftl - ftl_p2l.c (source / functions) Hit Total Coverage
Test: Combined Lines: 189 250 75.6 %
Date: 2024-07-11 19:06:16 Functions: 18 20 90.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 76 152 50.0 %

           Branch data     Line data    Source code
       1                 :            : /*   SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  *   Copyright (C) 2022 Intel Corporation.
       3                 :            :  *   All rights reserved.
       4                 :            :  */
       5                 :            : 
       6                 :            : #include "spdk/bdev_module.h"
       7                 :            : #include "spdk/crc32.h"
       8                 :            : 
       9                 :            : #include "ftl_internal.h"
      10                 :            : #include "ftl_band.h"
      11                 :            : #include "ftl_core.h"
      12                 :            : #include "ftl_layout.h"
      13                 :            : #include "ftl_nv_cache_io.h"
      14                 :            : #include "ftl_writer.h"
      15                 :            : #include "mngt/ftl_mngt.h"
      16                 :            : 
      17                 :            : struct ftl_p2l_ckpt {
      18                 :            :         TAILQ_ENTRY(ftl_p2l_ckpt)       link;
      19                 :            :         union ftl_md_vss                *vss_md_page;
      20                 :            :         struct ftl_md                   *md;
      21                 :            :         struct ftl_layout_region        *layout_region;
      22                 :            :         uint64_t                        num_pages;
      23                 :            : 
      24                 :            : #if defined(DEBUG)
      25                 :            :         uint64_t                        dbg_bmp_sz;
      26                 :            :         void                            *dbg_bmp;
      27                 :            :         struct ftl_bitmap               *bmp;
      28                 :            : #endif
      29                 :            : };
      30                 :            : 
      31                 :            : static struct ftl_p2l_ckpt *
      32                 :         88 : ftl_p2l_ckpt_new(struct spdk_ftl_dev *dev, int region_type)
      33                 :            : {
      34                 :            :         struct ftl_p2l_ckpt *ckpt;
      35                 :         88 :         struct ftl_layout_region *region = ftl_layout_region_get(dev, region_type);
      36                 :            : 
      37                 :         88 :         ckpt = calloc(1, sizeof(struct ftl_p2l_ckpt));
      38         [ -  + ]:         88 :         if (!ckpt) {
      39                 :          0 :                 return NULL;
      40                 :            :         }
      41                 :            : 
      42                 :         88 :         ckpt->vss_md_page = ftl_md_vss_buf_alloc(region, region->num_entries);
      43                 :         88 :         ckpt->layout_region = region;
      44                 :         88 :         ckpt->md = dev->layout.md[region_type];
      45                 :         88 :         ckpt->num_pages = spdk_divide_round_up(ftl_get_num_blocks_in_band(dev), FTL_NUM_LBA_IN_BLOCK);
      46                 :            : 
      47         [ -  + ]:         88 :         if (!ckpt->vss_md_page) {
      48                 :          0 :                 free(ckpt);
      49                 :          0 :                 return NULL;
      50                 :            :         }
      51                 :            : 
      52                 :            : #if defined(DEBUG)
      53                 :            :         /* The bitmap size must be a multiple of word size (8b) - round up */
      54                 :         88 :         ckpt->dbg_bmp_sz = spdk_divide_round_up(ckpt->num_pages, 8);
      55                 :            : 
      56                 :         88 :         ckpt->dbg_bmp = calloc(1, ckpt->dbg_bmp_sz);
      57         [ -  + ]:         88 :         assert(ckpt->dbg_bmp);
      58                 :         88 :         ckpt->bmp = ftl_bitmap_create(ckpt->dbg_bmp, ckpt->dbg_bmp_sz);
      59         [ -  + ]:         88 :         assert(ckpt->bmp);
      60                 :            : #endif
      61                 :            : 
      62                 :         88 :         return ckpt;
      63                 :            : }
      64                 :            : 
      65                 :            : static void
      66                 :         88 : ftl_p2l_ckpt_destroy(struct ftl_p2l_ckpt *ckpt)
      67                 :            : {
      68                 :            : #if defined(DEBUG)
      69                 :         88 :         ftl_bitmap_destroy(ckpt->bmp);
      70                 :         88 :         free(ckpt->dbg_bmp);
      71                 :            : #endif
      72                 :         88 :         spdk_dma_free(ckpt->vss_md_page);
      73                 :         88 :         free(ckpt);
      74                 :         88 : }
      75                 :            : 
      76                 :            : int
      77                 :         22 : ftl_p2l_ckpt_init(struct spdk_ftl_dev *dev)
      78                 :            : {
      79                 :            :         int region_type;
      80                 :            :         struct ftl_p2l_ckpt *ckpt;
      81                 :            : 
      82                 :         22 :         TAILQ_INIT(&dev->p2l_ckpt.free);
      83                 :         22 :         TAILQ_INIT(&dev->p2l_ckpt.inuse);
      84         [ #  # ]:         22 :         for (region_type = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MIN;
      85         [ +  + ]:        110 :              region_type <= FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MAX;
      86                 :         88 :              region_type++) {
      87                 :         88 :                 ckpt = ftl_p2l_ckpt_new(dev, region_type);
      88         [ -  + ]:         88 :                 if (!ckpt) {
      89                 :          0 :                         return -1;
      90                 :            :                 }
      91                 :         88 :                 TAILQ_INSERT_TAIL(&dev->p2l_ckpt.free, ckpt, link);
      92                 :            :         }
      93                 :         22 :         return 0;
      94                 :            : }
      95                 :            : 
      96                 :            : void
      97                 :         22 : ftl_p2l_ckpt_deinit(struct spdk_ftl_dev *dev)
      98                 :            : {
      99                 :            :         struct ftl_p2l_ckpt *ckpt, *ckpt_next;
     100                 :            : 
     101         [ +  + ]:        105 :         TAILQ_FOREACH_SAFE(ckpt, &dev->p2l_ckpt.free, link, ckpt_next) {
     102         [ +  + ]:         83 :                 TAILQ_REMOVE(&dev->p2l_ckpt.free, ckpt, link);
     103                 :         83 :                 ftl_p2l_ckpt_destroy(ckpt);
     104                 :            :         }
     105                 :            : 
     106         [ +  + ]:         27 :         TAILQ_FOREACH_SAFE(ckpt, &dev->p2l_ckpt.inuse, link, ckpt_next) {
     107         [ -  + ]:          5 :                 TAILQ_REMOVE(&dev->p2l_ckpt.inuse, ckpt, link);
     108                 :          5 :                 ftl_p2l_ckpt_destroy(ckpt);
     109                 :            :         }
     110                 :         22 : }
     111                 :            : 
     112                 :            : struct ftl_p2l_ckpt *
     113                 :          6 : ftl_p2l_ckpt_acquire(struct spdk_ftl_dev *dev)
     114                 :            : {
     115                 :            :         struct ftl_p2l_ckpt *ckpt;
     116                 :            : 
     117                 :          6 :         ckpt = TAILQ_FIRST(&dev->p2l_ckpt.free);
     118         [ -  + ]:          6 :         assert(ckpt);
     119         [ +  - ]:          6 :         TAILQ_REMOVE(&dev->p2l_ckpt.free, ckpt, link);
     120                 :          6 :         TAILQ_INSERT_TAIL(&dev->p2l_ckpt.inuse, ckpt, link);
     121                 :          6 :         return ckpt;
     122                 :            : }
     123                 :            : 
     124                 :            : void
     125                 :          4 : ftl_p2l_ckpt_release(struct spdk_ftl_dev *dev, struct ftl_p2l_ckpt *ckpt)
     126                 :            : {
     127         [ -  + ]:          4 :         assert(ckpt);
     128                 :            : #if defined(DEBUG)
     129         [ -  + ]:          4 :         memset(ckpt->dbg_bmp, 0, ckpt->dbg_bmp_sz);
     130                 :            : #endif
     131         [ +  + ]:          4 :         TAILQ_REMOVE(&dev->p2l_ckpt.inuse, ckpt, link);
     132                 :          4 :         TAILQ_INSERT_TAIL(&dev->p2l_ckpt.free, ckpt, link);
     133                 :          4 : }
     134                 :            : 
     135                 :            : static void
     136                 :       4616 : ftl_p2l_ckpt_issue_end(int status, void *arg)
     137                 :            : {
     138                 :       4616 :         struct ftl_rq *rq = arg;
     139         [ -  + ]:       4616 :         assert(rq);
     140                 :            : 
     141         [ -  + ]:       4616 :         if (status) {
     142                 :            : #ifdef SPDK_FTL_RETRY_ON_ERROR
     143                 :            :                 /* retry */
     144                 :            :                 ftl_md_persist_entry_retry(&rq->md_persist_entry_ctx);
     145                 :            :                 return;
     146                 :            : #else
     147                 :          0 :                 ftl_abort();
     148                 :            : #endif
     149                 :            :         }
     150                 :            : 
     151         [ -  + ]:       4616 :         assert(rq->io.band->queue_depth > 0);
     152                 :       4616 :         rq->io.band->queue_depth--;
     153                 :            : 
     154                 :       4616 :         rq->owner.cb(rq);
     155                 :       4616 : }
     156                 :            : 
     157                 :            : void
     158                 :       4616 : ftl_p2l_ckpt_issue(struct ftl_rq *rq)
     159                 :            : {
     160                 :       4616 :         struct ftl_rq_entry *iter = rq->entries;
     161                 :       4616 :         ftl_addr addr = rq->io.addr;
     162                 :       4616 :         struct ftl_p2l_ckpt *ckpt = NULL;
     163                 :            :         struct ftl_p2l_ckpt_page *map_page;
     164                 :            :         union ftl_md_vss *md_page;
     165                 :            :         struct ftl_band *band;
     166                 :            :         uint64_t band_offs, p2l_map_page_no, i;
     167                 :            : 
     168         [ -  + ]:       4616 :         assert(rq);
     169                 :       4616 :         band = rq->io.band;
     170                 :       4616 :         ckpt = band->p2l_map.p2l_ckpt;
     171         [ -  + ]:       4616 :         assert(ckpt);
     172                 :            : 
     173                 :            :         /* Derive the P2L map page no */
     174                 :       4616 :         band_offs =  ftl_band_block_offset_from_addr(band, rq->io.addr);
     175                 :       4616 :         p2l_map_page_no = band_offs / FTL_NUM_LBA_IN_BLOCK;
     176         [ -  + ]:       4616 :         assert((band_offs + rq->num_blocks - 1) / FTL_NUM_LBA_IN_BLOCK == p2l_map_page_no);
     177         [ -  + ]:       4616 :         assert(p2l_map_page_no < ckpt->num_pages);
     178                 :            : 
     179                 :            :         /* Get the corresponding P2L map page - the underlying stored data is the same as in the end metadata of band P2L (ftl_p2l_map_entry),
     180                 :            :          * however we're interested in a whole page (4KiB) worth of content
     181                 :            :          */
     182                 :       4616 :         map_page = ((struct ftl_p2l_ckpt_page *)band->p2l_map.band_map) + p2l_map_page_no;
     183         [ -  + ]:       4616 :         assert(map_page);
     184                 :            : 
     185                 :            :         /* Set up the md */
     186                 :       4616 :         md_page = &ckpt->vss_md_page[p2l_map_page_no];
     187                 :       4616 :         md_page->p2l_ckpt.seq_id = band->md->seq;
     188         [ -  + ]:       4616 :         assert(rq->num_blocks == FTL_NUM_LBA_IN_BLOCK);
     189                 :            : 
     190                 :            :         /* Update the band P2L map */
     191         [ +  + ]:    1186312 :         for (i = 0; i < rq->num_blocks; i++, iter++) {
     192         [ +  + ]:    1181696 :                 if (iter->lba != FTL_LBA_INVALID) {
     193                 :            :                         /* This is compaction or reloc */
     194         [ -  + ]:     922624 :                         assert(!ftl_addr_in_nvc(rq->dev, addr));
     195                 :     922624 :                         ftl_band_set_p2l(band, iter->lba, addr, iter->seq_id);
     196                 :            :                 }
     197                 :    1181696 :                 addr = ftl_band_next_addr(band, addr, 1);
     198                 :            :         }
     199                 :            : 
     200                 :            : #if defined(DEBUG)
     201                 :       4616 :         ftl_bitmap_set(ckpt->bmp, p2l_map_page_no);
     202                 :            : #endif
     203                 :            : 
     204                 :       4616 :         md_page->p2l_ckpt.p2l_checksum = spdk_crc32c_update(map_page,
     205                 :       4616 :                                          rq->num_blocks * sizeof(struct ftl_p2l_map_entry), 0);
     206                 :            :         /* Save the P2L map entry */
     207                 :       4616 :         ftl_md_persist_entry(ckpt->md, p2l_map_page_no, map_page, md_page, ftl_p2l_ckpt_issue_end,
     208                 :            :                              rq, &rq->md_persist_entry_ctx);
     209                 :       4616 : }
     210                 :            : 
     211                 :            : #if defined(DEBUG)
     212                 :            : static void
     213                 :          8 : ftl_p2l_validate_pages(struct ftl_band *band, struct ftl_p2l_ckpt *ckpt,
     214                 :            :                        uint64_t page_begin, uint64_t page_end, bool val)
     215                 :            : {
     216                 :            :         uint64_t page_no;
     217                 :            : 
     218         [ +  + ]:       4104 :         for (page_no = page_begin; page_no < page_end; page_no++) {
     219         [ -  + ]:       4096 :                 assert(ftl_bitmap_get(ckpt->bmp, page_no) == val);
     220                 :            :         }
     221                 :          8 : }
     222                 :            : 
     223                 :            : void
     224                 :          4 : ftl_p2l_validate_ckpt(struct ftl_band *band)
     225                 :            : {
     226                 :          4 :         struct ftl_p2l_ckpt *ckpt = band->p2l_map.p2l_ckpt;
     227                 :          4 :         uint64_t num_blks_tail_md = ftl_tail_md_num_blocks(band->dev);
     228                 :          4 :         uint64_t num_pages_tail_md = num_blks_tail_md / FTL_NUM_LBA_IN_BLOCK;
     229                 :            : 
     230         [ -  + ]:          4 :         if (!ckpt) {
     231                 :          0 :                 return;
     232                 :            :         }
     233                 :            : 
     234         [ -  + ]:          4 :         assert(num_blks_tail_md % FTL_NUM_LBA_IN_BLOCK == 0);
     235                 :            : 
     236                 :            :         /* all data pages written */
     237                 :          4 :         ftl_p2l_validate_pages(band, ckpt,
     238                 :          4 :                                0, ckpt->num_pages - num_pages_tail_md, true);
     239                 :            : 
     240                 :            :         /* tail md pages not written */
     241                 :          4 :         ftl_p2l_validate_pages(band, ckpt, ckpt->num_pages - num_pages_tail_md,
     242                 :            :                                ckpt->num_pages, false);
     243                 :            : }
     244                 :            : #endif
     245                 :            : 
     246                 :            : static struct ftl_band *
     247                 :         88 : ftl_get_band_from_region(struct spdk_ftl_dev *dev, enum ftl_layout_region_type type)
     248                 :            : {
     249                 :         88 :         struct ftl_band *band = NULL;
     250                 :            :         uint64_t i;
     251                 :            : 
     252         [ -  + ]:         88 :         assert(type >= FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MIN);
     253         [ -  + ]:         88 :         assert(type <= FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MAX);
     254                 :            : 
     255         [ +  + ]:       7734 :         for (i = 0; i < ftl_get_num_bands(dev); i++) {
     256                 :       7651 :                 band = &dev->bands[i];
     257         [ +  + ]:       7651 :                 if ((band->md->state == FTL_BAND_STATE_OPEN ||
     258         [ -  + ]:       7631 :                      band->md->state == FTL_BAND_STATE_FULL) &&
     259         [ +  + ]:         20 :                     band->md->p2l_md_region == type) {
     260                 :          5 :                         return band;
     261                 :            :                 }
     262                 :            :         }
     263                 :            : 
     264                 :         83 :         return NULL;
     265                 :            : }
     266                 :            : 
     267                 :            : static void ftl_mngt_persist_band_p2l(struct ftl_mngt_process *mngt, struct ftl_p2l_sync_ctx *ctx);
     268                 :            : 
     269                 :            : static void
     270                 :       1514 : ftl_p2l_ckpt_persist_end(int status, void *arg)
     271                 :            : {
     272                 :       1514 :         struct ftl_mngt_process *mngt = arg;
     273                 :            :         struct ftl_p2l_sync_ctx *ctx;
     274                 :            : 
     275         [ -  + ]:       1514 :         assert(mngt);
     276                 :            : 
     277         [ -  + ]:       1514 :         if (status) {
     278                 :          0 :                 ftl_mngt_fail_step(mngt);
     279                 :          0 :                 return;
     280                 :            :         }
     281                 :            : 
     282                 :       1514 :         ctx = ftl_mngt_get_step_ctx(mngt);
     283                 :       1514 :         ctx->page_start++;
     284                 :            : 
     285         [ +  + ]:       1514 :         if (ctx->page_start == ctx->page_end) {
     286                 :          5 :                 ctx->md_region++;
     287                 :          5 :                 ftl_mngt_continue_step(mngt);
     288                 :            :         } else {
     289                 :       1509 :                 ftl_mngt_persist_band_p2l(mngt, ctx);
     290                 :            :         }
     291                 :            : }
     292                 :            : 
     293                 :            : static void
     294                 :       1514 : ftl_mngt_persist_band_p2l(struct ftl_mngt_process *mngt, struct ftl_p2l_sync_ctx *ctx)
     295                 :            : {
     296                 :       1514 :         struct ftl_band *band = ctx->band;
     297                 :            :         union ftl_md_vss *md_page;
     298                 :            :         struct ftl_p2l_ckpt_page *map_page;
     299                 :            :         struct ftl_p2l_ckpt *ckpt;
     300                 :            : 
     301                 :       1514 :         ckpt = band->p2l_map.p2l_ckpt;
     302                 :            : 
     303                 :       1514 :         map_page = ((struct ftl_p2l_ckpt_page *)band->p2l_map.band_map) + ctx->page_start;
     304                 :            : 
     305                 :       1514 :         md_page = &ckpt->vss_md_page[ctx->page_start];
     306                 :       1514 :         md_page->p2l_ckpt.seq_id = band->md->seq;
     307                 :       1514 :         md_page->p2l_ckpt.p2l_checksum = spdk_crc32c_update(map_page,
     308                 :            :                                          FTL_NUM_LBA_IN_BLOCK * sizeof(struct ftl_p2l_map_entry), 0);
     309                 :            : 
     310                 :            :         /* Save the P2L map entry */
     311                 :       1514 :         ftl_md_persist_entry(ckpt->md, ctx->page_start, map_page, md_page,
     312                 :            :                              ftl_p2l_ckpt_persist_end, mngt, &band->md_persist_entry_ctx);
     313                 :       1514 : }
     314                 :            : 
     315                 :            : void
     316                 :        110 : ftl_mngt_persist_bands_p2l(struct ftl_mngt_process *mngt)
     317                 :            : {
     318                 :        110 :         struct ftl_p2l_sync_ctx *ctx = ftl_mngt_get_step_ctx(mngt);
     319                 :            :         struct ftl_band *band;
     320                 :            :         uint64_t band_offs, p2l_map_page_no;
     321                 :            : 
     322         [ +  + ]:        110 :         if (ctx->md_region > FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MAX) {
     323                 :         22 :                 ftl_mngt_next_step(mngt);
     324                 :         22 :                 return;
     325                 :            :         }
     326                 :            : 
     327                 :         88 :         band = ftl_get_band_from_region(ftl_mngt_get_dev(mngt), ctx->md_region);
     328                 :            : 
     329                 :            :         /* No band has the md region assigned (shutdown happened before next_band was assigned) */
     330         [ +  + ]:         88 :         if (!band) {
     331                 :         83 :                 ctx->page_start = 0;
     332                 :         83 :                 ctx->page_end = 0;
     333                 :         83 :                 ctx->md_region++;
     334                 :         83 :                 ftl_mngt_continue_step(mngt);
     335                 :         83 :                 return;
     336                 :            :         }
     337                 :            : 
     338                 :          5 :         band_offs = ftl_band_block_offset_from_addr(band, band->md->iter.addr);
     339                 :          5 :         p2l_map_page_no = band_offs / FTL_NUM_LBA_IN_BLOCK;
     340                 :            : 
     341                 :          5 :         ctx->page_start = 0;
     342                 :          5 :         ctx->page_end = p2l_map_page_no;
     343                 :          5 :         ctx->band = band;
     344                 :            : 
     345                 :            :         /* Band wasn't written to - no need to sync its P2L */
     346         [ -  + ]:          5 :         if (ctx->page_end == 0) {
     347                 :          0 :                 ctx->md_region++;
     348                 :          0 :                 ftl_mngt_continue_step(mngt);
     349                 :          0 :                 return;
     350                 :            :         }
     351                 :            : 
     352                 :          5 :         ftl_mngt_persist_band_p2l(mngt, ctx);
     353                 :            : }
     354                 :            : 
     355                 :            : uint64_t
     356                 :          4 : ftl_mngt_p2l_ckpt_get_seq_id(struct spdk_ftl_dev *dev, int md_region)
     357                 :            : {
     358                 :          4 :         struct ftl_layout *layout = &dev->layout;
     359                 :          4 :         struct ftl_md *md = layout->md[md_region];
     360                 :          4 :         union ftl_md_vss *page_md_buf = ftl_md_get_vss_buffer(md);
     361                 :          4 :         uint64_t page_no, seq_id = 0;
     362                 :            : 
     363         [ +  + ]:       4100 :         for (page_no = 0; page_no < layout->p2l.ckpt_pages; page_no++, page_md_buf++) {
     364         [ +  + ]:       4096 :                 if (seq_id < page_md_buf->p2l_ckpt.seq_id) {
     365                 :          3 :                         seq_id = page_md_buf->p2l_ckpt.seq_id;
     366                 :            :                 }
     367                 :            :         }
     368                 :          4 :         return seq_id;
     369                 :            : }
     370                 :            : 
     371                 :            : int
     372                 :          0 : ftl_mngt_p2l_ckpt_restore(struct ftl_band *band, uint32_t md_region, uint64_t seq_id)
     373                 :            : {
     374                 :          0 :         struct ftl_layout *layout = &band->dev->layout;
     375                 :          0 :         struct ftl_md *md = layout->md[md_region];
     376                 :          0 :         union ftl_md_vss *page_md_buf = ftl_md_get_vss_buffer(md);
     377                 :          0 :         struct ftl_p2l_ckpt_page *page = ftl_md_get_buffer(md);
     378                 :            :         struct ftl_p2l_ckpt_page *map_page;
     379                 :          0 :         uint64_t page_no, page_max = 0;
     380                 :          0 :         bool page_found = false;
     381                 :            : 
     382         [ #  # ]:          0 :         assert(band->md->p2l_md_region == md_region);
     383         [ #  # ]:          0 :         if (band->md->p2l_md_region != md_region) {
     384                 :          0 :                 return -EINVAL;
     385                 :            :         }
     386                 :            : 
     387         [ #  # ]:          0 :         assert(band->md->seq == seq_id);
     388         [ #  # ]:          0 :         if (band->md->seq != seq_id) {
     389                 :          0 :                 return -EINVAL;
     390                 :            :         }
     391                 :            : 
     392         [ #  # ]:          0 :         for (page_no = 0; page_no < layout->p2l.ckpt_pages; page_no++, page++, page_md_buf++) {
     393         [ #  # ]:          0 :                 if (page_md_buf->p2l_ckpt.seq_id != seq_id) {
     394                 :          0 :                         continue;
     395                 :            :                 }
     396                 :            : 
     397                 :          0 :                 page_max = page_no;
     398                 :          0 :                 page_found = true;
     399                 :            : 
     400                 :            :                 /* Get the corresponding P2L map page - the underlying stored data is the same as in the end metadata of band P2L (ftl_p2l_map_entry),
     401                 :            :                  * however we're interested in a whole page (4KiB) worth of content
     402                 :            :                  */
     403                 :          0 :                 map_page = ((struct ftl_p2l_ckpt_page *)band->p2l_map.band_map) + page_no;
     404                 :            : 
     405   [ #  #  #  # ]:          0 :                 if (page_md_buf->p2l_ckpt.p2l_checksum &&
     406                 :          0 :                     page_md_buf->p2l_ckpt.p2l_checksum != spdk_crc32c_update(page,
     407                 :            :                                     FTL_NUM_LBA_IN_BLOCK * sizeof(struct ftl_p2l_map_entry), 0)) {
     408                 :          0 :                         ftl_stats_crc_error(band->dev, FTL_STATS_TYPE_MD_NV_CACHE);
     409                 :          0 :                         return -EINVAL;
     410                 :            :                 }
     411                 :            : 
     412                 :            :                 /* Restore the page from P2L checkpoint */
     413                 :          0 :                 *map_page = *page;
     414                 :            :         }
     415                 :            : 
     416         [ #  # ]:          0 :         assert(page_found);
     417         [ #  # ]:          0 :         if (!page_found) {
     418                 :          0 :                 return -EINVAL;
     419                 :            :         }
     420                 :            : 
     421                 :            :         /* Restore check point in band P2L map */
     422                 :          0 :         band->p2l_map.p2l_ckpt = ftl_p2l_ckpt_acquire_region_type(
     423                 :            :                                          band->dev, md_region);
     424                 :            : 
     425                 :            : #ifdef DEBUG
     426                 :            :         /* Set check point valid map for validation */
     427                 :          0 :         struct ftl_p2l_ckpt *ckpt = band->p2l_map.p2l_ckpt ;
     428         [ #  # ]:          0 :         for (uint64_t i = 0; i <= page_max; i++) {
     429                 :          0 :                 ftl_bitmap_set(ckpt->bmp, i);
     430                 :            :         }
     431                 :            : #endif
     432                 :            : 
     433                 :          0 :         ftl_band_iter_init(band);
     434                 :          0 :         ftl_band_iter_set(band, (page_max + 1) * FTL_NUM_LBA_IN_BLOCK);
     435                 :            : 
     436                 :          0 :         return 0;
     437                 :            : }
     438                 :            : 
     439                 :            : enum ftl_layout_region_type
     440                 :          6 : ftl_p2l_ckpt_region_type(const struct ftl_p2l_ckpt *ckpt) {
     441                 :          6 :         return ckpt->layout_region->type;
     442                 :            : }
     443                 :            : 
     444                 :            : struct ftl_p2l_ckpt *
     445                 :          3 : ftl_p2l_ckpt_acquire_region_type(struct spdk_ftl_dev *dev, uint32_t region_type)
     446                 :            : {
     447                 :          3 :         struct ftl_p2l_ckpt *ckpt = NULL;
     448                 :            : 
     449         [ +  - ]:          4 :         TAILQ_FOREACH(ckpt, &dev->p2l_ckpt.free, link) {
     450         [ +  + ]:          4 :                 if (ckpt->layout_region->type == region_type) {
     451                 :          3 :                         break;
     452                 :            :                 }
     453                 :            :         }
     454                 :            : 
     455         [ -  + ]:          3 :         assert(ckpt);
     456                 :            : 
     457         [ +  - ]:          3 :         TAILQ_REMOVE(&dev->p2l_ckpt.free, ckpt, link);
     458                 :          3 :         TAILQ_INSERT_TAIL(&dev->p2l_ckpt.inuse, ckpt, link);
     459                 :            : 
     460                 :          3 :         return ckpt;
     461                 :            : }
     462                 :            : 
     463                 :            : int
     464                 :          3 : ftl_mngt_p2l_ckpt_restore_clean(struct ftl_band *band)
     465                 :            : {
     466                 :          3 :         struct spdk_ftl_dev *dev = band->dev;
     467                 :          3 :         struct ftl_layout *layout = &dev->layout;
     468                 :            :         struct ftl_p2l_ckpt_page *page, *map_page;
     469                 :          3 :         enum ftl_layout_region_type md_region = band->md->p2l_md_region;
     470                 :            :         uint64_t page_no;
     471                 :            :         uint64_t num_written_pages;
     472                 :            :         union ftl_md_vss *page_md_buf;
     473                 :            : 
     474   [ +  -  -  + ]:          3 :         if (md_region < FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MIN ||
     475                 :            :             md_region > FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MAX) {
     476                 :          0 :                 return -EINVAL;
     477                 :            :         }
     478                 :            : 
     479         [ -  + ]:          3 :         assert(band->md->iter.offset % FTL_NUM_LBA_IN_BLOCK == 0);
     480                 :          3 :         num_written_pages = band->md->iter.offset / FTL_NUM_LBA_IN_BLOCK;
     481                 :            : 
     482                 :            :         /* Associate band with md region before shutdown */
     483         [ +  - ]:          3 :         if (!band->p2l_map.p2l_ckpt) {
     484                 :          3 :                 band->p2l_map.p2l_ckpt = ftl_p2l_ckpt_acquire_region_type(dev, md_region);
     485                 :            :         }
     486                 :            : 
     487                 :            :         /* Band was opened but no data was written */
     488         [ -  + ]:          3 :         if (band->md->iter.offset == 0) {
     489                 :          0 :                 return 0;
     490                 :            :         }
     491                 :            : 
     492                 :          3 :         page_no = 0;
     493                 :            : 
     494                 :            :         /* Restore P2L map up to last written page */
     495                 :          3 :         page_md_buf = ftl_md_get_vss_buffer(layout->md[md_region]);
     496                 :          3 :         page = ftl_md_get_buffer(layout->md[md_region]);
     497                 :            : 
     498         [ +  + ]:        981 :         for (; page_no < num_written_pages; page_no++, page++, page_md_buf++) {
     499         [ -  + ]:        978 :                 if (page_md_buf->p2l_ckpt.seq_id != band->md->seq) {
     500         [ #  # ]:          0 :                         assert(page_md_buf->p2l_ckpt.seq_id == band->md->seq);
     501                 :            :                 }
     502                 :            : 
     503                 :            :                 /* Get the corresponding P2L map page */
     504                 :        978 :                 map_page = ((struct ftl_p2l_ckpt_page *)band->p2l_map.band_map) + page_no;
     505                 :            : 
     506                 :            :                 /* Restore the page from P2L checkpoint */
     507                 :        978 :                 *map_page = *page;
     508                 :            : 
     509                 :            : #if defined(DEBUG)
     510         [ -  + ]:        978 :                 assert(ftl_bitmap_get(band->p2l_map.p2l_ckpt->bmp, page_no) == false);
     511                 :        978 :                 ftl_bitmap_set(band->p2l_map.p2l_ckpt->bmp, page_no);
     512                 :            : #endif
     513                 :            :         }
     514                 :            : 
     515         [ -  + ]:          3 :         assert(page_md_buf->p2l_ckpt.seq_id < band->md->seq);
     516                 :            : 
     517                 :          3 :         return 0;
     518                 :            : }
     519                 :            : 
     520                 :            : void
     521                 :          0 : ftl_mngt_p2l_ckpt_restore_shm_clean(struct ftl_band *band)
     522                 :            : {
     523                 :          0 :         struct spdk_ftl_dev *dev = band->dev;
     524                 :          0 :         enum ftl_layout_region_type md_region = band->md->p2l_md_region;
     525                 :            : 
     526                 :            :         /* Associate band with md region before shutdown */
     527         [ #  # ]:          0 :         if (!band->p2l_map.p2l_ckpt) {
     528                 :          0 :                 band->p2l_map.p2l_ckpt = ftl_p2l_ckpt_acquire_region_type(dev, md_region);
     529                 :            :         }
     530                 :            : 
     531                 :            : #if defined(DEBUG)
     532                 :            :         uint64_t page_no;
     533                 :            :         uint64_t num_written_pages;
     534                 :            : 
     535         [ #  # ]:          0 :         assert(band->md->iter.offset % FTL_NUM_LBA_IN_BLOCK == 0);
     536                 :          0 :         num_written_pages = band->md->iter.offset / FTL_NUM_LBA_IN_BLOCK;
     537                 :            : 
     538                 :            :         /* Band was opened but no data was written */
     539         [ #  # ]:          0 :         if (band->md->iter.offset == 0) {
     540                 :          0 :                 return;
     541                 :            :         }
     542                 :            : 
     543                 :            :         /* Set page number to first data page - skip head md */
     544                 :          0 :         page_no = 0;
     545                 :            : 
     546         [ #  # ]:          0 :         for (; page_no < num_written_pages; page_no++) {
     547         [ #  # ]:          0 :                 assert(ftl_bitmap_get(band->p2l_map.p2l_ckpt->bmp, page_no) == false);
     548                 :          0 :                 ftl_bitmap_set(band->p2l_map.p2l_ckpt->bmp, page_no);
     549                 :            :         }
     550                 :            : #endif
     551                 :            : }

Generated by: LCOV version 1.14