LCOV - code coverage report
Current view: top level - spdk/lib/ftl/utils - ftl_md.c (source / functions) Hit Total Coverage
Test: Combined Lines: 415 567 73.2 %
Date: 2024-07-13 10:29:36 Functions: 52 60 86.7 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 201 321 62.6 %

           Branch data     Line data    Source code
       1                 :            : /*   SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  *   Copyright 2023 Solidigm All Rights Reserved
       3                 :            :  *   Copyright (C) 2022 Intel Corporation.
       4                 :            :  *   All rights reserved.
       5                 :            :  */
       6                 :            : 
       7                 :            : #include "spdk/env.h"
       8                 :            : #include "spdk/bdev_module.h"
       9                 :            : 
      10                 :            : #include "ftl_core.h"
      11                 :            : #include "ftl_md.h"
      12                 :            : #include "ftl_nv_cache_io.h"
      13                 :            : 
      14                 :            : struct ftl_md;
      15                 :            : static void io_submit(struct ftl_md *md);
      16                 :            : static void io_done(struct ftl_md *md);
      17                 :            : 
      18                 :            : static bool
      19                 :       7269 : has_mirror(struct ftl_md *md)
      20                 :            : {
      21         [ +  - ]:       7269 :         if (md->region) {
      22         [ +  + ]:       7269 :                 if (md->region->mirror_type != FTL_LAYOUT_REGION_TYPE_INVALID) {
      23         [ -  + ]:        639 :                         return md->mirror_enabled;
      24                 :            :                 }
      25                 :            :         }
      26                 :            : 
      27                 :       6630 :         return false;
      28                 :            : }
      29                 :            : 
      30                 :            : static struct ftl_md *
      31                 :        316 : ftl_md_get_mirror(struct ftl_md *md)
      32                 :            : {
      33         [ +  - ]:        316 :         if (has_mirror(md)) {
      34                 :        316 :                 return md->dev->layout.md[md->region->mirror_type];
      35                 :            :         }
      36                 :            : 
      37                 :          0 :         return NULL;
      38                 :            : }
      39                 :            : 
      40                 :            : uint64_t
      41                 :      22751 : ftl_md_xfer_blocks(struct spdk_ftl_dev *dev)
      42                 :            : {
      43                 :      22751 :         return 4ULL * dev->xfer_size;
      44                 :            : }
      45                 :            : 
      46                 :            : static uint64_t
      47                 :        528 : xfer_size(struct ftl_md *md)
      48                 :            : {
      49                 :        528 :         return ftl_md_xfer_blocks(md->dev) * FTL_BLOCK_SIZE;
      50                 :            : }
      51                 :            : 
      52                 :            : static void
      53                 :         88 : ftl_md_create_heap(struct ftl_md *md, uint64_t vss_blksz)
      54                 :            : {
      55                 :         88 :         md->shm_fd = -1;
      56                 :         88 :         md->vss_data = NULL;
      57                 :         88 :         md->data = calloc(md->data_blocks, FTL_BLOCK_SIZE + vss_blksz);
      58                 :            : 
      59   [ +  -  +  - ]:         88 :         if (md->data && vss_blksz) {
      60                 :         88 :                 md->vss_data = ((char *)md->data) + md->data_blocks * FTL_BLOCK_SIZE;
      61                 :            :         }
      62                 :         88 : }
      63                 :            : 
      64                 :            : static void
      65                 :        176 : ftl_md_destroy_heap(struct ftl_md *md)
      66                 :            : {
      67         [ +  + ]:        176 :         if (md->data) {
      68                 :         88 :                 free(md->data);
      69                 :         88 :                 md->data = NULL;
      70                 :         88 :                 md->vss_data = NULL;
      71                 :            :         }
      72                 :        176 : }
      73                 :            : 
      74                 :            : static int
      75                 :        258 : ftl_wrapper_open(const char *name, int of, mode_t m)
      76                 :            : {
      77         [ -  + ]:        258 :         return open(name, of, m);
      78                 :            : }
      79                 :            : 
      80                 :            : static void
      81                 :        258 : ftl_md_setup_obj(struct ftl_md *md, int flags,
      82                 :            :                  const char *name)
      83                 :            : {
      84                 :        258 :         char uuid_str[SPDK_UUID_STRING_LEN];
      85                 :            :         const char *fmt;
      86                 :            : 
      87         [ -  + ]:        258 :         if (!(flags & FTL_MD_CREATE_SHM)) {
      88                 :          0 :                 assert(false);
      89                 :            :                 return;
      90                 :            :         }
      91                 :            : 
      92                 :            :         /* TODO: temporary, define a proper hugetlbfs mountpoint */
      93                 :        258 :         fmt = "/dev/hugepages/ftl_%s_%s";
      94                 :        258 :         md->shm_mmap_flags = MAP_SHARED;
      95                 :        258 :         md->shm_open = ftl_wrapper_open;
      96                 :        258 :         md->shm_unlink = unlink;
      97                 :            : 
      98   [ +  -  +  - ]:        516 :         if (name == NULL ||
      99                 :        258 :             spdk_uuid_fmt_lower(uuid_str, SPDK_UUID_STRING_LEN, &md->dev->conf.uuid) ||
     100   [ -  +  -  + ]:        258 :             snprintf(md->name, sizeof(md->name) / sizeof(md->name[0]),
     101                 :            :                      fmt, uuid_str, name) <= 0) {
     102                 :          0 :                 md->name[0] = 0;
     103                 :            :         }
     104                 :            : }
     105                 :            : 
     106                 :            : static void
     107                 :         16 : ftl_md_invalidate_shm(struct ftl_md *md)
     108                 :            : {
     109   [ -  +  -  -  :         16 :         if (md->dev->sb_shm && md->dev->sb_shm->shm_ready) {
                   -  - ]
     110                 :          0 :                 md->dev->init_retry = true;
     111                 :          0 :                 md->dev->sb_shm->shm_ready = false;
     112                 :            :         }
     113                 :         16 : }
     114                 :            : 
     115                 :            : static void
     116                 :        258 : ftl_md_create_shm(struct ftl_md *md, uint64_t vss_blksz, int flags)
     117                 :            : {
     118                 :        258 :         struct stat shm_stat;
     119                 :            :         size_t vss_blk_offs;
     120                 :            :         void *shm_ptr;
     121                 :        258 :         int open_flags = O_RDWR;
     122                 :        258 :         mode_t open_mode = S_IRUSR | S_IWUSR;
     123                 :            : 
     124   [ +  -  +  - ]:        258 :         assert(md->shm_open && md->shm_unlink);
     125                 :        258 :         md->data = NULL;
     126                 :        258 :         md->vss_data = NULL;
     127                 :        258 :         md->shm_sz = 0;
     128                 :            : 
     129                 :            :         /* Must have an object name */
     130         [ -  + ]:        258 :         if (md->name[0] == 0) {
     131                 :          0 :                 assert(false);
     132                 :          0 :                 return;
     133                 :            :         }
     134                 :            : 
     135                 :            :         /* If specified, unlink before create a new SHM object */
     136         [ +  + ]:        258 :         if (flags & FTL_MD_CREATE_SHM_NEW) {
     137   [ +  +  -  + ]:        233 :                 if (md->shm_unlink(md->name) < 0 && errno != ENOENT) {
     138                 :          0 :                         ftl_md_invalidate_shm(md);
     139                 :          0 :                         return;
     140                 :            :                 }
     141                 :        233 :                 open_flags += O_CREAT | O_TRUNC;
     142                 :            :         }
     143                 :            : 
     144                 :            :         /* Open existing or create a new SHM object, then query its props */
     145                 :        258 :         md->shm_fd = md->shm_open(md->name, open_flags, open_mode);
     146   [ +  +  -  + ]:        258 :         if (md->shm_fd < 0 || fstat(md->shm_fd, &shm_stat) < 0) {
     147                 :         16 :                 goto err_shm;
     148                 :            :         }
     149                 :            : 
     150                 :            :         /* Verify open mode hasn't changed */
     151         [ -  + ]:        242 :         if ((shm_stat.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO)) != open_mode) {
     152                 :          0 :                 goto err_shm;
     153                 :            :         }
     154                 :            : 
     155                 :            :         /* Round up the SHM obj size to the nearest blk size (i.e. page size) */
     156                 :        242 :         md->shm_sz = spdk_divide_round_up(md->data_blocks * FTL_BLOCK_SIZE, shm_stat.st_blksize);
     157                 :            : 
     158                 :            :         /* Add some blks for VSS metadata */
     159                 :        242 :         vss_blk_offs = md->shm_sz;
     160                 :            : 
     161         [ +  + ]:        242 :         if (vss_blksz) {
     162                 :         88 :                 md->shm_sz += spdk_divide_round_up(md->data_blocks * vss_blksz,
     163                 :         88 :                                                    shm_stat.st_blksize);
     164                 :            :         }
     165                 :            : 
     166                 :            :         /* Total SHM obj size */
     167                 :        242 :         md->shm_sz *= shm_stat.st_blksize;
     168                 :            : 
     169                 :            :         /* Set or check the object size - zero init`d in case of set (FTL_MD_CREATE_SHM_NEW) */
     170   [ +  +  +  - ]:        242 :         if ((shm_stat.st_size == 0 && (ftruncate(md->shm_fd, md->shm_sz) < 0 ||
     171         [ +  - ]:        233 :                                        (flags & FTL_MD_CREATE_SHM_NEW) == 0))
     172   [ +  +  -  + ]:        242 :             || (shm_stat.st_size > 0 && (size_t)shm_stat.st_size != md->shm_sz)) {
     173                 :          0 :                 goto err_shm;
     174                 :            :         }
     175                 :            : 
     176                 :            :         /* Create a virtual memory mapping for the object */
     177                 :        242 :         shm_ptr = mmap(NULL, md->shm_sz, PROT_READ | PROT_WRITE, md->shm_mmap_flags,
     178                 :            :                        md->shm_fd, 0);
     179         [ -  + ]:        242 :         if (shm_ptr == MAP_FAILED) {
     180                 :          0 :                 goto err_shm;
     181                 :            :         }
     182                 :            : 
     183                 :        242 :         md->data = shm_ptr;
     184         [ +  + ]:        242 :         if (vss_blksz) {
     185                 :         88 :                 md->vss_data = ((char *)shm_ptr) + vss_blk_offs * shm_stat.st_blksize;
     186                 :            :         }
     187                 :            : 
     188                 :            :         /* Lock the pages in memory (i.e. prevent the pages to be paged out) */
     189         [ -  + ]:        242 :         if (mlock(md->data, md->shm_sz) < 0) {
     190                 :          0 :                 goto err_map;
     191                 :            :         }
     192                 :            : 
     193         [ -  + ]:        242 :         if (spdk_mem_register(md->data, md->shm_sz)) {
     194                 :          0 :                 goto err_mlock;
     195                 :            :         }
     196                 :        242 :         md->mem_reg = true;
     197                 :            : 
     198                 :        242 :         return;
     199                 :            : 
     200                 :            :         /* Cleanup upon fault */
     201                 :          0 : err_mlock:
     202                 :          0 :         munlock(md->data, md->shm_sz);
     203                 :            : 
     204                 :          0 : err_map:
     205                 :          0 :         munmap(md->data, md->shm_sz);
     206                 :          0 :         md->data = NULL;
     207                 :          0 :         md->vss_data = NULL;
     208                 :          0 :         md->shm_sz = 0;
     209                 :            : 
     210                 :         16 : err_shm:
     211         [ -  + ]:         16 :         if (md->shm_fd >= 0) {
     212                 :          0 :                 close(md->shm_fd);
     213                 :          0 :                 md->shm_unlink(md->name);
     214                 :          0 :                 md->shm_fd = -1;
     215                 :            :         }
     216                 :         16 :         ftl_md_invalidate_shm(md);
     217                 :            : }
     218                 :            : 
     219                 :            : static void
     220                 :        308 : ftl_md_destroy_shm(struct ftl_md *md, int flags)
     221                 :            : {
     222         [ +  + ]:        308 :         if (!md->data) {
     223                 :         66 :                 return;
     224                 :            :         }
     225                 :            : 
     226         [ -  + ]:        242 :         assert(md->shm_sz > 0);
     227   [ -  +  +  - ]:        242 :         if (md->mem_reg) {
     228                 :        242 :                 spdk_mem_unregister(md->data, md->shm_sz);
     229                 :        242 :                 md->mem_reg = false;
     230                 :            :         }
     231                 :            : 
     232                 :            :         /* Unlock the pages in memory */
     233                 :        242 :         munlock(md->data, md->shm_sz);
     234                 :            : 
     235                 :            :         /* Remove the virtual memory mapping for the object */
     236                 :        242 :         munmap(md->data, md->shm_sz);
     237                 :            : 
     238                 :            :         /* Close SHM object fd */
     239                 :        242 :         close(md->shm_fd);
     240                 :            : 
     241                 :        242 :         md->data = NULL;
     242                 :        242 :         md->vss_data = NULL;
     243                 :            : 
     244                 :            :         /* If specified, keep the object in SHM */
     245         [ -  + ]:        242 :         if (flags & FTL_MD_DESTROY_SHM_KEEP) {
     246                 :          0 :                 return;
     247                 :            :         }
     248                 :            : 
     249                 :            :         /* Otherwise destroy/unlink the object */
     250   [ +  -  +  - ]:        242 :         assert(md->name[0] != 0 && md->shm_unlink != NULL);
     251                 :        242 :         md->shm_unlink(md->name);
     252                 :            : }
     253                 :            : 
     254                 :        500 : struct ftl_md *ftl_md_create(struct spdk_ftl_dev *dev, uint64_t blocks,
     255                 :            :                              uint64_t vss_blksz, const char *name, int flags,
     256                 :            :                              const struct ftl_layout_region *region)
     257                 :            : {
     258                 :            :         struct ftl_md *md;
     259                 :            : 
     260                 :        500 :         md = calloc(1, sizeof(*md));
     261         [ -  + ]:        500 :         if (!md) {
     262                 :          0 :                 return NULL;
     263                 :            :         }
     264                 :        500 :         md->dev = dev;
     265                 :        500 :         md->data_blocks = blocks;
     266                 :        500 :         md->mirror_enabled = true;
     267                 :            : 
     268         [ +  + ]:        500 :         if (flags != FTL_MD_CREATE_NO_MEM) {
     269         [ +  + ]:        346 :                 if (flags & FTL_MD_CREATE_SHM) {
     270                 :        258 :                         ftl_md_setup_obj(md, flags, name);
     271                 :        258 :                         ftl_md_create_shm(md, vss_blksz, flags);
     272                 :            :                 } else {
     273         [ -  + ]:         88 :                         assert((flags & FTL_MD_CREATE_HEAP) == FTL_MD_CREATE_HEAP);
     274                 :         88 :                         ftl_md_create_heap(md, vss_blksz);
     275                 :            :                 }
     276                 :            : 
     277         [ +  + ]:        346 :                 if (!md->data) {
     278                 :         16 :                         free(md);
     279                 :         16 :                         return NULL;
     280                 :            :                 }
     281                 :            :         }
     282                 :            : 
     283         [ +  + ]:        484 :         if (region) {
     284                 :        352 :                 size_t entry_vss_buf_size = vss_blksz * region->entry_size;
     285                 :            : 
     286         [ +  + ]:        352 :                 if (entry_vss_buf_size) {
     287                 :        242 :                         md->entry_vss_dma_buf = spdk_malloc(entry_vss_buf_size, FTL_BLOCK_SIZE,
     288                 :            :                                                             NULL, SPDK_ENV_LCORE_ID_ANY,
     289                 :            :                                                             SPDK_MALLOC_DMA);
     290         [ -  + ]:        242 :                         if (!md->entry_vss_dma_buf) {
     291                 :          0 :                                 goto err;
     292                 :            :                         }
     293                 :            :                 }
     294                 :            : 
     295                 :        352 :                 ftl_md_set_region(md, region);
     296                 :            :         }
     297                 :            : 
     298                 :        484 :         return md;
     299                 :          0 : err:
     300                 :          0 :         ftl_md_destroy(md, ftl_md_destroy_region_flags(dev, region->type));
     301                 :          0 :         return NULL;
     302                 :            : }
     303                 :            : 
     304                 :            : int
     305                 :          0 : ftl_md_unlink(struct spdk_ftl_dev *dev, const char *name, int flags)
     306                 :            : {
     307                 :          0 :         struct ftl_md md = { 0 };
     308                 :            : 
     309         [ #  # ]:          0 :         if (0 == (flags & FTL_MD_CREATE_SHM)) {
     310                 :            :                 /* Unlink can be called for shared memory only */
     311                 :          0 :                 return -EINVAL;
     312                 :            :         }
     313                 :            : 
     314                 :          0 :         md.dev = dev;
     315                 :          0 :         ftl_md_setup_obj(&md, flags, name);
     316                 :            : 
     317                 :          0 :         return md.shm_unlink(md.name);
     318                 :            : }
     319                 :            : 
     320                 :            : void
     321                 :        485 : ftl_md_destroy(struct ftl_md *md, int flags)
     322                 :            : {
     323         [ +  + ]:        485 :         if (!md) {
     324                 :          1 :                 return;
     325                 :            :         }
     326                 :            : 
     327   [ -  +  +  + ]:        484 :         if (!md->is_mirror) {
     328                 :        396 :                 ftl_md_free_buf(md, flags);
     329                 :        396 :                 spdk_free(md->entry_vss_dma_buf);
     330                 :            :         }
     331                 :        484 :         free(md);
     332                 :            : }
     333                 :            : 
     334                 :            : void
     335                 :        484 : ftl_md_free_buf(struct ftl_md *md, int flags)
     336                 :            : {
     337         [ -  + ]:        484 :         if (!md) {
     338                 :          0 :                 return;
     339                 :            :         }
     340                 :            : 
     341         [ +  + ]:        484 :         if (md->shm_fd < 0) {
     342         [ -  + ]:        176 :                 assert(flags == 0);
     343                 :        176 :                 ftl_md_destroy_heap(md);
     344                 :            :         } else {
     345                 :        308 :                 ftl_md_destroy_shm(md, flags);
     346                 :            :         }
     347                 :            : }
     348                 :            : 
     349                 :            : void *
     350                 :    1755211 : ftl_md_get_buffer(struct ftl_md *md)
     351                 :            : {
     352                 :    1755211 :         return md->data;
     353                 :            : }
     354                 :            : 
     355                 :            : uint64_t
     356                 :        329 : ftl_md_get_buffer_size(struct ftl_md *md)
     357                 :            : {
     358                 :        329 :         return md->data_blocks * FTL_BLOCK_SIZE;
     359                 :            : }
     360                 :            : 
     361                 :            : static void
     362                 :        438 : ftl_md_vss_buf_init(union ftl_md_vss *buf, uint32_t count,
     363                 :            :                     const union ftl_md_vss *vss_pattern)
     364                 :            : {
     365         [ +  + ]:     207354 :         while (count) {
     366                 :     206916 :                 count--;
     367                 :     206916 :                 buf[count] = *vss_pattern;
     368                 :            :         }
     369                 :        438 : }
     370                 :            : 
     371                 :         88 : union ftl_md_vss *ftl_md_vss_buf_alloc(struct ftl_layout_region *region, uint32_t count)
     372                 :            : {
     373                 :         88 :         union ftl_md_vss *buf = spdk_zmalloc(count * FTL_MD_VSS_SZ, FTL_BLOCK_SIZE, NULL,
     374                 :            :                                                      SPDK_ENV_LCORE_ID_ANY,
     375                 :            :                                                      SPDK_MALLOC_DMA);
     376                 :            : 
     377         [ -  + ]:         88 :         if (!buf) {
     378                 :          0 :                 return NULL;
     379                 :            :         }
     380                 :            : 
     381                 :         88 :         union ftl_md_vss vss_buf = {0};
     382                 :         88 :         vss_buf.version.md_version = region->current.version;
     383                 :         88 :         ftl_md_vss_buf_init(buf, count, &vss_buf);
     384                 :         88 :         return buf;
     385                 :            : }
     386                 :            : 
     387                 :         11 : union ftl_md_vss *ftl_md_get_vss_buffer(struct ftl_md *md)
     388                 :            : {
     389                 :         11 :         return md->vss_data;
     390                 :            : }
     391                 :            : 
     392                 :            : static void
     393                 :        508 : io_cleanup(struct ftl_md *md)
     394                 :            : {
     395                 :        508 :         spdk_dma_free(md->io.data);
     396                 :        508 :         md->io.data = NULL;
     397                 :            : 
     398                 :        508 :         spdk_dma_free(md->io.md);
     399                 :        508 :         md->io.md = NULL;
     400                 :        508 : }
     401                 :            : 
     402                 :            : static void
     403                 :          0 : exception(void *arg)
     404                 :            : {
     405                 :          0 :         struct ftl_md *md = arg;
     406                 :            : 
     407                 :          0 :         md->cb(md->dev, md, -EINVAL);
     408                 :          0 :         io_cleanup(md);
     409                 :          0 : }
     410                 :            : 
     411                 :            : static inline enum ftl_stats_type
     412                 :      12023 : get_bdev_io_ftl_stats_type(struct spdk_ftl_dev *dev, struct spdk_bdev_io *bdev_io) {
     413                 :      12023 :         struct spdk_bdev *nvc = spdk_bdev_desc_get_bdev(dev->nv_cache.bdev_desc);
     414                 :            : 
     415         [ +  + ]:      12023 :         if (bdev_io->bdev == nvc)
     416                 :            :         {
     417                 :      11919 :                 return FTL_STATS_TYPE_MD_NV_CACHE;
     418                 :            :         } else
     419                 :            :         {
     420                 :        104 :                 return FTL_STATS_TYPE_MD_BASE;
     421                 :            :         }
     422                 :            : }
     423                 :            : 
     424                 :            : static void
     425                 :       5601 : audit_md_vss_version(struct ftl_md *md, uint64_t blocks)
     426                 :            : {
     427                 :            : #if defined(DEBUG)
     428                 :       5601 :         union ftl_md_vss *vss = md->io.md;
     429                 :            :         /* Need to load the superblock regardless of its version */
     430         [ +  + ]:       5601 :         if (md->region->type == FTL_LAYOUT_REGION_TYPE_SB) {
     431                 :         82 :                 return;
     432                 :            :         }
     433         [ +  + ]:    5442319 :         while (blocks) {
     434                 :    5436800 :                 blocks--;
     435         [ -  + ]:    5436800 :                 assert(vss[blocks].version.md_version == md->region->current.version);
     436                 :            :         }
     437                 :            : #endif
     438                 :            : }
     439                 :            : 
     440                 :            : static void
     441                 :       5705 : read_write_blocks_cb(struct spdk_bdev_io *bdev_io, bool success, void *arg)
     442                 :            : {
     443                 :       5705 :         struct ftl_md *md = arg;
     444                 :            : 
     445                 :       5705 :         ftl_stats_bdev_io_completed(md->dev, get_bdev_io_ftl_stats_type(md->dev, bdev_io), bdev_io);
     446                 :            : 
     447         [ -  + ]:       5705 :         if (spdk_unlikely(!success)) {
     448   [ #  #  #  # ]:          0 :                 if (md->io.op == FTL_MD_OP_RESTORE && has_mirror(md)) {
     449                 :          0 :                         md->io.status = -EAGAIN;
     450                 :            :                 } else {
     451                 :          0 :                         md->io.status = -EIO;
     452                 :            :                 }
     453                 :            :         } else {
     454                 :       5705 :                 uint64_t blocks = bdev_io->u.bdev.num_blocks;
     455                 :       5705 :                 uint64_t size = blocks * FTL_BLOCK_SIZE;
     456                 :            : 
     457         [ +  + ]:       5705 :                 if (md->io.op == FTL_MD_OP_RESTORE) {
     458   [ -  +  -  + ]:        151 :                         memcpy(md->data + md->io.data_offset, md->io.data, size);
     459                 :            : 
     460         [ +  + ]:        151 :                         if (md->vss_data) {
     461                 :        135 :                                 uint64_t vss_offset = md->io.data_offset / FTL_BLOCK_SIZE;
     462                 :        135 :                                 vss_offset *= FTL_MD_VSS_SZ;
     463                 :        135 :                                 audit_md_vss_version(md, blocks);
     464   [ -  +  -  + ]:        135 :                                 memcpy(md->vss_data + vss_offset, md->io.md, blocks * FTL_MD_VSS_SZ);
     465                 :            :                         }
     466                 :            :                 }
     467                 :            : 
     468                 :       5705 :                 md->io.address += blocks;
     469                 :       5705 :                 md->io.remaining -= blocks;
     470                 :       5705 :                 md->io.data_offset += size;
     471                 :            :         }
     472                 :            : 
     473                 :       5705 :         spdk_bdev_free_io(bdev_io);
     474                 :            : 
     475                 :       5705 :         io_submit(md);
     476                 :       5705 : }
     477                 :            : 
     478                 :            : static inline int
     479                 :        151 : read_blocks(struct spdk_ftl_dev *dev, struct spdk_bdev_desc *desc,
     480                 :            :             struct spdk_io_channel *ch,
     481                 :            :             void *buf, void *md_buf,
     482                 :            :             uint64_t offset_blocks, uint64_t num_blocks,
     483                 :            :             spdk_bdev_io_completion_cb cb, void *cb_arg)
     484                 :            : {
     485         [ +  + ]:        151 :         if (desc == dev->nv_cache.bdev_desc) {
     486                 :        135 :                 return ftl_nv_cache_bdev_read_blocks_with_md(dev, desc, ch, buf, md_buf,
     487                 :            :                                 offset_blocks, num_blocks,
     488                 :            :                                 cb, cb_arg);
     489         [ -  + ]:         16 :         } else if (md_buf) {
     490                 :          0 :                 return spdk_bdev_read_blocks_with_md(desc, ch, buf, md_buf,
     491                 :            :                                                      offset_blocks, num_blocks,
     492                 :            :                                                      cb, cb_arg);
     493                 :            :         } else {
     494                 :         16 :                 return spdk_bdev_read_blocks(desc, ch, buf,
     495                 :            :                                              offset_blocks, num_blocks,
     496                 :            :                                              cb, cb_arg);
     497                 :            :         }
     498                 :            : }
     499                 :            : 
     500                 :            : static inline int
     501                 :      11872 : write_blocks(struct spdk_ftl_dev *dev, struct spdk_bdev_desc *desc,
     502                 :            :              struct spdk_io_channel *ch,
     503                 :            :              void *buf, void *md_buf,
     504                 :            :              uint64_t offset_blocks, uint64_t num_blocks,
     505                 :            :              spdk_bdev_io_completion_cb cb, void *cb_arg)
     506                 :            : {
     507         [ +  + ]:      11872 :         if (desc == dev->nv_cache.bdev_desc) {
     508                 :      11784 :                 return ftl_nv_cache_bdev_write_blocks_with_md(dev, desc, ch, buf, md_buf,
     509                 :            :                                 offset_blocks, num_blocks,
     510                 :            :                                 cb, cb_arg);
     511         [ -  + ]:         88 :         } else if (md_buf) {
     512                 :          0 :                 return spdk_bdev_write_blocks_with_md(desc, ch, buf, md_buf, offset_blocks,
     513                 :            :                                                       num_blocks, cb, cb_arg);
     514                 :            :         } else {
     515                 :         88 :                 return spdk_bdev_write_blocks(desc, ch, buf, offset_blocks, num_blocks, cb, cb_arg);
     516                 :            :         }
     517                 :            : }
     518                 :            : 
     519                 :            : static void
     520                 :       5705 : read_write_blocks(void *_md)
     521                 :            : {
     522                 :       5705 :         struct ftl_md *md = _md;
     523                 :       5705 :         const struct ftl_layout_region *region = md->region;
     524                 :            :         uint64_t blocks;
     525                 :       5705 :         int rc = 0;
     526                 :            : 
     527         [ +  + ]:       5705 :         blocks = spdk_min(md->io.remaining, ftl_md_xfer_blocks(md->dev));
     528                 :            : 
     529      [ +  +  - ]:       5705 :         switch (md->io.op) {
     530                 :        151 :         case FTL_MD_OP_RESTORE:
     531                 :        151 :                 rc = read_blocks(md->dev, region->bdev_desc, region->ioch,
     532                 :            :                                  md->io.data, md->io.md,
     533                 :            :                                  md->io.address, blocks,
     534                 :            :                                  read_write_blocks_cb, md);
     535                 :        151 :                 break;
     536                 :       5554 :         case FTL_MD_OP_PERSIST:
     537                 :            :         case FTL_MD_OP_CLEAR:
     538                 :       5554 :                 rc = write_blocks(md->dev, region->bdev_desc, region->ioch,
     539                 :            :                                   md->io.data, md->io.md,
     540                 :            :                                   md->io.address, blocks,
     541                 :            :                                   read_write_blocks_cb, md);
     542                 :       5554 :                 break;
     543                 :          0 :         default:
     544                 :          0 :                 ftl_abort();
     545                 :            :         }
     546                 :            : 
     547         [ -  + ]:       5705 :         if (spdk_unlikely(rc)) {
     548         [ #  # ]:          0 :                 if (rc == -ENOMEM) {
     549                 :          0 :                         struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(region->bdev_desc);
     550                 :          0 :                         md->io.bdev_io_wait.bdev = bdev;
     551                 :          0 :                         md->io.bdev_io_wait.cb_fn = read_write_blocks;
     552                 :          0 :                         md->io.bdev_io_wait.cb_arg = md;
     553                 :          0 :                         spdk_bdev_queue_io_wait(bdev, region->ioch, &md->io.bdev_io_wait);
     554                 :            :                 } else {
     555                 :          0 :                         ftl_abort();
     556                 :            :                 }
     557                 :            :         }
     558                 :       5705 : }
     559                 :            : 
     560                 :            : static void
     561                 :       6213 : io_submit(struct ftl_md *md)
     562                 :            : {
     563   [ +  +  -  + ]:       6213 :         if (!md->io.remaining || md->io.status) {
     564                 :        508 :                 io_done(md);
     565                 :        508 :                 return;
     566                 :            :         }
     567                 :            : 
     568         [ +  + ]:       5705 :         if (md->io.op == FTL_MD_OP_PERSIST) {
     569         [ +  + ]:        337 :                 uint64_t blocks = spdk_min(md->io.remaining, ftl_md_xfer_blocks(md->dev));
     570                 :            : 
     571   [ -  +  -  + ]:        337 :                 memcpy(md->io.data, md->data + md->io.data_offset, FTL_BLOCK_SIZE * blocks);
     572                 :            : 
     573         [ +  + ]:        337 :                 if (md->vss_data) {
     574                 :        249 :                         uint64_t vss_offset = md->io.data_offset / FTL_BLOCK_SIZE;
     575                 :        249 :                         vss_offset *= FTL_MD_VSS_SZ;
     576         [ -  + ]:        249 :                         assert(md->io.md);
     577   [ -  +  -  + ]:        249 :                         memcpy(md->io.md, md->vss_data + vss_offset, FTL_MD_VSS_SZ * blocks);
     578                 :        249 :                         audit_md_vss_version(md, blocks);
     579                 :            :                 }
     580                 :            :         }
     581                 :            : #if defined(DEBUG)
     582   [ +  +  +  + ]:       5705 :         if (md->io.md && md->io.op == FTL_MD_OP_CLEAR) {
     583         [ +  + ]:       5217 :                 uint64_t blocks = spdk_min(md->io.remaining, ftl_md_xfer_blocks(md->dev));
     584                 :       5217 :                 audit_md_vss_version(md, blocks);
     585                 :            :         }
     586                 :            : #endif
     587                 :            : 
     588                 :       5705 :         read_write_blocks(md);
     589                 :            : }
     590                 :            : 
     591                 :            : static int
     592                 :        508 : io_can_start(struct ftl_md *md)
     593                 :            : {
     594         [ -  + ]:        508 :         assert(NULL == md->io.data);
     595         [ -  + ]:        508 :         if (NULL != md->io.data) {
     596                 :            :                 /* Outgoing IO on metadata */
     597                 :          0 :                 return -EINVAL;
     598                 :            :         }
     599                 :            : 
     600         [ -  + ]:        508 :         if (!md->region) {
     601                 :            :                 /* No device region to process data */
     602                 :          0 :                 return -EINVAL;
     603                 :            :         }
     604                 :            : 
     605         [ -  + ]:        508 :         if (md->region->current.blocks > md->data_blocks) {
     606                 :            :                 /* No device region to process data */
     607         [ #  # ]:          0 :                 FTL_ERRLOG(md->dev, "Blocks number mismatch between metadata object and"
     608                 :            :                            "device region\n");
     609                 :          0 :                 return -EINVAL;
     610                 :            :         }
     611                 :            : 
     612                 :        508 :         return 0;
     613                 :            : }
     614                 :            : 
     615                 :            : static int
     616                 :        508 : io_prepare(struct ftl_md *md, enum ftl_md_ops op)
     617                 :            : {
     618                 :        508 :         const struct ftl_layout_region *region = md->region;
     619                 :        508 :         uint64_t data_size, meta_size = 0;
     620                 :            : 
     621                 :            :         /* Allocates buffer for IO */
     622                 :        508 :         data_size = xfer_size(md);
     623                 :        508 :         md->io.data = spdk_zmalloc(data_size, FTL_BLOCK_SIZE, NULL,
     624                 :            :                                    SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
     625         [ -  + ]:        508 :         if (!md->io.data) {
     626                 :          0 :                 return -ENOMEM;
     627                 :            :         }
     628                 :            : 
     629   [ +  +  +  + ]:        508 :         if (md->vss_data || md->region->vss_blksz) {
     630                 :        404 :                 meta_size = ftl_md_xfer_blocks(md->dev) * FTL_MD_VSS_SZ;
     631                 :        404 :                 md->io.md = spdk_zmalloc(meta_size, FTL_BLOCK_SIZE, NULL,
     632                 :            :                                          SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
     633         [ -  + ]:        404 :                 if (!md->io.md) {
     634                 :          0 :                         spdk_dma_free(md->io.data);
     635                 :          0 :                         md->io.data = NULL;
     636                 :          0 :                         return -ENOMEM;
     637                 :            :                 }
     638                 :            :         }
     639                 :            : 
     640                 :        508 :         md->io.address = region->current.offset;
     641                 :        508 :         md->io.remaining = region->current.blocks;
     642                 :        508 :         md->io.data_offset = 0;
     643                 :        508 :         md->io.status = 0;
     644                 :        508 :         md->io.op = op;
     645                 :            : 
     646                 :        508 :         return 0;
     647                 :            : }
     648                 :            : 
     649                 :            : static int
     650                 :        508 : io_init(struct ftl_md *md, enum ftl_md_ops op)
     651                 :            : {
     652         [ -  + ]:        508 :         if (io_can_start(md)) {
     653                 :          0 :                 return -EINVAL;
     654                 :            :         }
     655                 :            : 
     656         [ -  + ]:        508 :         if (io_prepare(md, op)) {
     657                 :          0 :                 return -ENOMEM;
     658                 :            :         }
     659                 :            : 
     660                 :        508 :         return 0;
     661                 :            : }
     662                 :            : 
     663                 :            : static uint64_t
     664                 :       6318 : persist_entry_lba(struct ftl_md *md, uint64_t start_entry)
     665                 :            : {
     666                 :       6318 :         return md->region->current.offset + start_entry * md->region->entry_size;
     667                 :            : }
     668                 :            : 
     669                 :            : static void
     670                 :       6318 : persist_entry_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
     671                 :            : {
     672                 :       6318 :         struct ftl_md_io_entry_ctx *ctx = cb_arg;
     673                 :       6318 :         struct ftl_md *md = ctx->md;
     674                 :            : 
     675                 :       6318 :         ftl_stats_bdev_io_completed(md->dev, get_bdev_io_ftl_stats_type(md->dev, bdev_io), bdev_io);
     676                 :            : 
     677                 :       6318 :         spdk_bdev_free_io(bdev_io);
     678                 :            : 
     679         [ -  + ]:       6318 :         assert(ctx->remaining > 0);
     680                 :       6318 :         ctx->remaining--;
     681                 :            : 
     682         [ -  + ]:       6318 :         if (!success) {
     683                 :          0 :                 ctx->status = -EIO;
     684                 :            :         }
     685                 :            : 
     686         [ +  + ]:       6318 :         if (!ctx->remaining) {
     687                 :       6237 :                 ctx->cb(ctx->status, ctx->cb_arg);
     688                 :            :         }
     689                 :       6318 : }
     690                 :            : 
     691                 :            : static int
     692                 :       6318 : ftl_md_persist_entry_write_blocks(struct ftl_md_io_entry_ctx *ctx, struct ftl_md *md,
     693                 :            :                                   spdk_bdev_io_wait_cb retry_fn)
     694                 :            : {
     695                 :            :         int rc;
     696                 :            : 
     697                 :       6318 :         rc = write_blocks(md->dev, md->region->bdev_desc, md->region->ioch,
     698                 :            :                           ctx->buffer, ctx->vss_buffer,
     699                 :       6318 :                           persist_entry_lba(md, ctx->start_entry), md->region->entry_size,
     700                 :            :                           persist_entry_cb, ctx);
     701         [ -  + ]:       6318 :         if (spdk_unlikely(rc)) {
     702         [ #  # ]:          0 :                 if (rc == -ENOMEM) {
     703                 :          0 :                         struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(md->region->bdev_desc);
     704                 :          0 :                         ctx->bdev_io_wait.bdev = bdev;
     705                 :          0 :                         ctx->bdev_io_wait.cb_fn = retry_fn;
     706                 :          0 :                         ctx->bdev_io_wait.cb_arg = ctx;
     707                 :          0 :                         spdk_bdev_queue_io_wait(bdev, md->region->ioch, &ctx->bdev_io_wait);
     708                 :            :                 } else {
     709                 :          0 :                         ftl_abort();
     710                 :            :                 }
     711                 :            :         }
     712                 :            : 
     713                 :       6318 :         return rc;
     714                 :            : }
     715                 :            : 
     716                 :            : static void
     717                 :         81 : ftl_md_persist_entry_mirror(void *_ctx)
     718                 :            : {
     719                 :         81 :         struct ftl_md_io_entry_ctx *ctx = _ctx;
     720                 :         81 :         struct ftl_md *md_mirror = ftl_md_get_mirror(ctx->md);
     721                 :            : 
     722                 :         81 :         ftl_md_persist_entry_write_blocks(ctx, md_mirror, ftl_md_persist_entry_mirror);
     723                 :         81 : }
     724                 :            : 
     725                 :            : static void
     726                 :       6237 : ftl_md_persist_entry_primary(void *_ctx)
     727                 :            : {
     728                 :       6237 :         struct ftl_md_io_entry_ctx *ctx = _ctx;
     729                 :       6237 :         struct ftl_md *md = ctx->md;
     730                 :            :         int rc;
     731                 :            : 
     732                 :       6237 :         rc = ftl_md_persist_entry_write_blocks(ctx, md, ftl_md_persist_entry_primary);
     733                 :            : 
     734   [ +  -  +  + ]:       6237 :         if (!rc && has_mirror(md)) {
     735         [ -  + ]:         81 :                 assert(md->region->entry_size == (ftl_md_get_mirror(md))->region->entry_size);
     736                 :            : 
     737                 :            :                 /* The MD object has mirror so execute persist on it too */
     738                 :         81 :                 ftl_md_persist_entry_mirror(ctx);
     739                 :         81 :                 ctx->remaining++;
     740                 :            :         }
     741                 :       6237 : }
     742                 :            : 
     743                 :            : static void
     744                 :       6237 : _ftl_md_persist_entry(struct ftl_md_io_entry_ctx *ctx)
     745                 :            : {
     746                 :       6237 :         ctx->status = 0;
     747                 :       6237 :         ctx->remaining = 1;
     748                 :            : 
     749                 :            :         /* First execute an IO to the primary region */
     750                 :       6237 :         ftl_md_persist_entry_primary(ctx);
     751                 :       6237 : }
     752                 :            : 
     753                 :            : void
     754                 :       6237 : ftl_md_persist_entry(struct ftl_md *md, uint64_t start_entry, void *buffer, void *vss_buffer,
     755                 :            :                      ftl_md_io_entry_cb cb, void *cb_arg,
     756                 :            :                      struct ftl_md_io_entry_ctx *ctx)
     757                 :            : {
     758         [ -  + ]:       6237 :         if (spdk_unlikely(0 == md->region->entry_size)) {
     759                 :            :                 /* This MD has not been configured to support persist entry call */
     760                 :          0 :                 ftl_abort();
     761                 :            :         }
     762                 :            : 
     763                 :            :         /* Initialize persist entry context */
     764                 :       6237 :         ctx->cb = cb;
     765                 :       6237 :         ctx->cb_arg = cb_arg;
     766                 :       6237 :         ctx->md = md;
     767                 :       6237 :         ctx->start_entry = start_entry;
     768                 :       6237 :         ctx->buffer = buffer;
     769         [ +  + ]:       6237 :         ctx->vss_buffer = vss_buffer ? : md->entry_vss_dma_buf;
     770                 :            : 
     771                 :       6237 :         _ftl_md_persist_entry(ctx);
     772                 :       6237 : }
     773                 :            : 
     774                 :            : static void
     775                 :          0 : read_entry_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
     776                 :            : {
     777                 :          0 :         struct ftl_md_io_entry_ctx *ctx = cb_arg;
     778                 :          0 :         struct ftl_md *md = ctx->md;
     779                 :            : 
     780                 :          0 :         ftl_stats_bdev_io_completed(md->dev, get_bdev_io_ftl_stats_type(md->dev, bdev_io), bdev_io);
     781                 :            : 
     782                 :          0 :         spdk_bdev_free_io(bdev_io);
     783                 :            : 
     784         [ #  # ]:          0 :         if (!success) {
     785         [ #  # ]:          0 :                 if (has_mirror(md)) {
     786                 :          0 :                         md->mirror_enabled = true;
     787                 :            : 
     788                 :            :                         /* First read from the mirror */
     789                 :          0 :                         ftl_md_read_entry(ftl_md_get_mirror(md), ctx->start_entry, ctx->buffer,
     790                 :            :                                           ctx->vss_buffer,
     791                 :            :                                           ctx->cb, ctx->cb_arg,
     792                 :            :                                           ctx);
     793                 :          0 :                         return;
     794                 :            :                 } else {
     795                 :          0 :                         ctx->status = -EIO;
     796                 :          0 :                         goto finish_io;
     797                 :            :                 }
     798                 :            :         }
     799                 :            : 
     800                 :          0 : finish_io:
     801                 :          0 :         ctx->cb(ctx->status, ctx->cb_arg);
     802                 :            : }
     803                 :            : 
     804                 :            : static void
     805                 :          0 : ftl_md_read_entry_read_blocks(struct ftl_md_io_entry_ctx *ctx, struct ftl_md *md,
     806                 :            :                               spdk_bdev_io_wait_cb retry_fn)
     807                 :            : {
     808                 :            :         int rc;
     809                 :            : 
     810                 :          0 :         rc = read_blocks(md->dev, md->region->bdev_desc, md->region->ioch,
     811                 :            :                          ctx->buffer, ctx->vss_buffer,
     812                 :          0 :                          persist_entry_lba(md, ctx->start_entry), md->region->entry_size,
     813                 :            :                          read_entry_cb, ctx);
     814                 :            : 
     815         [ #  # ]:          0 :         if (spdk_unlikely(rc)) {
     816         [ #  # ]:          0 :                 if (rc == -ENOMEM) {
     817                 :          0 :                         struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(md->region->bdev_desc);
     818                 :          0 :                         ctx->bdev_io_wait.bdev = bdev;
     819                 :          0 :                         ctx->bdev_io_wait.cb_fn = retry_fn;
     820                 :          0 :                         ctx->bdev_io_wait.cb_arg = ctx;
     821                 :          0 :                         spdk_bdev_queue_io_wait(bdev, md->region->ioch, &ctx->bdev_io_wait);
     822                 :            :                 } else {
     823                 :          0 :                         ftl_abort();
     824                 :            :                 }
     825                 :            :         }
     826                 :          0 : }
     827                 :            : 
     828                 :            : static void
     829                 :          0 : _ftl_md_read_entry(void *_ctx)
     830                 :            : {
     831                 :          0 :         struct ftl_md_io_entry_ctx *ctx = _ctx;
     832                 :            : 
     833                 :          0 :         ftl_md_read_entry_read_blocks(ctx, ctx->md, _ftl_md_read_entry);
     834                 :          0 : }
     835                 :            : 
     836                 :            : void
     837                 :          0 : ftl_md_read_entry(struct ftl_md *md, uint64_t start_entry, void *buffer, void *vss_buffer,
     838                 :            :                   ftl_md_io_entry_cb cb, void *cb_arg,
     839                 :            :                   struct ftl_md_io_entry_ctx *ctx)
     840                 :            : {
     841         [ #  # ]:          0 :         if (spdk_unlikely(0 == md->region->entry_size)) {
     842                 :            :                 /* This MD has not been configured to support read entry call */
     843                 :          0 :                 ftl_abort();
     844                 :            :         }
     845                 :            : 
     846                 :          0 :         ctx->cb = cb;
     847                 :          0 :         ctx->cb_arg = cb_arg;
     848                 :          0 :         ctx->md = md;
     849                 :          0 :         ctx->start_entry = start_entry;
     850                 :          0 :         ctx->buffer = buffer;
     851                 :          0 :         ctx->vss_buffer = vss_buffer;
     852                 :            : 
     853                 :          0 :         _ftl_md_read_entry(ctx);
     854                 :          0 : }
     855                 :            : 
     856                 :            : void
     857                 :          0 : ftl_md_persist_entry_retry(struct ftl_md_io_entry_ctx *ctx)
     858                 :            : {
     859                 :          0 :         _ftl_md_persist_entry(ctx);
     860                 :          0 : }
     861                 :            : 
     862                 :            : static void
     863                 :        146 : persist_mirror_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status)
     864                 :            : {
     865                 :        146 :         struct ftl_md *primary = md->owner.private;
     866                 :            : 
     867         [ -  + ]:        146 :         if (status) {
     868                 :            :                 /* We got an error, stop persist procedure immediately */
     869                 :          0 :                 primary->io.status = status;
     870                 :          0 :                 io_done(primary);
     871                 :            :         } else {
     872                 :            :                 /* Now continue the persist procedure on the primary MD object */
     873         [ +  - ]:        146 :                 if (0 == io_init(primary, FTL_MD_OP_PERSIST)) {
     874                 :        146 :                         io_submit(primary);
     875                 :            :                 } else {
     876                 :          0 :                         spdk_thread_send_msg(spdk_get_thread(), exception, primary);
     877                 :            :                 }
     878                 :            :         }
     879                 :        146 : }
     880                 :            : 
     881                 :            : void
     882                 :        337 : ftl_md_persist(struct ftl_md *md)
     883                 :            : {
     884         [ +  + ]:        337 :         if (has_mirror(md)) {
     885                 :        146 :                 struct ftl_md *md_mirror = ftl_md_get_mirror(md);
     886                 :            : 
     887                 :        146 :                 md->mirror_enabled = true;
     888                 :            : 
     889                 :            :                 /* Set callback and context in mirror */
     890                 :        146 :                 md_mirror->cb = persist_mirror_cb;
     891                 :        146 :                 md_mirror->owner.private = md;
     892                 :            : 
     893                 :            :                 /* First persist the mirror */
     894                 :        146 :                 ftl_md_persist(md_mirror);
     895                 :        146 :                 return;
     896                 :            :         }
     897                 :            : 
     898         [ +  - ]:        191 :         if (0 == io_init(md, FTL_MD_OP_PERSIST)) {
     899                 :        191 :                 io_submit(md);
     900                 :            :         } else {
     901                 :          0 :                 spdk_thread_send_msg(spdk_get_thread(), exception, md);
     902                 :            :         }
     903                 :            : }
     904                 :            : 
     905                 :            : static void
     906                 :          0 : restore_mirror_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status)
     907                 :            : {
     908                 :          0 :         struct ftl_md *primary = md->owner.private;
     909                 :            : 
     910         [ #  # ]:          0 :         if (status) {
     911                 :            :                 /* Cannot restore the object from the mirror too, mark error and fail */
     912                 :          0 :                 primary->io.status = -EIO;
     913                 :          0 :                 io_done(primary);
     914                 :            :         } else {
     915                 :            :                 /*
     916                 :            :                  * Restoring from the mirror successful. Synchronize mirror to the primary.
     917                 :            :                  * Because we read MD content from the mirror, we can disable it, only the primary
     918                 :            :                  * requires persisting.
     919                 :            :                  */
     920                 :          0 :                 primary->io.status = 0;
     921                 :          0 :                 primary->mirror_enabled = false;
     922                 :          0 :                 io_cleanup(primary);
     923                 :          0 :                 ftl_md_persist(primary);
     924                 :          0 :                 primary->mirror_enabled = true;
     925                 :            :         }
     926                 :          0 : }
     927                 :            : 
     928                 :            : static void
     929                 :          3 : restore_sync_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status)
     930                 :            : {
     931                 :          3 :         struct ftl_md *primary = md->owner.private;
     932                 :            : 
     933         [ -  + ]:          3 :         if (status) {
     934                 :            :                 /* Cannot sync the object from the primary to the mirror, mark error and fail */
     935                 :          0 :                 primary->io.status = -EIO;
     936                 :          0 :                 io_done(primary);
     937                 :            :         } else {
     938                 :          3 :                 primary->cb(dev, primary, primary->io.status);
     939                 :          3 :                 io_cleanup(primary);
     940                 :            :         }
     941                 :          3 : }
     942                 :            : 
     943                 :            : static int
     944                 :        151 : restore_done(struct ftl_md *md)
     945                 :            : {
     946         [ -  + ]:        151 :         if (-EAGAIN == md->io.status) {
     947                 :            :                 /* Failed to read MD from primary region, try it from mirror.
     948                 :            :                  * At the moment read the mirror entirely, (TODO) in the
     949                 :            :                  * feature we can restore from primary and mirror region
     950                 :            :                  * with finer granularity.
     951                 :            :                  */
     952                 :            : 
     953         [ #  # ]:          0 :                 if (has_mirror(md)) {
     954                 :          0 :                         struct ftl_md *md_mirror = ftl_md_get_mirror(md);
     955                 :            : 
     956                 :          0 :                         md->mirror_enabled = true;
     957                 :            : 
     958                 :            :                         /* Set callback and context in mirror */
     959                 :          0 :                         md_mirror->cb = restore_mirror_cb;
     960                 :          0 :                         md_mirror->owner.private = md;
     961                 :            : 
     962                 :            :                         /* First persist the mirror */
     963                 :          0 :                         ftl_md_restore(md_mirror);
     964                 :          0 :                         return -EAGAIN;
     965                 :            :                 } else {
     966                 :          0 :                         return -EIO;
     967                 :            :                 }
     968   [ +  -  +  + ]:        151 :         } else if (0 == md->io.status && false == md->dev->sb->clean) {
     969         [ +  + ]:          7 :                 if (has_mirror(md)) {
     970                 :          3 :                         struct ftl_md *md_mirror = ftl_md_get_mirror(md);
     971                 :            :                         /* There was a dirty shutdown, synchronize primary to mirror */
     972                 :            : 
     973                 :            :                         /* Set callback and context in the mirror */
     974                 :          3 :                         md_mirror->cb = restore_sync_cb;
     975                 :          3 :                         md_mirror->owner.private = md;
     976                 :            : 
     977                 :            :                         /* First persist the mirror */
     978                 :          3 :                         ftl_md_persist(md_mirror);
     979                 :          3 :                         return -EAGAIN;
     980                 :            :                 }
     981                 :            :         }
     982                 :            : 
     983                 :        148 :         return md->io.status;
     984                 :            : }
     985                 :            : 
     986                 :            : static void
     987                 :        508 : io_done(struct ftl_md *md)
     988                 :            : {
     989                 :            :         int status;
     990                 :            : 
     991         [ +  + ]:        508 :         if (md->io.op == FTL_MD_OP_RESTORE) {
     992                 :        151 :                 status = restore_done(md);
     993                 :            :         } else {
     994                 :        357 :                 status = md->io.status;
     995                 :            :         }
     996                 :            : 
     997         [ +  + ]:        508 :         if (status != -EAGAIN) {
     998                 :            :                 /* The MD instance may be destroyed in ctx of md->cb(), e.g. upon region upgrade. */
     999                 :            :                 /* Need to cleanup DMA bufs first. */
    1000                 :        505 :                 io_cleanup(md);
    1001                 :        505 :                 md->cb(md->dev, md, status);
    1002                 :            :         }
    1003                 :        508 : }
    1004                 :            : 
    1005                 :            : void
    1006                 :        151 : ftl_md_restore(struct ftl_md *md)
    1007                 :            : {
    1008         [ +  - ]:        151 :         if (0 == io_init(md, FTL_MD_OP_RESTORE)) {
    1009                 :        151 :                 io_submit(md);
    1010                 :            :         } else {
    1011                 :          0 :                 spdk_thread_send_msg(spdk_get_thread(), exception, md);
    1012                 :            :         }
    1013                 :        151 : }
    1014                 :            : 
    1015                 :            : static int
    1016                 :         20 : pattern_prepare(struct ftl_md *md,
    1017                 :            :                 int data_pattern, union ftl_md_vss *vss_pattern)
    1018                 :            : {
    1019                 :         20 :         void *data = md->io.data;
    1020                 :         20 :         uint64_t data_size = xfer_size(md);
    1021                 :            : 
    1022         [ -  + ]:         20 :         memset(data, data_pattern, data_size);
    1023                 :            : 
    1024         [ +  - ]:         20 :         if (md->io.md) {
    1025         [ +  + ]:         20 :                 if (vss_pattern) {
    1026                 :            :                         /* store the VSS pattern... */
    1027                 :          5 :                         ftl_md_vss_buf_init(md->io.md, ftl_md_xfer_blocks(md->dev), vss_pattern);
    1028                 :            :                 } else {
    1029                 :            :                         /* ...or default init VSS to 0 */
    1030                 :         15 :                         union ftl_md_vss vss = {0};
    1031                 :            : 
    1032                 :         15 :                         vss.version.md_version = md->region->current.version;
    1033                 :         15 :                         ftl_md_vss_buf_init(md->io.md, ftl_md_xfer_blocks(md->dev), &vss);
    1034                 :            :                 }
    1035                 :            :         }
    1036                 :            : 
    1037                 :         20 :         return 0;
    1038                 :            : }
    1039                 :            : 
    1040                 :            : static void
    1041                 :          5 : clear_mirror_cb(struct spdk_ftl_dev *dev, struct ftl_md *secondary, int status)
    1042                 :            : {
    1043                 :          5 :         struct ftl_md *primary = secondary->owner.private;
    1044                 :            : 
    1045         [ -  + ]:          5 :         if (status) {
    1046                 :            :                 /* We got an error, stop persist procedure immediately */
    1047                 :          0 :                 primary->io.status = status;
    1048                 :          0 :                 io_done(primary);
    1049                 :            :         } else {
    1050                 :            :                 /* Now continue the persist procedure on the primary MD object */
    1051                 :          5 :                 io_submit(primary);
    1052                 :            :         }
    1053                 :          5 : }
    1054                 :            : 
    1055                 :            : void
    1056                 :         20 : ftl_md_clear(struct ftl_md *md, int data_pattern, union ftl_md_vss *vss_pattern)
    1057                 :            : {
    1058         [ +  + ]:         20 :         if (has_mirror(md)) {
    1059                 :          5 :                 struct ftl_md *md_mirror = ftl_md_get_mirror(md);
    1060                 :            : 
    1061                 :          5 :                 md->mirror_enabled = true;
    1062                 :            : 
    1063                 :            :                 /* Set callback and context in mirror */
    1064                 :          5 :                 md_mirror->cb = clear_mirror_cb;
    1065                 :          5 :                 md_mirror->owner.private = md;
    1066                 :            : 
    1067                 :            :                 /* The pattern bufs will not be available outside of this fn context */
    1068                 :            :                 /* Configure the IO for the primary region now */
    1069   [ +  -  +  - ]:          5 :                 if (0 == io_init(md, FTL_MD_OP_CLEAR) && 0 == pattern_prepare(md, data_pattern, vss_pattern)) {
    1070                 :            :                         /* First persist the mirror */
    1071                 :          5 :                         ftl_md_clear(md_mirror, data_pattern, vss_pattern);
    1072                 :            :                 } else {
    1073                 :          0 :                         spdk_thread_send_msg(spdk_get_thread(), exception, md);
    1074                 :            :                 }
    1075                 :          5 :                 return;
    1076                 :            :         }
    1077                 :            : 
    1078   [ +  -  +  - ]:         15 :         if (0 == io_init(md, FTL_MD_OP_CLEAR) && 0 == pattern_prepare(md, data_pattern, vss_pattern)) {
    1079                 :         15 :                 io_submit(md);
    1080                 :            :         } else {
    1081                 :          0 :                 spdk_thread_send_msg(spdk_get_thread(), exception, md);
    1082                 :            :         }
    1083                 :            : }
    1084                 :            : 
    1085                 :            : const struct ftl_layout_region *
    1086                 :         81 : ftl_md_get_region(struct ftl_md *md)
    1087                 :            : {
    1088                 :         81 :         return md->region;
    1089                 :            : }
    1090                 :            : 
    1091                 :            : void
    1092                 :        352 : ftl_md_set_region(struct ftl_md *md,
    1093                 :            :                   const struct ftl_layout_region *region)
    1094                 :            : {
    1095         [ -  + ]:        352 :         assert(region->current.blocks <= md->data_blocks);
    1096                 :        352 :         md->region = region;
    1097                 :            : 
    1098         [ +  + ]:        352 :         if (md->vss_data) {
    1099                 :        176 :                 union ftl_md_vss vss = {0};
    1100                 :        176 :                 vss.version.md_version = region->current.version;
    1101                 :        176 :                 ftl_md_vss_buf_init(md->vss_data, md->data_blocks, &vss);
    1102         [ +  + ]:        176 :                 if (region->entry_size) {
    1103         [ -  + ]:        154 :                         assert(md->entry_vss_dma_buf);
    1104                 :        154 :                         ftl_md_vss_buf_init(md->entry_vss_dma_buf, region->entry_size, &vss);
    1105                 :            :                 }
    1106                 :            :         }
    1107                 :            : 
    1108         [ +  + ]:        352 :         if (has_mirror(md)) {
    1109                 :         88 :                 md->mirror_enabled = true;
    1110                 :            :         }
    1111                 :        352 : }
    1112                 :            : 
    1113                 :            : int
    1114                 :        198 : ftl_md_create_region_flags(struct spdk_ftl_dev *dev, int region_type)
    1115                 :            : {
    1116                 :        198 :         int flags = FTL_MD_CREATE_SHM;
    1117                 :            : 
    1118   [ +  +  +  + ]:        198 :         switch (region_type) {
    1119                 :         22 :         case FTL_LAYOUT_REGION_TYPE_SB:
    1120         [ +  + ]:         22 :                 if (dev->conf.mode & SPDK_FTL_MODE_CREATE) {
    1121                 :          5 :                         flags |= FTL_MD_CREATE_SHM_NEW;
    1122                 :            :                 }
    1123                 :         22 :                 break;
    1124                 :            : 
    1125                 :         44 :         case FTL_LAYOUT_REGION_TYPE_BAND_MD:
    1126                 :            :         case FTL_LAYOUT_REGION_TYPE_NVC_MD:
    1127         [ +  - ]:         44 :                 if (!ftl_fast_startup(dev)) {
    1128                 :         44 :                         flags |= FTL_MD_CREATE_SHM_NEW;
    1129                 :            :                 }
    1130                 :         44 :                 break;
    1131                 :         44 :         case FTL_LAYOUT_REGION_TYPE_VALID_MAP:
    1132                 :            :         case FTL_LAYOUT_REGION_TYPE_TRIM_MD:
    1133   [ +  -  +  + ]:         44 :                 if (!ftl_fast_startup(dev) && !ftl_fast_recovery(dev)) {
    1134                 :         42 :                         flags |= FTL_MD_CREATE_SHM_NEW;
    1135                 :            :                 }
    1136                 :         44 :                 break;
    1137                 :         88 :         default:
    1138                 :         88 :                 return FTL_MD_CREATE_HEAP;
    1139                 :            :         }
    1140                 :            : 
    1141                 :        110 :         return flags;
    1142                 :            : }
    1143                 :            : 
    1144                 :            : int
    1145                 :        440 : ftl_md_destroy_region_flags(struct spdk_ftl_dev *dev, int region_type)
    1146                 :            : {
    1147         [ +  + ]:        440 :         switch (region_type) {
    1148                 :        110 :         case FTL_LAYOUT_REGION_TYPE_SB:
    1149                 :            :         case FTL_LAYOUT_REGION_TYPE_BAND_MD:
    1150                 :            :         case FTL_LAYOUT_REGION_TYPE_VALID_MAP:
    1151                 :            :         case FTL_LAYOUT_REGION_TYPE_NVC_MD:
    1152                 :            :         case FTL_LAYOUT_REGION_TYPE_TRIM_MD:
    1153   [ -  +  -  + ]:        110 :                 if (dev->conf.fast_shutdown) {
    1154                 :          0 :                         return FTL_MD_DESTROY_SHM_KEEP;
    1155                 :            :                 }
    1156                 :        110 :                 break;
    1157                 :            : 
    1158                 :        330 :         default:
    1159                 :        330 :                 break;
    1160                 :            :         }
    1161                 :        440 :         return 0;
    1162                 :            : }
    1163                 :            : 
    1164                 :            : int
    1165                 :        110 : ftl_md_create_shm_flags(struct spdk_ftl_dev *dev)
    1166                 :            : {
    1167                 :        110 :         int flags = FTL_MD_CREATE_SHM;
    1168                 :            : 
    1169   [ +  -  +  + ]:        110 :         if (!ftl_fast_startup(dev) && !ftl_fast_recovery(dev)) {
    1170                 :        105 :                 flags |= FTL_MD_CREATE_SHM_NEW;
    1171                 :            :         }
    1172                 :        110 :         return flags;
    1173                 :            : }
    1174                 :            : 
    1175                 :            : int
    1176                 :        132 : ftl_md_destroy_shm_flags(struct spdk_ftl_dev *dev)
    1177                 :            : {
    1178         [ -  + ]:        132 :         return (dev->conf.fast_shutdown) ? FTL_MD_DESTROY_SHM_KEEP : 0;
    1179                 :            : }

Generated by: LCOV version 1.14