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

Generated by: LCOV version 1.15