LCOV - code coverage report
Current view: top level - lib/ftl/utils - ftl_md.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 0 578 0.0 %
Date: 2024-12-06 22:23:36 Functions: 0 61 0.0 %

          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           0 : has_mirror(struct ftl_md *md)
      20             : {
      21           0 :         if (md->region) {
      22           0 :                 if (md->region->mirror_type != FTL_LAYOUT_REGION_TYPE_INVALID) {
      23           0 :                         return md->mirror_enabled;
      24             :                 }
      25             :         }
      26             : 
      27           0 :         return false;
      28             : }
      29             : 
      30             : static struct ftl_md *
      31           0 : ftl_md_get_mirror(struct ftl_md *md)
      32             : {
      33           0 :         if (has_mirror(md)) {
      34           0 :                 return md->dev->layout.md[md->region->mirror_type];
      35             :         }
      36             : 
      37           0 :         return NULL;
      38             : }
      39             : 
      40             : uint64_t
      41           0 : ftl_md_xfer_blocks(struct spdk_ftl_dev *dev)
      42             : {
      43           0 :         return 4ULL * dev->xfer_size;
      44             : }
      45             : 
      46             : static uint64_t
      47           0 : xfer_size(struct ftl_md *md)
      48             : {
      49           0 :         return ftl_md_xfer_blocks(md->dev) * FTL_BLOCK_SIZE;
      50             : }
      51             : 
      52             : static void
      53           0 : ftl_md_create_spdk_buf(struct ftl_md *md, uint64_t vss_blksz)
      54             : {
      55           0 :         md->shm_fd = -1;
      56           0 :         md->vss_data = NULL;
      57           0 :         md->data = spdk_zmalloc(md->data_blocks * (FTL_BLOCK_SIZE + vss_blksz), FTL_BLOCK_SIZE, NULL,
      58             :                                 SPDK_ENV_NUMA_ID_ANY, SPDK_MALLOC_DMA);
      59             : 
      60           0 :         if (md->data && vss_blksz) {
      61           0 :                 md->vss_data = ((char *)md->data) + md->data_blocks * FTL_BLOCK_SIZE;
      62             :         }
      63           0 : }
      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           0 : ftl_md_destroy_spdk_buf(struct ftl_md *md)
      79             : {
      80           0 :         if (md->data) {
      81           0 :                 spdk_free(md->data);
      82           0 :                 md->data = NULL;
      83           0 :                 md->vss_data = NULL;
      84             :         }
      85           0 : }
      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           0 : ftl_wrapper_open(const char *name, int of, mode_t m)
      99             : {
     100           0 :         return open(name, of, m);
     101             : }
     102             : 
     103             : static void
     104           0 : ftl_md_setup_obj(struct ftl_md *md, int flags,
     105             :                  const char *name)
     106             : {
     107           0 :         char uuid_str[SPDK_UUID_STRING_LEN];
     108             :         const char *fmt;
     109             : 
     110           0 :         if (!(flags & FTL_MD_CREATE_SHM)) {
     111           0 :                 assert(false);
     112             :                 return;
     113             :         }
     114             : 
     115             :         /* TODO: temporary, define a proper hugetlbfs mountpoint */
     116           0 :         fmt = "/dev/hugepages/ftl_%s_%s";
     117           0 :         md->shm_mmap_flags = MAP_SHARED;
     118           0 :         md->shm_open = ftl_wrapper_open;
     119           0 :         md->shm_unlink = unlink;
     120             : 
     121           0 :         if (name == NULL ||
     122           0 :             spdk_uuid_fmt_lower(uuid_str, SPDK_UUID_STRING_LEN, &md->dev->conf.uuid) ||
     123           0 :             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           0 : ftl_md_invalidate_shm(struct ftl_md *md)
     131             : {
     132           0 :         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           0 : }
     137             : 
     138             : static void
     139           0 : ftl_md_create_shm(struct ftl_md *md, uint64_t vss_blksz, int flags)
     140             : {
     141           0 :         struct stat shm_stat;
     142             :         size_t vss_blk_offs;
     143             :         void *shm_ptr;
     144           0 :         int open_flags = O_RDWR;
     145           0 :         mode_t open_mode = S_IRUSR | S_IWUSR;
     146             : 
     147           0 :         assert(md->shm_open && md->shm_unlink);
     148           0 :         md->data = NULL;
     149           0 :         md->vss_data = NULL;
     150           0 :         md->shm_sz = 0;
     151             : 
     152             :         /* Must have an object name */
     153           0 :         if (md->name[0] == 0) {
     154           0 :                 assert(false);
     155             :                 return;
     156             :         }
     157             : 
     158             :         /* If specified, unlink before create a new SHM object */
     159           0 :         if (flags & FTL_MD_CREATE_SHM_NEW) {
     160           0 :                 if (md->shm_unlink(md->name) < 0 && errno != ENOENT) {
     161           0 :                         ftl_md_invalidate_shm(md);
     162           0 :                         return;
     163             :                 }
     164           0 :                 open_flags += O_CREAT | O_TRUNC;
     165             :         }
     166             : 
     167             :         /* Open existing or create a new SHM object, then query its props */
     168           0 :         md->shm_fd = md->shm_open(md->name, open_flags, open_mode);
     169           0 :         if (md->shm_fd < 0 || fstat(md->shm_fd, &shm_stat) < 0) {
     170           0 :                 goto err_shm;
     171             :         }
     172             : 
     173             :         /* Verify open mode hasn't changed */
     174           0 :         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           0 :         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           0 :         vss_blk_offs = md->shm_sz;
     183             : 
     184           0 :         if (vss_blksz) {
     185           0 :                 md->shm_sz += spdk_divide_round_up(md->data_blocks * vss_blksz,
     186           0 :                                                    shm_stat.st_blksize);
     187             :         }
     188             : 
     189             :         /* Total SHM obj size */
     190           0 :         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           0 :         if ((shm_stat.st_size == 0 && (ftruncate(md->shm_fd, md->shm_sz) < 0 ||
     194           0 :                                        (flags & FTL_MD_CREATE_SHM_NEW) == 0))
     195           0 :             || (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           0 :         shm_ptr = mmap(NULL, md->shm_sz, PROT_READ | PROT_WRITE, md->shm_mmap_flags,
     201             :                        md->shm_fd, 0);
     202           0 :         if (shm_ptr == MAP_FAILED) {
     203           0 :                 goto err_shm;
     204             :         }
     205             : 
     206           0 :         md->data = shm_ptr;
     207           0 :         if (vss_blksz) {
     208           0 :                 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           0 :         if (mlock(md->data, md->shm_sz) < 0) {
     213           0 :                 goto err_map;
     214             :         }
     215             : 
     216           0 :         if (spdk_mem_register(md->data, md->shm_sz)) {
     217           0 :                 goto err_mlock;
     218             :         }
     219           0 :         md->mem_reg = true;
     220             : 
     221           0 :         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           0 : err_shm:
     234           0 :         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           0 :         ftl_md_invalidate_shm(md);
     240             : }
     241             : 
     242             : static void
     243           0 : ftl_md_destroy_shm(struct ftl_md *md, int flags)
     244             : {
     245           0 :         if (!md->data) {
     246           0 :                 return;
     247             :         }
     248             : 
     249           0 :         assert(md->shm_sz > 0);
     250           0 :         if (md->mem_reg) {
     251           0 :                 spdk_mem_unregister(md->data, md->shm_sz);
     252           0 :                 md->mem_reg = false;
     253             :         }
     254             : 
     255             :         /* Unlock the pages in memory */
     256           0 :         munlock(md->data, md->shm_sz);
     257             : 
     258             :         /* Remove the virtual memory mapping for the object */
     259           0 :         munmap(md->data, md->shm_sz);
     260             : 
     261             :         /* Close SHM object fd */
     262           0 :         close(md->shm_fd);
     263             : 
     264           0 :         md->data = NULL;
     265           0 :         md->vss_data = NULL;
     266             : 
     267             :         /* If specified, keep the object in SHM */
     268           0 :         if (flags & FTL_MD_DESTROY_SHM_KEEP) {
     269           0 :                 return;
     270             :         }
     271             : 
     272             :         /* Otherwise destroy/unlink the object */
     273           0 :         assert(md->name[0] != 0 && md->shm_unlink != NULL);
     274           0 :         md->shm_unlink(md->name);
     275             : }
     276             : 
     277           0 : 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           0 :         md = calloc(1, sizeof(*md));
     284           0 :         if (!md) {
     285           0 :                 return NULL;
     286             :         }
     287           0 :         md->dev = dev;
     288           0 :         md->data_blocks = blocks;
     289           0 :         md->mirror_enabled = true;
     290             : 
     291           0 :         if (flags != FTL_MD_CREATE_NO_MEM) {
     292           0 :                 if (flags & FTL_MD_CREATE_SHM) {
     293           0 :                         ftl_md_setup_obj(md, flags, name);
     294           0 :                         ftl_md_create_shm(md, vss_blksz, flags);
     295           0 :                 } else if (flags & FTL_MD_CREATE_SPDK_BUF) {
     296           0 :                         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           0 :                 if (!md->data) {
     303           0 :                         free(md);
     304           0 :                         return NULL;
     305             :                 }
     306             :         }
     307             : 
     308           0 :         if (region) {
     309           0 :                 size_t entry_vss_buf_size = vss_blksz * region->entry_size;
     310             : 
     311           0 :                 if (entry_vss_buf_size) {
     312           0 :                         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           0 :                         if (!md->entry_vss_dma_buf) {
     316           0 :                                 goto err;
     317             :                         }
     318             :                 }
     319             : 
     320           0 :                 ftl_md_set_region(md, region);
     321             :         }
     322             : 
     323           0 :         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           0 : ftl_md_destroy(struct ftl_md *md, int flags)
     347             : {
     348           0 :         if (!md) {
     349           0 :                 return;
     350             :         }
     351             : 
     352           0 :         if (!md->is_mirror) {
     353           0 :                 ftl_md_free_buf(md, flags);
     354           0 :                 spdk_free(md->entry_vss_dma_buf);
     355             :         }
     356           0 :         free(md);
     357             : }
     358             : 
     359             : void
     360           0 : ftl_md_free_buf(struct ftl_md *md, int flags)
     361             : {
     362           0 :         if (!md) {
     363           0 :                 return;
     364             :         }
     365             : 
     366           0 :         if (md->shm_fd < 0) {
     367           0 :                 if (flags & FTL_MD_DESTROY_SPDK_BUF) {
     368           0 :                         ftl_md_destroy_spdk_buf(md);
     369             :                 } else {
     370           0 :                         assert(flags == 0);
     371           0 :                         ftl_md_destroy_heap(md);
     372             :                 }
     373             :         } else {
     374           0 :                 ftl_md_destroy_shm(md, flags);
     375             :         }
     376             : }
     377             : 
     378             : void *
     379           0 : ftl_md_get_buffer(struct ftl_md *md)
     380             : {
     381           0 :         return md->data;
     382             : }
     383             : 
     384             : uint64_t
     385           0 : ftl_md_get_buffer_size(struct ftl_md *md)
     386             : {
     387           0 :         return md->data_blocks * FTL_BLOCK_SIZE;
     388             : }
     389             : 
     390             : static void
     391           0 : ftl_md_vss_buf_init(union ftl_md_vss *buf, uint32_t count,
     392             :                     const union ftl_md_vss *vss_pattern)
     393             : {
     394           0 :         while (count) {
     395           0 :                 count--;
     396           0 :                 buf[count] = *vss_pattern;
     397             :         }
     398           0 : }
     399             : 
     400           0 : union ftl_md_vss *ftl_md_vss_buf_alloc(struct ftl_layout_region *region, uint32_t count)
     401             : {
     402           0 :         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           0 :         if (!buf) {
     407           0 :                 return NULL;
     408             :         }
     409             : 
     410           0 :         union ftl_md_vss vss_buf = {0};
     411           0 :         vss_buf.version.md_version = region->current.version;
     412           0 :         ftl_md_vss_buf_init(buf, count, &vss_buf);
     413           0 :         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           0 : io_cleanup(struct ftl_md *md)
     423             : {
     424           0 :         spdk_dma_free(md->io.data);
     425           0 :         md->io.data = NULL;
     426             : 
     427           0 :         spdk_dma_free(md->io.md);
     428           0 :         md->io.md = NULL;
     429           0 : }
     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           0 : get_bdev_io_ftl_stats_type(struct spdk_ftl_dev *dev, struct spdk_bdev_io *bdev_io) {
     442           0 :         struct spdk_bdev *nvc = spdk_bdev_desc_get_bdev(dev->nv_cache.bdev_desc);
     443             : 
     444           0 :         if (bdev_io->bdev == nvc)
     445             :         {
     446           0 :                 return FTL_STATS_TYPE_MD_NV_CACHE;
     447             :         } else
     448             :         {
     449           0 :                 return FTL_STATS_TYPE_MD_BASE;
     450             :         }
     451             : }
     452             : 
     453             : static void
     454           0 : read_write_blocks_cb(struct spdk_bdev_io *bdev_io, bool success, void *arg)
     455             : {
     456           0 :         struct ftl_md *md = arg;
     457             : 
     458           0 :         ftl_stats_bdev_io_completed(md->dev, get_bdev_io_ftl_stats_type(md->dev, bdev_io), bdev_io);
     459             : 
     460           0 :         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           0 :                 uint64_t blocks = bdev_io->u.bdev.num_blocks;
     468           0 :                 uint64_t size = blocks * FTL_BLOCK_SIZE;
     469             : 
     470           0 :                 if (md->io.op == FTL_MD_OP_RESTORE) {
     471           0 :                         memcpy(md->data + md->io.data_offset, md->io.data, size);
     472             : 
     473           0 :                         if (md->vss_data) {
     474           0 :                                 uint64_t vss_offset = md->io.data_offset / FTL_BLOCK_SIZE;
     475           0 :                                 vss_offset *= FTL_MD_VSS_SZ;
     476           0 :                                 memcpy(md->vss_data + vss_offset, md->io.md, blocks * FTL_MD_VSS_SZ);
     477             :                         }
     478             :                 }
     479             : 
     480           0 :                 md->io.address += blocks;
     481           0 :                 md->io.remaining -= blocks;
     482           0 :                 md->io.data_offset += size;
     483             :         }
     484             : 
     485           0 :         spdk_bdev_free_io(bdev_io);
     486             : 
     487           0 :         io_submit(md);
     488           0 : }
     489             : 
     490             : static inline int
     491           0 : 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           0 :         if (desc == dev->nv_cache.bdev_desc) {
     498           0 :                 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           0 :         } 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           0 :                 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           0 : 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           0 :         if (desc == dev->nv_cache.bdev_desc) {
     520           0 :                 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           0 :         } 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           0 :                 return spdk_bdev_write_blocks(desc, ch, buf, offset_blocks, num_blocks, cb, cb_arg);
     528             :         }
     529             : }
     530             : 
     531             : static void
     532           0 : read_write_blocks(void *_md)
     533             : {
     534           0 :         struct ftl_md *md = _md;
     535           0 :         const struct ftl_layout_region *region = md->region;
     536             :         uint64_t blocks;
     537           0 :         int rc = 0;
     538             : 
     539           0 :         blocks = spdk_min(md->io.remaining, ftl_md_xfer_blocks(md->dev));
     540             : 
     541           0 :         switch (md->io.op) {
     542           0 :         case FTL_MD_OP_RESTORE:
     543           0 :                 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           0 :                 break;
     548           0 :         case FTL_MD_OP_PERSIST:
     549             :         case FTL_MD_OP_CLEAR:
     550           0 :                 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           0 :                 break;
     555           0 :         default:
     556           0 :                 ftl_abort();
     557             :         }
     558             : 
     559           0 :         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           0 : }
     571             : 
     572             : static void
     573           0 : io_submit(struct ftl_md *md)
     574             : {
     575           0 :         if (!md->io.remaining || md->io.status) {
     576           0 :                 io_done(md);
     577           0 :                 return;
     578             :         }
     579             : 
     580           0 :         if (md->io.op == FTL_MD_OP_PERSIST) {
     581           0 :                 uint64_t blocks = spdk_min(md->io.remaining, ftl_md_xfer_blocks(md->dev));
     582             : 
     583           0 :                 memcpy(md->io.data, md->data + md->io.data_offset, FTL_BLOCK_SIZE * blocks);
     584             : 
     585           0 :                 if (md->vss_data) {
     586           0 :                         uint64_t vss_offset = md->io.data_offset / FTL_BLOCK_SIZE;
     587           0 :                         vss_offset *= FTL_MD_VSS_SZ;
     588           0 :                         assert(md->io.md);
     589           0 :                         memcpy(md->io.md, md->vss_data + vss_offset, FTL_MD_VSS_SZ * blocks);
     590             :                 }
     591             :         }
     592             : 
     593           0 :         read_write_blocks(md);
     594             : }
     595             : 
     596             : static int
     597           0 : io_can_start(struct ftl_md *md)
     598             : {
     599           0 :         assert(NULL == md->io.data);
     600           0 :         if (NULL != md->io.data) {
     601             :                 /* Outgoing IO on metadata */
     602           0 :                 return -EINVAL;
     603             :         }
     604             : 
     605           0 :         if (!md->region) {
     606             :                 /* No device region to process data */
     607           0 :                 return -EINVAL;
     608             :         }
     609             : 
     610           0 :         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           0 :         return 0;
     618             : }
     619             : 
     620             : static int
     621           0 : io_prepare(struct ftl_md *md, enum ftl_md_ops op)
     622             : {
     623           0 :         const struct ftl_layout_region *region = md->region;
     624           0 :         uint64_t data_size, meta_size = 0;
     625             : 
     626             :         /* Allocates buffer for IO */
     627           0 :         data_size = xfer_size(md);
     628           0 :         md->io.data = spdk_zmalloc(data_size, FTL_BLOCK_SIZE, NULL,
     629             :                                    SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
     630           0 :         if (!md->io.data) {
     631           0 :                 return -ENOMEM;
     632             :         }
     633             : 
     634           0 :         if (md->vss_data || md->region->vss_blksz) {
     635           0 :                 meta_size = ftl_md_xfer_blocks(md->dev) * FTL_MD_VSS_SZ;
     636           0 :                 md->io.md = spdk_zmalloc(meta_size, FTL_BLOCK_SIZE, NULL,
     637             :                                          SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
     638           0 :                 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           0 :         md->io.address = region->current.offset;
     646           0 :         md->io.remaining = region->current.blocks;
     647           0 :         md->io.data_offset = 0;
     648           0 :         md->io.status = 0;
     649           0 :         md->io.op = op;
     650             : 
     651           0 :         return 0;
     652             : }
     653             : 
     654             : static int
     655           0 : io_init(struct ftl_md *md, enum ftl_md_ops op)
     656             : {
     657           0 :         if (io_can_start(md)) {
     658           0 :                 return -EINVAL;
     659             :         }
     660             : 
     661           0 :         if (io_prepare(md, op)) {
     662           0 :                 return -ENOMEM;
     663             :         }
     664             : 
     665           0 :         return 0;
     666             : }
     667             : 
     668             : static uint64_t
     669           0 : persist_entry_lba(struct ftl_md *md, uint64_t start_entry)
     670             : {
     671           0 :         return md->region->current.offset + start_entry * md->region->entry_size;
     672             : }
     673             : 
     674             : static void
     675           0 : persist_entry_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
     676             : {
     677           0 :         struct ftl_md_io_entry_ctx *ctx = cb_arg;
     678           0 :         struct ftl_md *md = ctx->md;
     679             : 
     680           0 :         ftl_stats_bdev_io_completed(md->dev, get_bdev_io_ftl_stats_type(md->dev, bdev_io), bdev_io);
     681             : 
     682           0 :         spdk_bdev_free_io(bdev_io);
     683             : 
     684           0 :         assert(ctx->remaining > 0);
     685           0 :         ctx->remaining--;
     686             : 
     687           0 :         if (!success) {
     688           0 :                 ctx->status = -EIO;
     689             :         }
     690             : 
     691           0 :         if (!ctx->remaining) {
     692           0 :                 ctx->cb(ctx->status, ctx->cb_arg);
     693             :         }
     694           0 : }
     695             : 
     696             : static int
     697           0 : 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           0 :         rc = write_blocks(md->dev, md->region->bdev_desc, md->region->ioch,
     703             :                           ctx->buffer, ctx->vss_buffer,
     704           0 :                           persist_entry_lba(md, ctx->start_entry), md->region->entry_size * ctx->num_entries,
     705             :                           persist_entry_cb, ctx);
     706           0 :         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           0 :         return rc;
     719             : }
     720             : 
     721             : static void
     722           0 : ftl_md_persist_entry_mirror(void *_ctx)
     723             : {
     724           0 :         struct ftl_md_io_entry_ctx *ctx = _ctx;
     725           0 :         struct ftl_md *md_mirror = ftl_md_get_mirror(ctx->md);
     726             : 
     727           0 :         ftl_md_persist_entry_write_blocks(ctx, md_mirror, ftl_md_persist_entry_mirror);
     728           0 : }
     729             : 
     730             : static void
     731           0 : ftl_md_persist_entry_primary(void *_ctx)
     732             : {
     733           0 :         struct ftl_md_io_entry_ctx *ctx = _ctx;
     734           0 :         struct ftl_md *md = ctx->md;
     735             :         int rc;
     736             : 
     737           0 :         rc = ftl_md_persist_entry_write_blocks(ctx, md, ftl_md_persist_entry_primary);
     738             : 
     739           0 :         if (!rc && has_mirror(md)) {
     740           0 :                 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           0 :                 ftl_md_persist_entry_mirror(ctx);
     744           0 :                 ctx->remaining++;
     745             :         }
     746           0 : }
     747             : 
     748             : static void
     749           0 : _ftl_md_persist_entry(struct ftl_md_io_entry_ctx *ctx)
     750             : {
     751           0 :         ctx->status = 0;
     752           0 :         ctx->remaining = 1;
     753             : 
     754             :         /* First execute an IO to the primary region */
     755           0 :         ftl_md_persist_entry_primary(ctx);
     756           0 : }
     757             : 
     758             : void
     759           0 : 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           0 :         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           0 :         if (spdk_unlikely(start_entry + num_entries > md->region->num_entries)) {
     768             :                 /* Exceeding number of available entries */
     769           0 :                 ftl_abort();
     770             :         }
     771             : 
     772             :         /* Initialize persist entry context */
     773           0 :         ctx->cb = cb;
     774           0 :         ctx->cb_arg = cb_arg;
     775           0 :         ctx->md = md;
     776           0 :         ctx->start_entry = start_entry;
     777           0 :         ctx->buffer = buffer;
     778           0 :         ctx->num_entries = num_entries;
     779           0 :         ctx->vss_buffer = vss_buffer ? : md->entry_vss_dma_buf;
     780             : 
     781           0 :         _ftl_md_persist_entry(ctx);
     782           0 : }
     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           0 : persist_mirror_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status)
     874             : {
     875           0 :         struct ftl_md *primary = md->owner.private;
     876             : 
     877           0 :         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           0 :                 if (0 == io_init(primary, FTL_MD_OP_PERSIST)) {
     884           0 :                         io_submit(primary);
     885             :                 } else {
     886           0 :                         spdk_thread_send_msg(spdk_get_thread(), exception, primary);
     887             :                 }
     888             :         }
     889           0 : }
     890             : 
     891             : void
     892           0 : ftl_md_persist(struct ftl_md *md)
     893             : {
     894           0 :         if (has_mirror(md)) {
     895           0 :                 struct ftl_md *md_mirror = ftl_md_get_mirror(md);
     896             : 
     897           0 :                 md->mirror_enabled = true;
     898             : 
     899             :                 /* Set callback and context in mirror */
     900           0 :                 md_mirror->cb = persist_mirror_cb;
     901           0 :                 md_mirror->owner.private = md;
     902             : 
     903             :                 /* First persist the mirror */
     904           0 :                 ftl_md_persist(md_mirror);
     905           0 :                 return;
     906             :         }
     907             : 
     908           0 :         if (0 == io_init(md, FTL_MD_OP_PERSIST)) {
     909           0 :                 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           0 : restore_sync_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status)
     940             : {
     941           0 :         struct ftl_md *primary = md->owner.private;
     942             : 
     943           0 :         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           0 :                 primary->cb(dev, primary, primary->io.status);
     949           0 :                 io_cleanup(primary);
     950             :         }
     951           0 : }
     952             : 
     953             : static int
     954           0 : restore_done(struct ftl_md *md)
     955             : {
     956           0 :         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           0 :         } else if (0 == md->io.status && false == md->dev->sb->clean) {
     979           0 :                 if (has_mirror(md)) {
     980           0 :                         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           0 :                         md_mirror->cb = restore_sync_cb;
     985           0 :                         md_mirror->owner.private = md;
     986             : 
     987             :                         /* First persist the mirror */
     988           0 :                         ftl_md_persist(md_mirror);
     989           0 :                         return -EAGAIN;
     990             :                 }
     991             :         }
     992             : 
     993           0 :         return md->io.status;
     994             : }
     995             : 
     996             : static void
     997           0 : io_done(struct ftl_md *md)
     998             : {
     999             :         int status;
    1000             : 
    1001           0 :         if (md->io.op == FTL_MD_OP_RESTORE) {
    1002           0 :                 status = restore_done(md);
    1003             :         } else {
    1004           0 :                 status = md->io.status;
    1005             :         }
    1006             : 
    1007           0 :         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           0 :                 io_cleanup(md);
    1011           0 :                 md->cb(md->dev, md, status);
    1012             :         }
    1013           0 : }
    1014             : 
    1015             : void
    1016           0 : ftl_md_restore(struct ftl_md *md)
    1017             : {
    1018           0 :         if (0 == io_init(md, FTL_MD_OP_RESTORE)) {
    1019           0 :                 io_submit(md);
    1020             :         } else {
    1021           0 :                 spdk_thread_send_msg(spdk_get_thread(), exception, md);
    1022             :         }
    1023           0 : }
    1024             : 
    1025             : static int
    1026           0 : pattern_prepare(struct ftl_md *md,
    1027             :                 int data_pattern, union ftl_md_vss *vss_pattern)
    1028             : {
    1029           0 :         void *data = md->io.data;
    1030           0 :         uint64_t data_size = xfer_size(md);
    1031             : 
    1032           0 :         memset(data, data_pattern, data_size);
    1033             : 
    1034           0 :         if (md->io.md) {
    1035           0 :                 if (vss_pattern) {
    1036             :                         /* store the VSS pattern... */
    1037           0 :                         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           0 :                         union ftl_md_vss vss = {0};
    1041             : 
    1042           0 :                         vss.version.md_version = md->region->current.version;
    1043           0 :                         ftl_md_vss_buf_init(md->io.md, ftl_md_xfer_blocks(md->dev), &vss);
    1044             :                 }
    1045             :         }
    1046             : 
    1047           0 :         return 0;
    1048             : }
    1049             : 
    1050             : static void
    1051           0 : clear_mirror_cb(struct spdk_ftl_dev *dev, struct ftl_md *secondary, int status)
    1052             : {
    1053           0 :         struct ftl_md *primary = secondary->owner.private;
    1054             : 
    1055           0 :         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           0 :                 io_submit(primary);
    1062             :         }
    1063           0 : }
    1064             : 
    1065             : void
    1066           0 : ftl_md_clear(struct ftl_md *md, int data_pattern, union ftl_md_vss *vss_pattern)
    1067             : {
    1068           0 :         if (has_mirror(md)) {
    1069           0 :                 struct ftl_md *md_mirror = ftl_md_get_mirror(md);
    1070             : 
    1071           0 :                 md->mirror_enabled = true;
    1072             : 
    1073             :                 /* Set callback and context in mirror */
    1074           0 :                 md_mirror->cb = clear_mirror_cb;
    1075           0 :                 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           0 :                 if (0 == io_init(md, FTL_MD_OP_CLEAR) && 0 == pattern_prepare(md, data_pattern, vss_pattern)) {
    1080             :                         /* First persist the mirror */
    1081           0 :                         ftl_md_clear(md_mirror, data_pattern, vss_pattern);
    1082             :                 } else {
    1083           0 :                         spdk_thread_send_msg(spdk_get_thread(), exception, md);
    1084             :                 }
    1085           0 :                 return;
    1086             :         }
    1087             : 
    1088           0 :         if (0 == io_init(md, FTL_MD_OP_CLEAR) && 0 == pattern_prepare(md, data_pattern, vss_pattern)) {
    1089           0 :                 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           0 : ftl_md_get_region(struct ftl_md *md)
    1097             : {
    1098           0 :         return md->region;
    1099             : }
    1100             : 
    1101             : void
    1102           0 : ftl_md_set_region(struct ftl_md *md,
    1103             :                   const struct ftl_layout_region *region)
    1104             : {
    1105           0 :         assert(region->current.blocks <= md->data_blocks);
    1106           0 :         md->region = region;
    1107             : 
    1108           0 :         if (md->vss_data) {
    1109           0 :                 union ftl_md_vss vss = {0};
    1110           0 :                 vss.version.md_version = region->current.version;
    1111           0 :                 ftl_md_vss_buf_init(md->vss_data, md->data_blocks, &vss);
    1112           0 :                 if (region->entry_size) {
    1113           0 :                         assert(md->entry_vss_dma_buf);
    1114           0 :                         ftl_md_vss_buf_init(md->entry_vss_dma_buf, region->entry_size, &vss);
    1115             :                 }
    1116             :         }
    1117             : 
    1118           0 :         if (has_mirror(md)) {
    1119           0 :                 md->mirror_enabled = true;
    1120             :         }
    1121           0 : }
    1122             : 
    1123             : int
    1124           0 : ftl_md_create_region_flags(struct spdk_ftl_dev *dev, int region_type)
    1125             : {
    1126           0 :         int flags = FTL_MD_CREATE_SHM;
    1127             : 
    1128           0 :         switch (region_type) {
    1129           0 :         case FTL_LAYOUT_REGION_TYPE_SB:
    1130           0 :                 if (dev->conf.mode & SPDK_FTL_MODE_CREATE) {
    1131           0 :                         flags |= FTL_MD_CREATE_SHM_NEW;
    1132             :                 }
    1133           0 :                 break;
    1134             : 
    1135           0 :         case FTL_LAYOUT_REGION_TYPE_BAND_MD:
    1136             :         case FTL_LAYOUT_REGION_TYPE_NVC_MD:
    1137           0 :                 if (!ftl_fast_startup(dev)) {
    1138           0 :                         flags |= FTL_MD_CREATE_SHM_NEW;
    1139             :                 }
    1140           0 :                 break;
    1141           0 :         case FTL_LAYOUT_REGION_TYPE_VALID_MAP:
    1142             :         case FTL_LAYOUT_REGION_TYPE_TRIM_MD:
    1143             :         case FTL_LAYOUT_REGION_TYPE_TRIM_LOG:
    1144           0 :                 if (!ftl_fast_startup(dev) && !ftl_fast_recovery(dev)) {
    1145           0 :                         flags |= FTL_MD_CREATE_SHM_NEW;
    1146             :                 }
    1147           0 :                 break;
    1148           0 :         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           0 :                 return FTL_MD_CREATE_SPDK_BUF;
    1153           0 :         default:
    1154           0 :                 return FTL_MD_CREATE_HEAP;
    1155             :         }
    1156             : 
    1157           0 :         return flags;
    1158             : }
    1159             : 
    1160             : int
    1161           0 : ftl_md_destroy_region_flags(struct spdk_ftl_dev *dev, int region_type)
    1162             : {
    1163           0 :         switch (region_type) {
    1164           0 :         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           0 :                 if (dev->conf.fast_shutdown) {
    1171           0 :                         return FTL_MD_DESTROY_SHM_KEEP;
    1172             :                 }
    1173           0 :                 break;
    1174           0 :         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           0 :                 return FTL_MD_DESTROY_SPDK_BUF;
    1179           0 :         default:
    1180           0 :                 break;
    1181             :         }
    1182           0 :         return 0;
    1183             : }
    1184             : 
    1185             : int
    1186           0 : ftl_md_create_shm_flags(struct spdk_ftl_dev *dev)
    1187             : {
    1188           0 :         int flags = FTL_MD_CREATE_SHM;
    1189             : 
    1190           0 :         if (!ftl_fast_startup(dev) && !ftl_fast_recovery(dev)) {
    1191           0 :                 flags |= FTL_MD_CREATE_SHM_NEW;
    1192             :         }
    1193           0 :         return flags;
    1194             : }
    1195             : 
    1196             : int
    1197           0 : ftl_md_destroy_shm_flags(struct spdk_ftl_dev *dev)
    1198             : {
    1199           0 :         return (dev->conf.fast_shutdown) ? FTL_MD_DESTROY_SHM_KEEP : 0;
    1200             : }

Generated by: LCOV version 1.15