LCOV - code coverage report
Current view: top level - spdk/lib/ftl/utils - ftl_md.c (source / functions) Hit Total Coverage
Test: Combined Lines: 405 579 69.9 %
Date: 2024-07-15 11:23:48 Functions: 50 61 82.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 189 323 58.5 %

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

Generated by: LCOV version 1.14