17a7ac2afSArtur Paszkiewicz /* SPDX-License-Identifier: BSD-3-Clause 217cf101bSMateusz Kozlowski * Copyright 2023 Solidigm All Rights Reserved 3a6dbe372Spaul luse * Copyright (C) 2022 Intel Corporation. 47a7ac2afSArtur Paszkiewicz * All rights reserved. 57a7ac2afSArtur Paszkiewicz */ 67a7ac2afSArtur Paszkiewicz 77a7ac2afSArtur Paszkiewicz #include "spdk/env.h" 87a7ac2afSArtur Paszkiewicz #include "spdk/bdev_module.h" 97a7ac2afSArtur Paszkiewicz 107a7ac2afSArtur Paszkiewicz #include "ftl_core.h" 117a7ac2afSArtur Paszkiewicz #include "ftl_md.h" 12d6795254SArtur Paszkiewicz #include "ftl_nv_cache_io.h" 137a7ac2afSArtur Paszkiewicz 147a7ac2afSArtur Paszkiewicz struct ftl_md; 157a7ac2afSArtur Paszkiewicz static void io_submit(struct ftl_md *md); 167a7ac2afSArtur Paszkiewicz static void io_done(struct ftl_md *md); 177a7ac2afSArtur Paszkiewicz 187a7ac2afSArtur Paszkiewicz static bool 197a7ac2afSArtur Paszkiewicz has_mirror(struct ftl_md *md) 207a7ac2afSArtur Paszkiewicz { 217a7ac2afSArtur Paszkiewicz if (md->region) { 227a7ac2afSArtur Paszkiewicz if (md->region->mirror_type != FTL_LAYOUT_REGION_TYPE_INVALID) { 237a7ac2afSArtur Paszkiewicz return md->mirror_enabled; 247a7ac2afSArtur Paszkiewicz } 257a7ac2afSArtur Paszkiewicz } 267a7ac2afSArtur Paszkiewicz 277a7ac2afSArtur Paszkiewicz return false; 287a7ac2afSArtur Paszkiewicz } 297a7ac2afSArtur Paszkiewicz 30522a0c82SLukasz Lasek static struct ftl_md * 31522a0c82SLukasz Lasek ftl_md_get_mirror(struct ftl_md *md) 327a7ac2afSArtur Paszkiewicz { 33522a0c82SLukasz Lasek if (has_mirror(md)) { 34522a0c82SLukasz Lasek return md->dev->layout.md[md->region->mirror_type]; 357a7ac2afSArtur Paszkiewicz } 367a7ac2afSArtur Paszkiewicz 37522a0c82SLukasz Lasek return NULL; 387a7ac2afSArtur Paszkiewicz } 397a7ac2afSArtur Paszkiewicz 407a7ac2afSArtur Paszkiewicz uint64_t 417a7ac2afSArtur Paszkiewicz ftl_md_xfer_blocks(struct spdk_ftl_dev *dev) 427a7ac2afSArtur Paszkiewicz { 437a7ac2afSArtur Paszkiewicz return 4ULL * dev->xfer_size; 447a7ac2afSArtur Paszkiewicz } 457a7ac2afSArtur Paszkiewicz 467a7ac2afSArtur Paszkiewicz static uint64_t 477a7ac2afSArtur Paszkiewicz xfer_size(struct ftl_md *md) 487a7ac2afSArtur Paszkiewicz { 497a7ac2afSArtur Paszkiewicz return ftl_md_xfer_blocks(md->dev) * FTL_BLOCK_SIZE; 507a7ac2afSArtur Paszkiewicz } 517a7ac2afSArtur Paszkiewicz 52818b9c05SArtur Paszkiewicz static void 53a0fb555bSMateusz Kozlowski ftl_md_create_spdk_buf(struct ftl_md *md, uint64_t vss_blksz) 54a0fb555bSMateusz Kozlowski { 55a0fb555bSMateusz Kozlowski md->shm_fd = -1; 56a0fb555bSMateusz Kozlowski md->vss_data = NULL; 57a0fb555bSMateusz Kozlowski md->data = spdk_zmalloc(md->data_blocks * (FTL_BLOCK_SIZE + vss_blksz), FTL_BLOCK_SIZE, NULL, 58*186b109dSJim Harris SPDK_ENV_NUMA_ID_ANY, SPDK_MALLOC_DMA); 59a0fb555bSMateusz Kozlowski 60a0fb555bSMateusz Kozlowski if (md->data && vss_blksz) { 61a0fb555bSMateusz Kozlowski md->vss_data = ((char *)md->data) + md->data_blocks * FTL_BLOCK_SIZE; 62a0fb555bSMateusz Kozlowski } 63a0fb555bSMateusz Kozlowski } 64a0fb555bSMateusz Kozlowski 65a0fb555bSMateusz Kozlowski static void 66818b9c05SArtur Paszkiewicz ftl_md_create_heap(struct ftl_md *md, uint64_t vss_blksz) 67818b9c05SArtur Paszkiewicz { 68818b9c05SArtur Paszkiewicz md->shm_fd = -1; 69818b9c05SArtur Paszkiewicz md->vss_data = NULL; 70818b9c05SArtur Paszkiewicz md->data = calloc(md->data_blocks, FTL_BLOCK_SIZE + vss_blksz); 71818b9c05SArtur Paszkiewicz 72818b9c05SArtur Paszkiewicz if (md->data && vss_blksz) { 73818b9c05SArtur Paszkiewicz md->vss_data = ((char *)md->data) + md->data_blocks * FTL_BLOCK_SIZE; 74818b9c05SArtur Paszkiewicz } 75818b9c05SArtur Paszkiewicz } 76818b9c05SArtur Paszkiewicz 77818b9c05SArtur Paszkiewicz static void 78a0fb555bSMateusz Kozlowski ftl_md_destroy_spdk_buf(struct ftl_md *md) 79a0fb555bSMateusz Kozlowski { 80a0fb555bSMateusz Kozlowski if (md->data) { 81a0fb555bSMateusz Kozlowski spdk_free(md->data); 82a0fb555bSMateusz Kozlowski md->data = NULL; 83a0fb555bSMateusz Kozlowski md->vss_data = NULL; 84a0fb555bSMateusz Kozlowski } 85a0fb555bSMateusz Kozlowski } 86a0fb555bSMateusz Kozlowski 87a0fb555bSMateusz Kozlowski static void 88818b9c05SArtur Paszkiewicz ftl_md_destroy_heap(struct ftl_md *md) 89818b9c05SArtur Paszkiewicz { 90818b9c05SArtur Paszkiewicz if (md->data) { 91818b9c05SArtur Paszkiewicz free(md->data); 92818b9c05SArtur Paszkiewicz md->data = NULL; 93818b9c05SArtur Paszkiewicz md->vss_data = NULL; 94818b9c05SArtur Paszkiewicz } 95818b9c05SArtur Paszkiewicz } 96818b9c05SArtur Paszkiewicz 97818b9c05SArtur Paszkiewicz static int 98818b9c05SArtur Paszkiewicz ftl_wrapper_open(const char *name, int of, mode_t m) 99818b9c05SArtur Paszkiewicz { 100818b9c05SArtur Paszkiewicz return open(name, of, m); 101818b9c05SArtur Paszkiewicz } 102818b9c05SArtur Paszkiewicz 103818b9c05SArtur Paszkiewicz static void 104818b9c05SArtur Paszkiewicz ftl_md_setup_obj(struct ftl_md *md, int flags, 105818b9c05SArtur Paszkiewicz const char *name) 106818b9c05SArtur Paszkiewicz { 107818b9c05SArtur Paszkiewicz char uuid_str[SPDK_UUID_STRING_LEN]; 108818b9c05SArtur Paszkiewicz const char *fmt; 109818b9c05SArtur Paszkiewicz 110818b9c05SArtur Paszkiewicz if (!(flags & FTL_MD_CREATE_SHM)) { 111818b9c05SArtur Paszkiewicz assert(false); 112818b9c05SArtur Paszkiewicz return; 113818b9c05SArtur Paszkiewicz } 114818b9c05SArtur Paszkiewicz 115818b9c05SArtur Paszkiewicz /* TODO: temporary, define a proper hugetlbfs mountpoint */ 116818b9c05SArtur Paszkiewicz fmt = "/dev/hugepages/ftl_%s_%s"; 117818b9c05SArtur Paszkiewicz md->shm_mmap_flags = MAP_SHARED; 118818b9c05SArtur Paszkiewicz md->shm_open = ftl_wrapper_open; 119818b9c05SArtur Paszkiewicz md->shm_unlink = unlink; 120818b9c05SArtur Paszkiewicz 121818b9c05SArtur Paszkiewicz if (name == NULL || 122818b9c05SArtur Paszkiewicz spdk_uuid_fmt_lower(uuid_str, SPDK_UUID_STRING_LEN, &md->dev->conf.uuid) || 123818b9c05SArtur Paszkiewicz snprintf(md->name, sizeof(md->name) / sizeof(md->name[0]), 124818b9c05SArtur Paszkiewicz fmt, uuid_str, name) <= 0) { 125818b9c05SArtur Paszkiewicz md->name[0] = 0; 126818b9c05SArtur Paszkiewicz } 127818b9c05SArtur Paszkiewicz } 128818b9c05SArtur Paszkiewicz 129818b9c05SArtur Paszkiewicz static void 130f45c0075SArtur Paszkiewicz ftl_md_invalidate_shm(struct ftl_md *md) 131f45c0075SArtur Paszkiewicz { 132f45c0075SArtur Paszkiewicz if (md->dev->sb_shm && md->dev->sb_shm->shm_ready) { 133f45c0075SArtur Paszkiewicz md->dev->init_retry = true; 134f45c0075SArtur Paszkiewicz md->dev->sb_shm->shm_ready = false; 135f45c0075SArtur Paszkiewicz } 136f45c0075SArtur Paszkiewicz } 137f45c0075SArtur Paszkiewicz 138f45c0075SArtur Paszkiewicz static void 139818b9c05SArtur Paszkiewicz ftl_md_create_shm(struct ftl_md *md, uint64_t vss_blksz, int flags) 140818b9c05SArtur Paszkiewicz { 141818b9c05SArtur Paszkiewicz struct stat shm_stat; 142818b9c05SArtur Paszkiewicz size_t vss_blk_offs; 143818b9c05SArtur Paszkiewicz void *shm_ptr; 144818b9c05SArtur Paszkiewicz int open_flags = O_RDWR; 145818b9c05SArtur Paszkiewicz mode_t open_mode = S_IRUSR | S_IWUSR; 146818b9c05SArtur Paszkiewicz 147818b9c05SArtur Paszkiewicz assert(md->shm_open && md->shm_unlink); 148818b9c05SArtur Paszkiewicz md->data = NULL; 149818b9c05SArtur Paszkiewicz md->vss_data = NULL; 150818b9c05SArtur Paszkiewicz md->shm_sz = 0; 151818b9c05SArtur Paszkiewicz 152818b9c05SArtur Paszkiewicz /* Must have an object name */ 153818b9c05SArtur Paszkiewicz if (md->name[0] == 0) { 154818b9c05SArtur Paszkiewicz assert(false); 155818b9c05SArtur Paszkiewicz return; 156818b9c05SArtur Paszkiewicz } 157818b9c05SArtur Paszkiewicz 158818b9c05SArtur Paszkiewicz /* If specified, unlink before create a new SHM object */ 159818b9c05SArtur Paszkiewicz if (flags & FTL_MD_CREATE_SHM_NEW) { 160818b9c05SArtur Paszkiewicz if (md->shm_unlink(md->name) < 0 && errno != ENOENT) { 161f45c0075SArtur Paszkiewicz ftl_md_invalidate_shm(md); 162818b9c05SArtur Paszkiewicz return; 163818b9c05SArtur Paszkiewicz } 164818b9c05SArtur Paszkiewicz open_flags += O_CREAT | O_TRUNC; 165818b9c05SArtur Paszkiewicz } 166818b9c05SArtur Paszkiewicz 167818b9c05SArtur Paszkiewicz /* Open existing or create a new SHM object, then query its props */ 168818b9c05SArtur Paszkiewicz md->shm_fd = md->shm_open(md->name, open_flags, open_mode); 169818b9c05SArtur Paszkiewicz if (md->shm_fd < 0 || fstat(md->shm_fd, &shm_stat) < 0) { 170818b9c05SArtur Paszkiewicz goto err_shm; 171818b9c05SArtur Paszkiewicz } 172818b9c05SArtur Paszkiewicz 173818b9c05SArtur Paszkiewicz /* Verify open mode hasn't changed */ 174818b9c05SArtur Paszkiewicz if ((shm_stat.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO)) != open_mode) { 175818b9c05SArtur Paszkiewicz goto err_shm; 176818b9c05SArtur Paszkiewicz } 177818b9c05SArtur Paszkiewicz 178818b9c05SArtur Paszkiewicz /* Round up the SHM obj size to the nearest blk size (i.e. page size) */ 179818b9c05SArtur Paszkiewicz md->shm_sz = spdk_divide_round_up(md->data_blocks * FTL_BLOCK_SIZE, shm_stat.st_blksize); 180818b9c05SArtur Paszkiewicz 181818b9c05SArtur Paszkiewicz /* Add some blks for VSS metadata */ 182818b9c05SArtur Paszkiewicz vss_blk_offs = md->shm_sz; 183818b9c05SArtur Paszkiewicz 184818b9c05SArtur Paszkiewicz if (vss_blksz) { 185818b9c05SArtur Paszkiewicz md->shm_sz += spdk_divide_round_up(md->data_blocks * vss_blksz, 186818b9c05SArtur Paszkiewicz shm_stat.st_blksize); 187818b9c05SArtur Paszkiewicz } 188818b9c05SArtur Paszkiewicz 189818b9c05SArtur Paszkiewicz /* Total SHM obj size */ 190818b9c05SArtur Paszkiewicz md->shm_sz *= shm_stat.st_blksize; 191818b9c05SArtur Paszkiewicz 192818b9c05SArtur Paszkiewicz /* Set or check the object size - zero init`d in case of set (FTL_MD_CREATE_SHM_NEW) */ 193818b9c05SArtur Paszkiewicz if ((shm_stat.st_size == 0 && (ftruncate(md->shm_fd, md->shm_sz) < 0 || 194818b9c05SArtur Paszkiewicz (flags & FTL_MD_CREATE_SHM_NEW) == 0)) 195818b9c05SArtur Paszkiewicz || (shm_stat.st_size > 0 && (size_t)shm_stat.st_size != md->shm_sz)) { 196818b9c05SArtur Paszkiewicz goto err_shm; 197818b9c05SArtur Paszkiewicz } 198818b9c05SArtur Paszkiewicz 199818b9c05SArtur Paszkiewicz /* Create a virtual memory mapping for the object */ 200818b9c05SArtur Paszkiewicz shm_ptr = mmap(NULL, md->shm_sz, PROT_READ | PROT_WRITE, md->shm_mmap_flags, 201818b9c05SArtur Paszkiewicz md->shm_fd, 0); 202818b9c05SArtur Paszkiewicz if (shm_ptr == MAP_FAILED) { 203818b9c05SArtur Paszkiewicz goto err_shm; 204818b9c05SArtur Paszkiewicz } 205818b9c05SArtur Paszkiewicz 206818b9c05SArtur Paszkiewicz md->data = shm_ptr; 207818b9c05SArtur Paszkiewicz if (vss_blksz) { 208818b9c05SArtur Paszkiewicz md->vss_data = ((char *)shm_ptr) + vss_blk_offs * shm_stat.st_blksize; 209818b9c05SArtur Paszkiewicz } 210818b9c05SArtur Paszkiewicz 211818b9c05SArtur Paszkiewicz /* Lock the pages in memory (i.e. prevent the pages to be paged out) */ 212818b9c05SArtur Paszkiewicz if (mlock(md->data, md->shm_sz) < 0) { 213818b9c05SArtur Paszkiewicz goto err_map; 214818b9c05SArtur Paszkiewicz } 215818b9c05SArtur Paszkiewicz 216818b9c05SArtur Paszkiewicz if (spdk_mem_register(md->data, md->shm_sz)) { 217818b9c05SArtur Paszkiewicz goto err_mlock; 218818b9c05SArtur Paszkiewicz } 219818b9c05SArtur Paszkiewicz md->mem_reg = true; 220818b9c05SArtur Paszkiewicz 221818b9c05SArtur Paszkiewicz return; 222818b9c05SArtur Paszkiewicz 223818b9c05SArtur Paszkiewicz /* Cleanup upon fault */ 224818b9c05SArtur Paszkiewicz err_mlock: 225818b9c05SArtur Paszkiewicz munlock(md->data, md->shm_sz); 226818b9c05SArtur Paszkiewicz 227818b9c05SArtur Paszkiewicz err_map: 228818b9c05SArtur Paszkiewicz munmap(md->data, md->shm_sz); 229818b9c05SArtur Paszkiewicz md->data = NULL; 230818b9c05SArtur Paszkiewicz md->vss_data = NULL; 231818b9c05SArtur Paszkiewicz md->shm_sz = 0; 232818b9c05SArtur Paszkiewicz 233818b9c05SArtur Paszkiewicz err_shm: 234818b9c05SArtur Paszkiewicz if (md->shm_fd >= 0) { 235818b9c05SArtur Paszkiewicz close(md->shm_fd); 236818b9c05SArtur Paszkiewicz md->shm_unlink(md->name); 237818b9c05SArtur Paszkiewicz md->shm_fd = -1; 238818b9c05SArtur Paszkiewicz } 239f45c0075SArtur Paszkiewicz ftl_md_invalidate_shm(md); 240818b9c05SArtur Paszkiewicz } 241818b9c05SArtur Paszkiewicz 242818b9c05SArtur Paszkiewicz static void 2430e33da49SKozlowski Mateusz ftl_md_destroy_shm(struct ftl_md *md, int flags) 244818b9c05SArtur Paszkiewicz { 245818b9c05SArtur Paszkiewicz if (!md->data) { 246818b9c05SArtur Paszkiewicz return; 247818b9c05SArtur Paszkiewicz } 248818b9c05SArtur Paszkiewicz 249818b9c05SArtur Paszkiewicz assert(md->shm_sz > 0); 250818b9c05SArtur Paszkiewicz if (md->mem_reg) { 251818b9c05SArtur Paszkiewicz spdk_mem_unregister(md->data, md->shm_sz); 252818b9c05SArtur Paszkiewicz md->mem_reg = false; 253818b9c05SArtur Paszkiewicz } 254818b9c05SArtur Paszkiewicz 255818b9c05SArtur Paszkiewicz /* Unlock the pages in memory */ 256818b9c05SArtur Paszkiewicz munlock(md->data, md->shm_sz); 257818b9c05SArtur Paszkiewicz 258818b9c05SArtur Paszkiewicz /* Remove the virtual memory mapping for the object */ 259818b9c05SArtur Paszkiewicz munmap(md->data, md->shm_sz); 260818b9c05SArtur Paszkiewicz 261818b9c05SArtur Paszkiewicz /* Close SHM object fd */ 262818b9c05SArtur Paszkiewicz close(md->shm_fd); 263818b9c05SArtur Paszkiewicz 264818b9c05SArtur Paszkiewicz md->data = NULL; 265818b9c05SArtur Paszkiewicz md->vss_data = NULL; 266818b9c05SArtur Paszkiewicz 2670e33da49SKozlowski Mateusz /* If specified, keep the object in SHM */ 2680e33da49SKozlowski Mateusz if (flags & FTL_MD_DESTROY_SHM_KEEP) { 2690e33da49SKozlowski Mateusz return; 2700e33da49SKozlowski Mateusz } 2710e33da49SKozlowski Mateusz 272818b9c05SArtur Paszkiewicz /* Otherwise destroy/unlink the object */ 273818b9c05SArtur Paszkiewicz assert(md->name[0] != 0 && md->shm_unlink != NULL); 274818b9c05SArtur Paszkiewicz md->shm_unlink(md->name); 275818b9c05SArtur Paszkiewicz } 276818b9c05SArtur Paszkiewicz 2777a7ac2afSArtur Paszkiewicz struct ftl_md *ftl_md_create(struct spdk_ftl_dev *dev, uint64_t blocks, 278818b9c05SArtur Paszkiewicz uint64_t vss_blksz, const char *name, int flags, 2797a7ac2afSArtur Paszkiewicz const struct ftl_layout_region *region) 2807a7ac2afSArtur Paszkiewicz { 2817a7ac2afSArtur Paszkiewicz struct ftl_md *md; 2827a7ac2afSArtur Paszkiewicz 2837a7ac2afSArtur Paszkiewicz md = calloc(1, sizeof(*md)); 2847a7ac2afSArtur Paszkiewicz if (!md) { 2857a7ac2afSArtur Paszkiewicz return NULL; 2867a7ac2afSArtur Paszkiewicz } 2877a7ac2afSArtur Paszkiewicz md->dev = dev; 2887a7ac2afSArtur Paszkiewicz md->data_blocks = blocks; 2897a7ac2afSArtur Paszkiewicz md->mirror_enabled = true; 2907a7ac2afSArtur Paszkiewicz 291818b9c05SArtur Paszkiewicz if (flags != FTL_MD_CREATE_NO_MEM) { 292818b9c05SArtur Paszkiewicz if (flags & FTL_MD_CREATE_SHM) { 293818b9c05SArtur Paszkiewicz ftl_md_setup_obj(md, flags, name); 294818b9c05SArtur Paszkiewicz ftl_md_create_shm(md, vss_blksz, flags); 295a0fb555bSMateusz Kozlowski } else if (flags & FTL_MD_CREATE_SPDK_BUF) { 296a0fb555bSMateusz Kozlowski ftl_md_create_spdk_buf(md, vss_blksz); 297818b9c05SArtur Paszkiewicz } else { 298818b9c05SArtur Paszkiewicz assert((flags & FTL_MD_CREATE_HEAP) == FTL_MD_CREATE_HEAP); 299818b9c05SArtur Paszkiewicz ftl_md_create_heap(md, vss_blksz); 300818b9c05SArtur Paszkiewicz } 3017a7ac2afSArtur Paszkiewicz 302818b9c05SArtur Paszkiewicz if (!md->data) { 3037a7ac2afSArtur Paszkiewicz free(md); 3047a7ac2afSArtur Paszkiewicz return NULL; 3057a7ac2afSArtur Paszkiewicz } 3067a7ac2afSArtur Paszkiewicz } 3077a7ac2afSArtur Paszkiewicz 3087a7ac2afSArtur Paszkiewicz if (region) { 3097a7ac2afSArtur Paszkiewicz size_t entry_vss_buf_size = vss_blksz * region->entry_size; 3107a7ac2afSArtur Paszkiewicz 3117a7ac2afSArtur Paszkiewicz if (entry_vss_buf_size) { 3127a7ac2afSArtur Paszkiewicz md->entry_vss_dma_buf = spdk_malloc(entry_vss_buf_size, FTL_BLOCK_SIZE, 3137a7ac2afSArtur Paszkiewicz NULL, SPDK_ENV_LCORE_ID_ANY, 3147a7ac2afSArtur Paszkiewicz SPDK_MALLOC_DMA); 3157a7ac2afSArtur Paszkiewicz if (!md->entry_vss_dma_buf) { 3167a7ac2afSArtur Paszkiewicz goto err; 3177a7ac2afSArtur Paszkiewicz } 3187a7ac2afSArtur Paszkiewicz } 3197a7ac2afSArtur Paszkiewicz 320522a0c82SLukasz Lasek ftl_md_set_region(md, region); 3217a7ac2afSArtur Paszkiewicz } 3227a7ac2afSArtur Paszkiewicz 3237a7ac2afSArtur Paszkiewicz return md; 3247a7ac2afSArtur Paszkiewicz err: 3250e33da49SKozlowski Mateusz ftl_md_destroy(md, ftl_md_destroy_region_flags(dev, region->type)); 3267a7ac2afSArtur Paszkiewicz return NULL; 3277a7ac2afSArtur Paszkiewicz } 3287a7ac2afSArtur Paszkiewicz 329818b9c05SArtur Paszkiewicz int 330818b9c05SArtur Paszkiewicz ftl_md_unlink(struct spdk_ftl_dev *dev, const char *name, int flags) 331818b9c05SArtur Paszkiewicz { 332818b9c05SArtur Paszkiewicz struct ftl_md md = { 0 }; 333818b9c05SArtur Paszkiewicz 334818b9c05SArtur Paszkiewicz if (0 == (flags & FTL_MD_CREATE_SHM)) { 335818b9c05SArtur Paszkiewicz /* Unlink can be called for shared memory only */ 336818b9c05SArtur Paszkiewicz return -EINVAL; 337818b9c05SArtur Paszkiewicz } 338818b9c05SArtur Paszkiewicz 339818b9c05SArtur Paszkiewicz md.dev = dev; 340818b9c05SArtur Paszkiewicz ftl_md_setup_obj(&md, flags, name); 341818b9c05SArtur Paszkiewicz 342818b9c05SArtur Paszkiewicz return md.shm_unlink(md.name); 343818b9c05SArtur Paszkiewicz } 344818b9c05SArtur Paszkiewicz 3457a7ac2afSArtur Paszkiewicz void 3460e33da49SKozlowski Mateusz ftl_md_destroy(struct ftl_md *md, int flags) 3477a7ac2afSArtur Paszkiewicz { 3487a7ac2afSArtur Paszkiewicz if (!md) { 3497a7ac2afSArtur Paszkiewicz return; 3507a7ac2afSArtur Paszkiewicz } 3517a7ac2afSArtur Paszkiewicz 352522a0c82SLukasz Lasek if (!md->is_mirror) { 3530e33da49SKozlowski Mateusz ftl_md_free_buf(md, flags); 3547a7ac2afSArtur Paszkiewicz spdk_free(md->entry_vss_dma_buf); 355522a0c82SLukasz Lasek } 3567a7ac2afSArtur Paszkiewicz free(md); 3577a7ac2afSArtur Paszkiewicz } 3587a7ac2afSArtur Paszkiewicz 3597a7ac2afSArtur Paszkiewicz void 3600e33da49SKozlowski Mateusz ftl_md_free_buf(struct ftl_md *md, int flags) 3617a7ac2afSArtur Paszkiewicz { 3627a7ac2afSArtur Paszkiewicz if (!md) { 3637a7ac2afSArtur Paszkiewicz return; 3647a7ac2afSArtur Paszkiewicz } 3657a7ac2afSArtur Paszkiewicz 366818b9c05SArtur Paszkiewicz if (md->shm_fd < 0) { 367a0fb555bSMateusz Kozlowski if (flags & FTL_MD_DESTROY_SPDK_BUF) { 368a0fb555bSMateusz Kozlowski ftl_md_destroy_spdk_buf(md); 369a0fb555bSMateusz Kozlowski } else { 3700e33da49SKozlowski Mateusz assert(flags == 0); 371818b9c05SArtur Paszkiewicz ftl_md_destroy_heap(md); 372a0fb555bSMateusz Kozlowski } 373818b9c05SArtur Paszkiewicz } else { 3740e33da49SKozlowski Mateusz ftl_md_destroy_shm(md, flags); 3757a7ac2afSArtur Paszkiewicz } 3767a7ac2afSArtur Paszkiewicz } 3777a7ac2afSArtur Paszkiewicz 3787a7ac2afSArtur Paszkiewicz void * 3797a7ac2afSArtur Paszkiewicz ftl_md_get_buffer(struct ftl_md *md) 3807a7ac2afSArtur Paszkiewicz { 3817a7ac2afSArtur Paszkiewicz return md->data; 3827a7ac2afSArtur Paszkiewicz } 3837a7ac2afSArtur Paszkiewicz 3847a7ac2afSArtur Paszkiewicz uint64_t 3857a7ac2afSArtur Paszkiewicz ftl_md_get_buffer_size(struct ftl_md *md) 3867a7ac2afSArtur Paszkiewicz { 3877a7ac2afSArtur Paszkiewicz return md->data_blocks * FTL_BLOCK_SIZE; 3887a7ac2afSArtur Paszkiewicz } 3897a7ac2afSArtur Paszkiewicz 3907a7ac2afSArtur Paszkiewicz static void 3917a7ac2afSArtur Paszkiewicz ftl_md_vss_buf_init(union ftl_md_vss *buf, uint32_t count, 3927a7ac2afSArtur Paszkiewicz const union ftl_md_vss *vss_pattern) 3937a7ac2afSArtur Paszkiewicz { 3947a7ac2afSArtur Paszkiewicz while (count) { 3957a7ac2afSArtur Paszkiewicz count--; 3967a7ac2afSArtur Paszkiewicz buf[count] = *vss_pattern; 3977a7ac2afSArtur Paszkiewicz } 3987a7ac2afSArtur Paszkiewicz } 3997a7ac2afSArtur Paszkiewicz 4007a7ac2afSArtur Paszkiewicz union ftl_md_vss *ftl_md_vss_buf_alloc(struct ftl_layout_region *region, uint32_t count) 4017a7ac2afSArtur Paszkiewicz { 4027a7ac2afSArtur Paszkiewicz union ftl_md_vss *buf = spdk_zmalloc(count * FTL_MD_VSS_SZ, FTL_BLOCK_SIZE, NULL, 4037a7ac2afSArtur Paszkiewicz SPDK_ENV_LCORE_ID_ANY, 4047a7ac2afSArtur Paszkiewicz SPDK_MALLOC_DMA); 4057a7ac2afSArtur Paszkiewicz 4067a7ac2afSArtur Paszkiewicz if (!buf) { 4077a7ac2afSArtur Paszkiewicz return NULL; 4087a7ac2afSArtur Paszkiewicz } 4097a7ac2afSArtur Paszkiewicz 4107a7ac2afSArtur Paszkiewicz union ftl_md_vss vss_buf = {0}; 4117a7ac2afSArtur Paszkiewicz vss_buf.version.md_version = region->current.version; 4127a7ac2afSArtur Paszkiewicz ftl_md_vss_buf_init(buf, count, &vss_buf); 4137a7ac2afSArtur Paszkiewicz return buf; 4147a7ac2afSArtur Paszkiewicz } 4157a7ac2afSArtur Paszkiewicz 4167a7ac2afSArtur Paszkiewicz union ftl_md_vss *ftl_md_get_vss_buffer(struct ftl_md *md) 4177a7ac2afSArtur Paszkiewicz { 4187a7ac2afSArtur Paszkiewicz return md->vss_data; 4197a7ac2afSArtur Paszkiewicz } 4207a7ac2afSArtur Paszkiewicz 4217a7ac2afSArtur Paszkiewicz static void 4227a7ac2afSArtur Paszkiewicz io_cleanup(struct ftl_md *md) 4237a7ac2afSArtur Paszkiewicz { 4247a7ac2afSArtur Paszkiewicz spdk_dma_free(md->io.data); 4257a7ac2afSArtur Paszkiewicz md->io.data = NULL; 4267a7ac2afSArtur Paszkiewicz 4277a7ac2afSArtur Paszkiewicz spdk_dma_free(md->io.md); 4287a7ac2afSArtur Paszkiewicz md->io.md = NULL; 4297a7ac2afSArtur Paszkiewicz } 4307a7ac2afSArtur Paszkiewicz 4317a7ac2afSArtur Paszkiewicz static void 4327a7ac2afSArtur Paszkiewicz exception(void *arg) 4337a7ac2afSArtur Paszkiewicz { 4347a7ac2afSArtur Paszkiewicz struct ftl_md *md = arg; 4357a7ac2afSArtur Paszkiewicz 4367a7ac2afSArtur Paszkiewicz md->cb(md->dev, md, -EINVAL); 4377a7ac2afSArtur Paszkiewicz io_cleanup(md); 4387a7ac2afSArtur Paszkiewicz } 4397a7ac2afSArtur Paszkiewicz 4401790ee8aSArtur Paszkiewicz static inline enum ftl_stats_type 4411790ee8aSArtur Paszkiewicz get_bdev_io_ftl_stats_type(struct spdk_ftl_dev *dev, struct spdk_bdev_io *bdev_io) { 4421790ee8aSArtur Paszkiewicz struct spdk_bdev *nvc = spdk_bdev_desc_get_bdev(dev->nv_cache.bdev_desc); 4431790ee8aSArtur Paszkiewicz 4441790ee8aSArtur Paszkiewicz if (bdev_io->bdev == nvc) 4451790ee8aSArtur Paszkiewicz { 4461790ee8aSArtur Paszkiewicz return FTL_STATS_TYPE_MD_NV_CACHE; 4471790ee8aSArtur Paszkiewicz } else 4481790ee8aSArtur Paszkiewicz { 4491790ee8aSArtur Paszkiewicz return FTL_STATS_TYPE_MD_BASE; 4501790ee8aSArtur Paszkiewicz } 4511790ee8aSArtur Paszkiewicz } 4521790ee8aSArtur Paszkiewicz 4537a7ac2afSArtur Paszkiewicz static void 4547a7ac2afSArtur Paszkiewicz read_write_blocks_cb(struct spdk_bdev_io *bdev_io, bool success, void *arg) 4557a7ac2afSArtur Paszkiewicz { 4567a7ac2afSArtur Paszkiewicz struct ftl_md *md = arg; 4577a7ac2afSArtur Paszkiewicz 4581790ee8aSArtur Paszkiewicz ftl_stats_bdev_io_completed(md->dev, get_bdev_io_ftl_stats_type(md->dev, bdev_io), bdev_io); 4591790ee8aSArtur Paszkiewicz 4607a7ac2afSArtur Paszkiewicz if (spdk_unlikely(!success)) { 4617a7ac2afSArtur Paszkiewicz if (md->io.op == FTL_MD_OP_RESTORE && has_mirror(md)) { 4627a7ac2afSArtur Paszkiewicz md->io.status = -EAGAIN; 4637a7ac2afSArtur Paszkiewicz } else { 4647a7ac2afSArtur Paszkiewicz md->io.status = -EIO; 4657a7ac2afSArtur Paszkiewicz } 4667a7ac2afSArtur Paszkiewicz } else { 4677a7ac2afSArtur Paszkiewicz uint64_t blocks = bdev_io->u.bdev.num_blocks; 4687a7ac2afSArtur Paszkiewicz uint64_t size = blocks * FTL_BLOCK_SIZE; 4697a7ac2afSArtur Paszkiewicz 4707a7ac2afSArtur Paszkiewicz if (md->io.op == FTL_MD_OP_RESTORE) { 4717a7ac2afSArtur Paszkiewicz memcpy(md->data + md->io.data_offset, md->io.data, size); 4727a7ac2afSArtur Paszkiewicz 4737a7ac2afSArtur Paszkiewicz if (md->vss_data) { 4747a7ac2afSArtur Paszkiewicz uint64_t vss_offset = md->io.data_offset / FTL_BLOCK_SIZE; 4757a7ac2afSArtur Paszkiewicz vss_offset *= FTL_MD_VSS_SZ; 4767a7ac2afSArtur Paszkiewicz memcpy(md->vss_data + vss_offset, md->io.md, blocks * FTL_MD_VSS_SZ); 4777a7ac2afSArtur Paszkiewicz } 4787a7ac2afSArtur Paszkiewicz } 4797a7ac2afSArtur Paszkiewicz 4807a7ac2afSArtur Paszkiewicz md->io.address += blocks; 4817a7ac2afSArtur Paszkiewicz md->io.remaining -= blocks; 4827a7ac2afSArtur Paszkiewicz md->io.data_offset += size; 4837a7ac2afSArtur Paszkiewicz } 4847a7ac2afSArtur Paszkiewicz 4857a7ac2afSArtur Paszkiewicz spdk_bdev_free_io(bdev_io); 4867a7ac2afSArtur Paszkiewicz 4877a7ac2afSArtur Paszkiewicz io_submit(md); 4887a7ac2afSArtur Paszkiewicz } 4897a7ac2afSArtur Paszkiewicz 4907a7ac2afSArtur Paszkiewicz static inline int 4917a7ac2afSArtur Paszkiewicz read_blocks(struct spdk_ftl_dev *dev, struct spdk_bdev_desc *desc, 4927a7ac2afSArtur Paszkiewicz struct spdk_io_channel *ch, 4937a7ac2afSArtur Paszkiewicz void *buf, void *md_buf, 4947a7ac2afSArtur Paszkiewicz uint64_t offset_blocks, uint64_t num_blocks, 4957a7ac2afSArtur Paszkiewicz spdk_bdev_io_completion_cb cb, void *cb_arg) 4967a7ac2afSArtur Paszkiewicz { 497a68a12a4SKozlowski Mateusz if (desc == dev->nv_cache.bdev_desc) { 498d6795254SArtur Paszkiewicz return ftl_nv_cache_bdev_read_blocks_with_md(dev, desc, ch, buf, md_buf, 499d6795254SArtur Paszkiewicz offset_blocks, num_blocks, 500d6795254SArtur Paszkiewicz cb, cb_arg); 501d6795254SArtur Paszkiewicz } else if (md_buf) { 5027a7ac2afSArtur Paszkiewicz return spdk_bdev_read_blocks_with_md(desc, ch, buf, md_buf, 5037a7ac2afSArtur Paszkiewicz offset_blocks, num_blocks, 5047a7ac2afSArtur Paszkiewicz cb, cb_arg); 5057a7ac2afSArtur Paszkiewicz } else { 5067a7ac2afSArtur Paszkiewicz return spdk_bdev_read_blocks(desc, ch, buf, 5077a7ac2afSArtur Paszkiewicz offset_blocks, num_blocks, 5087a7ac2afSArtur Paszkiewicz cb, cb_arg); 5097a7ac2afSArtur Paszkiewicz } 5107a7ac2afSArtur Paszkiewicz } 5117a7ac2afSArtur Paszkiewicz 5127a7ac2afSArtur Paszkiewicz static inline int 5137a7ac2afSArtur Paszkiewicz write_blocks(struct spdk_ftl_dev *dev, struct spdk_bdev_desc *desc, 5147a7ac2afSArtur Paszkiewicz struct spdk_io_channel *ch, 5157a7ac2afSArtur Paszkiewicz void *buf, void *md_buf, 5167a7ac2afSArtur Paszkiewicz uint64_t offset_blocks, uint64_t num_blocks, 5177a7ac2afSArtur Paszkiewicz spdk_bdev_io_completion_cb cb, void *cb_arg) 5187a7ac2afSArtur Paszkiewicz { 519a68a12a4SKozlowski Mateusz if (desc == dev->nv_cache.bdev_desc) { 520d6795254SArtur Paszkiewicz return ftl_nv_cache_bdev_write_blocks_with_md(dev, desc, ch, buf, md_buf, 521d6795254SArtur Paszkiewicz offset_blocks, num_blocks, 522d6795254SArtur Paszkiewicz cb, cb_arg); 523d6795254SArtur Paszkiewicz } else if (md_buf) { 5247a7ac2afSArtur Paszkiewicz return spdk_bdev_write_blocks_with_md(desc, ch, buf, md_buf, offset_blocks, 5257a7ac2afSArtur Paszkiewicz num_blocks, cb, cb_arg); 5267a7ac2afSArtur Paszkiewicz } else { 5277a7ac2afSArtur Paszkiewicz return spdk_bdev_write_blocks(desc, ch, buf, offset_blocks, num_blocks, cb, cb_arg); 5287a7ac2afSArtur Paszkiewicz } 5297a7ac2afSArtur Paszkiewicz } 5307a7ac2afSArtur Paszkiewicz 5317a7ac2afSArtur Paszkiewicz static void 5327a7ac2afSArtur Paszkiewicz read_write_blocks(void *_md) 5337a7ac2afSArtur Paszkiewicz { 5347a7ac2afSArtur Paszkiewicz struct ftl_md *md = _md; 5357a7ac2afSArtur Paszkiewicz const struct ftl_layout_region *region = md->region; 5367a7ac2afSArtur Paszkiewicz uint64_t blocks; 5377a7ac2afSArtur Paszkiewicz int rc = 0; 5387a7ac2afSArtur Paszkiewicz 5397a7ac2afSArtur Paszkiewicz blocks = spdk_min(md->io.remaining, ftl_md_xfer_blocks(md->dev)); 5407a7ac2afSArtur Paszkiewicz 5417a7ac2afSArtur Paszkiewicz switch (md->io.op) { 5427a7ac2afSArtur Paszkiewicz case FTL_MD_OP_RESTORE: 5437a7ac2afSArtur Paszkiewicz rc = read_blocks(md->dev, region->bdev_desc, region->ioch, 5447a7ac2afSArtur Paszkiewicz md->io.data, md->io.md, 5457a7ac2afSArtur Paszkiewicz md->io.address, blocks, 5467a7ac2afSArtur Paszkiewicz read_write_blocks_cb, md); 5477a7ac2afSArtur Paszkiewicz break; 5487a7ac2afSArtur Paszkiewicz case FTL_MD_OP_PERSIST: 5497a7ac2afSArtur Paszkiewicz case FTL_MD_OP_CLEAR: 5507a7ac2afSArtur Paszkiewicz rc = write_blocks(md->dev, region->bdev_desc, region->ioch, 5517a7ac2afSArtur Paszkiewicz md->io.data, md->io.md, 5527a7ac2afSArtur Paszkiewicz md->io.address, blocks, 5537a7ac2afSArtur Paszkiewicz read_write_blocks_cb, md); 5547a7ac2afSArtur Paszkiewicz break; 5557a7ac2afSArtur Paszkiewicz default: 5567a7ac2afSArtur Paszkiewicz ftl_abort(); 5577a7ac2afSArtur Paszkiewicz } 5587a7ac2afSArtur Paszkiewicz 5597a7ac2afSArtur Paszkiewicz if (spdk_unlikely(rc)) { 5607a7ac2afSArtur Paszkiewicz if (rc == -ENOMEM) { 5617a7ac2afSArtur Paszkiewicz struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(region->bdev_desc); 5627a7ac2afSArtur Paszkiewicz md->io.bdev_io_wait.bdev = bdev; 5637a7ac2afSArtur Paszkiewicz md->io.bdev_io_wait.cb_fn = read_write_blocks; 5647a7ac2afSArtur Paszkiewicz md->io.bdev_io_wait.cb_arg = md; 5657a7ac2afSArtur Paszkiewicz spdk_bdev_queue_io_wait(bdev, region->ioch, &md->io.bdev_io_wait); 5667a7ac2afSArtur Paszkiewicz } else { 5677a7ac2afSArtur Paszkiewicz ftl_abort(); 5687a7ac2afSArtur Paszkiewicz } 5697a7ac2afSArtur Paszkiewicz } 5707a7ac2afSArtur Paszkiewicz } 5717a7ac2afSArtur Paszkiewicz 5727a7ac2afSArtur Paszkiewicz static void 5737a7ac2afSArtur Paszkiewicz io_submit(struct ftl_md *md) 5747a7ac2afSArtur Paszkiewicz { 5757a7ac2afSArtur Paszkiewicz if (!md->io.remaining || md->io.status) { 5767a7ac2afSArtur Paszkiewicz io_done(md); 5777a7ac2afSArtur Paszkiewicz return; 5787a7ac2afSArtur Paszkiewicz } 5797a7ac2afSArtur Paszkiewicz 5807a7ac2afSArtur Paszkiewicz if (md->io.op == FTL_MD_OP_PERSIST) { 5817a7ac2afSArtur Paszkiewicz uint64_t blocks = spdk_min(md->io.remaining, ftl_md_xfer_blocks(md->dev)); 5827a7ac2afSArtur Paszkiewicz 5837a7ac2afSArtur Paszkiewicz memcpy(md->io.data, md->data + md->io.data_offset, FTL_BLOCK_SIZE * blocks); 5847a7ac2afSArtur Paszkiewicz 5857a7ac2afSArtur Paszkiewicz if (md->vss_data) { 5867a7ac2afSArtur Paszkiewicz uint64_t vss_offset = md->io.data_offset / FTL_BLOCK_SIZE; 5877a7ac2afSArtur Paszkiewicz vss_offset *= FTL_MD_VSS_SZ; 5887a7ac2afSArtur Paszkiewicz assert(md->io.md); 5897a7ac2afSArtur Paszkiewicz memcpy(md->io.md, md->vss_data + vss_offset, FTL_MD_VSS_SZ * blocks); 5907a7ac2afSArtur Paszkiewicz } 5917a7ac2afSArtur Paszkiewicz } 5927a7ac2afSArtur Paszkiewicz 5937a7ac2afSArtur Paszkiewicz read_write_blocks(md); 5947a7ac2afSArtur Paszkiewicz } 5957a7ac2afSArtur Paszkiewicz 5967a7ac2afSArtur Paszkiewicz static int 5977a7ac2afSArtur Paszkiewicz io_can_start(struct ftl_md *md) 5987a7ac2afSArtur Paszkiewicz { 5997a7ac2afSArtur Paszkiewicz assert(NULL == md->io.data); 6007a7ac2afSArtur Paszkiewicz if (NULL != md->io.data) { 6017a7ac2afSArtur Paszkiewicz /* Outgoing IO on metadata */ 6027a7ac2afSArtur Paszkiewicz return -EINVAL; 6037a7ac2afSArtur Paszkiewicz } 6047a7ac2afSArtur Paszkiewicz 6057a7ac2afSArtur Paszkiewicz if (!md->region) { 6067a7ac2afSArtur Paszkiewicz /* No device region to process data */ 6077a7ac2afSArtur Paszkiewicz return -EINVAL; 6087a7ac2afSArtur Paszkiewicz } 6097a7ac2afSArtur Paszkiewicz 6107a7ac2afSArtur Paszkiewicz if (md->region->current.blocks > md->data_blocks) { 6117a7ac2afSArtur Paszkiewicz /* No device region to process data */ 6127a7ac2afSArtur Paszkiewicz FTL_ERRLOG(md->dev, "Blocks number mismatch between metadata object and" 6137a7ac2afSArtur Paszkiewicz "device region\n"); 6147a7ac2afSArtur Paszkiewicz return -EINVAL; 6157a7ac2afSArtur Paszkiewicz } 6167a7ac2afSArtur Paszkiewicz 6177a7ac2afSArtur Paszkiewicz return 0; 6187a7ac2afSArtur Paszkiewicz } 6197a7ac2afSArtur Paszkiewicz 6207a7ac2afSArtur Paszkiewicz static int 6217a7ac2afSArtur Paszkiewicz io_prepare(struct ftl_md *md, enum ftl_md_ops op) 6227a7ac2afSArtur Paszkiewicz { 6237a7ac2afSArtur Paszkiewicz const struct ftl_layout_region *region = md->region; 6247a7ac2afSArtur Paszkiewicz uint64_t data_size, meta_size = 0; 6257a7ac2afSArtur Paszkiewicz 6267a7ac2afSArtur Paszkiewicz /* Allocates buffer for IO */ 6277a7ac2afSArtur Paszkiewicz data_size = xfer_size(md); 6287a7ac2afSArtur Paszkiewicz md->io.data = spdk_zmalloc(data_size, FTL_BLOCK_SIZE, NULL, 6297a7ac2afSArtur Paszkiewicz SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA); 6307a7ac2afSArtur Paszkiewicz if (!md->io.data) { 6317a7ac2afSArtur Paszkiewicz return -ENOMEM; 6327a7ac2afSArtur Paszkiewicz } 6337a7ac2afSArtur Paszkiewicz 6347a7ac2afSArtur Paszkiewicz if (md->vss_data || md->region->vss_blksz) { 6357a7ac2afSArtur Paszkiewicz meta_size = ftl_md_xfer_blocks(md->dev) * FTL_MD_VSS_SZ; 6367a7ac2afSArtur Paszkiewicz md->io.md = spdk_zmalloc(meta_size, FTL_BLOCK_SIZE, NULL, 6377a7ac2afSArtur Paszkiewicz SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA); 6387a7ac2afSArtur Paszkiewicz if (!md->io.md) { 6397a7ac2afSArtur Paszkiewicz spdk_dma_free(md->io.data); 6407a7ac2afSArtur Paszkiewicz md->io.data = NULL; 6417a7ac2afSArtur Paszkiewicz return -ENOMEM; 6427a7ac2afSArtur Paszkiewicz } 6437a7ac2afSArtur Paszkiewicz } 6447a7ac2afSArtur Paszkiewicz 6457a7ac2afSArtur Paszkiewicz md->io.address = region->current.offset; 6467a7ac2afSArtur Paszkiewicz md->io.remaining = region->current.blocks; 6477a7ac2afSArtur Paszkiewicz md->io.data_offset = 0; 6487a7ac2afSArtur Paszkiewicz md->io.status = 0; 6497a7ac2afSArtur Paszkiewicz md->io.op = op; 6507a7ac2afSArtur Paszkiewicz 6517a7ac2afSArtur Paszkiewicz return 0; 6527a7ac2afSArtur Paszkiewicz } 6537a7ac2afSArtur Paszkiewicz 6547a7ac2afSArtur Paszkiewicz static int 6557a7ac2afSArtur Paszkiewicz io_init(struct ftl_md *md, enum ftl_md_ops op) 6567a7ac2afSArtur Paszkiewicz { 6577a7ac2afSArtur Paszkiewicz if (io_can_start(md)) { 6587a7ac2afSArtur Paszkiewicz return -EINVAL; 6597a7ac2afSArtur Paszkiewicz } 6607a7ac2afSArtur Paszkiewicz 6617a7ac2afSArtur Paszkiewicz if (io_prepare(md, op)) { 6627a7ac2afSArtur Paszkiewicz return -ENOMEM; 6637a7ac2afSArtur Paszkiewicz } 6647a7ac2afSArtur Paszkiewicz 6657a7ac2afSArtur Paszkiewicz return 0; 6667a7ac2afSArtur Paszkiewicz } 6677a7ac2afSArtur Paszkiewicz 6687a7ac2afSArtur Paszkiewicz static uint64_t 6697a7ac2afSArtur Paszkiewicz persist_entry_lba(struct ftl_md *md, uint64_t start_entry) 6707a7ac2afSArtur Paszkiewicz { 6717a7ac2afSArtur Paszkiewicz return md->region->current.offset + start_entry * md->region->entry_size; 6727a7ac2afSArtur Paszkiewicz } 6737a7ac2afSArtur Paszkiewicz 6747a7ac2afSArtur Paszkiewicz static void 6757a7ac2afSArtur Paszkiewicz persist_entry_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg) 6767a7ac2afSArtur Paszkiewicz { 6777a7ac2afSArtur Paszkiewicz struct ftl_md_io_entry_ctx *ctx = cb_arg; 6781790ee8aSArtur Paszkiewicz struct ftl_md *md = ctx->md; 6791790ee8aSArtur Paszkiewicz 6801790ee8aSArtur Paszkiewicz ftl_stats_bdev_io_completed(md->dev, get_bdev_io_ftl_stats_type(md->dev, bdev_io), bdev_io); 6817a7ac2afSArtur Paszkiewicz 6827a7ac2afSArtur Paszkiewicz spdk_bdev_free_io(bdev_io); 6837a7ac2afSArtur Paszkiewicz 6847a7ac2afSArtur Paszkiewicz assert(ctx->remaining > 0); 6857a7ac2afSArtur Paszkiewicz ctx->remaining--; 6867a7ac2afSArtur Paszkiewicz 6877a7ac2afSArtur Paszkiewicz if (!success) { 6887a7ac2afSArtur Paszkiewicz ctx->status = -EIO; 6897a7ac2afSArtur Paszkiewicz } 6907a7ac2afSArtur Paszkiewicz 6917a7ac2afSArtur Paszkiewicz if (!ctx->remaining) { 6927a7ac2afSArtur Paszkiewicz ctx->cb(ctx->status, ctx->cb_arg); 6937a7ac2afSArtur Paszkiewicz } 6947a7ac2afSArtur Paszkiewicz } 6957a7ac2afSArtur Paszkiewicz 6967a7ac2afSArtur Paszkiewicz static int 6977a7ac2afSArtur Paszkiewicz ftl_md_persist_entry_write_blocks(struct ftl_md_io_entry_ctx *ctx, struct ftl_md *md, 6987a7ac2afSArtur Paszkiewicz spdk_bdev_io_wait_cb retry_fn) 6997a7ac2afSArtur Paszkiewicz { 7007a7ac2afSArtur Paszkiewicz int rc; 7017a7ac2afSArtur Paszkiewicz 7027a7ac2afSArtur Paszkiewicz rc = write_blocks(md->dev, md->region->bdev_desc, md->region->ioch, 7037a7ac2afSArtur Paszkiewicz ctx->buffer, ctx->vss_buffer, 7041f11e145SMateusz Kozlowski persist_entry_lba(md, ctx->start_entry), md->region->entry_size * ctx->num_entries, 7057a7ac2afSArtur Paszkiewicz persist_entry_cb, ctx); 7067a7ac2afSArtur Paszkiewicz if (spdk_unlikely(rc)) { 7077a7ac2afSArtur Paszkiewicz if (rc == -ENOMEM) { 7087a7ac2afSArtur Paszkiewicz struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(md->region->bdev_desc); 7097a7ac2afSArtur Paszkiewicz ctx->bdev_io_wait.bdev = bdev; 7107a7ac2afSArtur Paszkiewicz ctx->bdev_io_wait.cb_fn = retry_fn; 7117a7ac2afSArtur Paszkiewicz ctx->bdev_io_wait.cb_arg = ctx; 7127a7ac2afSArtur Paszkiewicz spdk_bdev_queue_io_wait(bdev, md->region->ioch, &ctx->bdev_io_wait); 7137a7ac2afSArtur Paszkiewicz } else { 7147a7ac2afSArtur Paszkiewicz ftl_abort(); 7157a7ac2afSArtur Paszkiewicz } 7167a7ac2afSArtur Paszkiewicz } 7177a7ac2afSArtur Paszkiewicz 7187a7ac2afSArtur Paszkiewicz return rc; 7197a7ac2afSArtur Paszkiewicz } 7207a7ac2afSArtur Paszkiewicz 7217a7ac2afSArtur Paszkiewicz static void 7227a7ac2afSArtur Paszkiewicz ftl_md_persist_entry_mirror(void *_ctx) 7237a7ac2afSArtur Paszkiewicz { 7247a7ac2afSArtur Paszkiewicz struct ftl_md_io_entry_ctx *ctx = _ctx; 725522a0c82SLukasz Lasek struct ftl_md *md_mirror = ftl_md_get_mirror(ctx->md); 7267a7ac2afSArtur Paszkiewicz 727522a0c82SLukasz Lasek ftl_md_persist_entry_write_blocks(ctx, md_mirror, ftl_md_persist_entry_mirror); 7287a7ac2afSArtur Paszkiewicz } 7297a7ac2afSArtur Paszkiewicz 7307a7ac2afSArtur Paszkiewicz static void 7317a7ac2afSArtur Paszkiewicz ftl_md_persist_entry_primary(void *_ctx) 7327a7ac2afSArtur Paszkiewicz { 7337a7ac2afSArtur Paszkiewicz struct ftl_md_io_entry_ctx *ctx = _ctx; 7347a7ac2afSArtur Paszkiewicz struct ftl_md *md = ctx->md; 7357a7ac2afSArtur Paszkiewicz int rc; 7367a7ac2afSArtur Paszkiewicz 7377a7ac2afSArtur Paszkiewicz rc = ftl_md_persist_entry_write_blocks(ctx, md, ftl_md_persist_entry_primary); 7387a7ac2afSArtur Paszkiewicz 7397a7ac2afSArtur Paszkiewicz if (!rc && has_mirror(md)) { 740522a0c82SLukasz Lasek assert(md->region->entry_size == (ftl_md_get_mirror(md))->region->entry_size); 7417a7ac2afSArtur Paszkiewicz 7427a7ac2afSArtur Paszkiewicz /* The MD object has mirror so execute persist on it too */ 7437a7ac2afSArtur Paszkiewicz ftl_md_persist_entry_mirror(ctx); 7447a7ac2afSArtur Paszkiewicz ctx->remaining++; 7457a7ac2afSArtur Paszkiewicz } 7467a7ac2afSArtur Paszkiewicz } 7477a7ac2afSArtur Paszkiewicz 7487a7ac2afSArtur Paszkiewicz static void 7497a7ac2afSArtur Paszkiewicz _ftl_md_persist_entry(struct ftl_md_io_entry_ctx *ctx) 7507a7ac2afSArtur Paszkiewicz { 7517a7ac2afSArtur Paszkiewicz ctx->status = 0; 7527a7ac2afSArtur Paszkiewicz ctx->remaining = 1; 7537a7ac2afSArtur Paszkiewicz 7547a7ac2afSArtur Paszkiewicz /* First execute an IO to the primary region */ 7557a7ac2afSArtur Paszkiewicz ftl_md_persist_entry_primary(ctx); 7567a7ac2afSArtur Paszkiewicz } 7577a7ac2afSArtur Paszkiewicz 7587a7ac2afSArtur Paszkiewicz void 7591f11e145SMateusz Kozlowski ftl_md_persist_entries(struct ftl_md *md, uint64_t start_entry, uint64_t num_entries, void *buffer, 7601f11e145SMateusz Kozlowski void *vss_buffer, ftl_md_io_entry_cb cb, void *cb_arg, 7617a7ac2afSArtur Paszkiewicz struct ftl_md_io_entry_ctx *ctx) 7627a7ac2afSArtur Paszkiewicz { 7637a7ac2afSArtur Paszkiewicz if (spdk_unlikely(0 == md->region->entry_size)) { 7647a7ac2afSArtur Paszkiewicz /* This MD has not been configured to support persist entry call */ 7657a7ac2afSArtur Paszkiewicz ftl_abort(); 7667a7ac2afSArtur Paszkiewicz } 7671f11e145SMateusz Kozlowski if (spdk_unlikely(start_entry + num_entries > md->region->num_entries)) { 76834edd9f1SKamil Godzwon /* Exceeding number of available entries */ 7691f11e145SMateusz Kozlowski ftl_abort(); 7701f11e145SMateusz Kozlowski } 7717a7ac2afSArtur Paszkiewicz 7727a7ac2afSArtur Paszkiewicz /* Initialize persist entry context */ 7737a7ac2afSArtur Paszkiewicz ctx->cb = cb; 7747a7ac2afSArtur Paszkiewicz ctx->cb_arg = cb_arg; 7757a7ac2afSArtur Paszkiewicz ctx->md = md; 7767a7ac2afSArtur Paszkiewicz ctx->start_entry = start_entry; 7777a7ac2afSArtur Paszkiewicz ctx->buffer = buffer; 7781f11e145SMateusz Kozlowski ctx->num_entries = num_entries; 7797a7ac2afSArtur Paszkiewicz ctx->vss_buffer = vss_buffer ? : md->entry_vss_dma_buf; 7807a7ac2afSArtur Paszkiewicz 7817a7ac2afSArtur Paszkiewicz _ftl_md_persist_entry(ctx); 7827a7ac2afSArtur Paszkiewicz } 7837a7ac2afSArtur Paszkiewicz 7847a7ac2afSArtur Paszkiewicz static void 7857a7ac2afSArtur Paszkiewicz read_entry_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg) 7867a7ac2afSArtur Paszkiewicz { 7877a7ac2afSArtur Paszkiewicz struct ftl_md_io_entry_ctx *ctx = cb_arg; 7887a7ac2afSArtur Paszkiewicz struct ftl_md *md = ctx->md; 7897a7ac2afSArtur Paszkiewicz 7901790ee8aSArtur Paszkiewicz ftl_stats_bdev_io_completed(md->dev, get_bdev_io_ftl_stats_type(md->dev, bdev_io), bdev_io); 7911790ee8aSArtur Paszkiewicz 7927a7ac2afSArtur Paszkiewicz spdk_bdev_free_io(bdev_io); 7937a7ac2afSArtur Paszkiewicz 7947a7ac2afSArtur Paszkiewicz if (!success) { 7957a7ac2afSArtur Paszkiewicz if (has_mirror(md)) { 796522a0c82SLukasz Lasek md->mirror_enabled = true; 7977a7ac2afSArtur Paszkiewicz 7987a7ac2afSArtur Paszkiewicz /* First read from the mirror */ 799522a0c82SLukasz Lasek ftl_md_read_entry(ftl_md_get_mirror(md), ctx->start_entry, ctx->buffer, 800522a0c82SLukasz Lasek ctx->vss_buffer, 8017a7ac2afSArtur Paszkiewicz ctx->cb, ctx->cb_arg, 8027a7ac2afSArtur Paszkiewicz ctx); 8037a7ac2afSArtur Paszkiewicz return; 8047a7ac2afSArtur Paszkiewicz } else { 8057a7ac2afSArtur Paszkiewicz ctx->status = -EIO; 8067a7ac2afSArtur Paszkiewicz goto finish_io; 8077a7ac2afSArtur Paszkiewicz } 8087a7ac2afSArtur Paszkiewicz } 8097a7ac2afSArtur Paszkiewicz 8107a7ac2afSArtur Paszkiewicz finish_io: 8117a7ac2afSArtur Paszkiewicz ctx->cb(ctx->status, ctx->cb_arg); 8127a7ac2afSArtur Paszkiewicz } 8137a7ac2afSArtur Paszkiewicz 8147a7ac2afSArtur Paszkiewicz static void 8157a7ac2afSArtur Paszkiewicz ftl_md_read_entry_read_blocks(struct ftl_md_io_entry_ctx *ctx, struct ftl_md *md, 8167a7ac2afSArtur Paszkiewicz spdk_bdev_io_wait_cb retry_fn) 8177a7ac2afSArtur Paszkiewicz { 8187a7ac2afSArtur Paszkiewicz int rc; 8197a7ac2afSArtur Paszkiewicz 8207a7ac2afSArtur Paszkiewicz rc = read_blocks(md->dev, md->region->bdev_desc, md->region->ioch, 8217a7ac2afSArtur Paszkiewicz ctx->buffer, ctx->vss_buffer, 8227a7ac2afSArtur Paszkiewicz persist_entry_lba(md, ctx->start_entry), md->region->entry_size, 8237a7ac2afSArtur Paszkiewicz read_entry_cb, ctx); 8247a7ac2afSArtur Paszkiewicz 8257a7ac2afSArtur Paszkiewicz if (spdk_unlikely(rc)) { 8267a7ac2afSArtur Paszkiewicz if (rc == -ENOMEM) { 8277a7ac2afSArtur Paszkiewicz struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(md->region->bdev_desc); 8287a7ac2afSArtur Paszkiewicz ctx->bdev_io_wait.bdev = bdev; 8297a7ac2afSArtur Paszkiewicz ctx->bdev_io_wait.cb_fn = retry_fn; 8307a7ac2afSArtur Paszkiewicz ctx->bdev_io_wait.cb_arg = ctx; 8317a7ac2afSArtur Paszkiewicz spdk_bdev_queue_io_wait(bdev, md->region->ioch, &ctx->bdev_io_wait); 8327a7ac2afSArtur Paszkiewicz } else { 8337a7ac2afSArtur Paszkiewicz ftl_abort(); 8347a7ac2afSArtur Paszkiewicz } 8357a7ac2afSArtur Paszkiewicz } 8367a7ac2afSArtur Paszkiewicz } 8377a7ac2afSArtur Paszkiewicz 8387a7ac2afSArtur Paszkiewicz static void 8397a7ac2afSArtur Paszkiewicz _ftl_md_read_entry(void *_ctx) 8407a7ac2afSArtur Paszkiewicz { 8417a7ac2afSArtur Paszkiewicz struct ftl_md_io_entry_ctx *ctx = _ctx; 8427a7ac2afSArtur Paszkiewicz 8437a7ac2afSArtur Paszkiewicz ftl_md_read_entry_read_blocks(ctx, ctx->md, _ftl_md_read_entry); 8447a7ac2afSArtur Paszkiewicz } 8457a7ac2afSArtur Paszkiewicz 8467a7ac2afSArtur Paszkiewicz void 8477a7ac2afSArtur Paszkiewicz ftl_md_read_entry(struct ftl_md *md, uint64_t start_entry, void *buffer, void *vss_buffer, 8487a7ac2afSArtur Paszkiewicz ftl_md_io_entry_cb cb, void *cb_arg, 8497a7ac2afSArtur Paszkiewicz struct ftl_md_io_entry_ctx *ctx) 8507a7ac2afSArtur Paszkiewicz { 8517a7ac2afSArtur Paszkiewicz if (spdk_unlikely(0 == md->region->entry_size)) { 8527a7ac2afSArtur Paszkiewicz /* This MD has not been configured to support read entry call */ 8537a7ac2afSArtur Paszkiewicz ftl_abort(); 8547a7ac2afSArtur Paszkiewicz } 8557a7ac2afSArtur Paszkiewicz 8567a7ac2afSArtur Paszkiewicz ctx->cb = cb; 8577a7ac2afSArtur Paszkiewicz ctx->cb_arg = cb_arg; 8587a7ac2afSArtur Paszkiewicz ctx->md = md; 8597a7ac2afSArtur Paszkiewicz ctx->start_entry = start_entry; 8607a7ac2afSArtur Paszkiewicz ctx->buffer = buffer; 8617a7ac2afSArtur Paszkiewicz ctx->vss_buffer = vss_buffer; 8627a7ac2afSArtur Paszkiewicz 8637a7ac2afSArtur Paszkiewicz _ftl_md_read_entry(ctx); 8647a7ac2afSArtur Paszkiewicz } 8657a7ac2afSArtur Paszkiewicz 8667a7ac2afSArtur Paszkiewicz void 8677a7ac2afSArtur Paszkiewicz ftl_md_persist_entry_retry(struct ftl_md_io_entry_ctx *ctx) 8687a7ac2afSArtur Paszkiewicz { 8697a7ac2afSArtur Paszkiewicz _ftl_md_persist_entry(ctx); 8707a7ac2afSArtur Paszkiewicz } 8717a7ac2afSArtur Paszkiewicz 8727a7ac2afSArtur Paszkiewicz static void 8737a7ac2afSArtur Paszkiewicz persist_mirror_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status) 8747a7ac2afSArtur Paszkiewicz { 8757a7ac2afSArtur Paszkiewicz struct ftl_md *primary = md->owner.private; 8767a7ac2afSArtur Paszkiewicz 8777a7ac2afSArtur Paszkiewicz if (status) { 8787a7ac2afSArtur Paszkiewicz /* We got an error, stop persist procedure immediately */ 8797a7ac2afSArtur Paszkiewicz primary->io.status = status; 8807a7ac2afSArtur Paszkiewicz io_done(primary); 8817a7ac2afSArtur Paszkiewicz } else { 8827a7ac2afSArtur Paszkiewicz /* Now continue the persist procedure on the primary MD object */ 8837a7ac2afSArtur Paszkiewicz if (0 == io_init(primary, FTL_MD_OP_PERSIST)) { 8847a7ac2afSArtur Paszkiewicz io_submit(primary); 8857a7ac2afSArtur Paszkiewicz } else { 8867a7ac2afSArtur Paszkiewicz spdk_thread_send_msg(spdk_get_thread(), exception, primary); 8877a7ac2afSArtur Paszkiewicz } 8887a7ac2afSArtur Paszkiewicz } 8897a7ac2afSArtur Paszkiewicz } 8907a7ac2afSArtur Paszkiewicz 8917a7ac2afSArtur Paszkiewicz void 8927a7ac2afSArtur Paszkiewicz ftl_md_persist(struct ftl_md *md) 8937a7ac2afSArtur Paszkiewicz { 8947a7ac2afSArtur Paszkiewicz if (has_mirror(md)) { 895522a0c82SLukasz Lasek struct ftl_md *md_mirror = ftl_md_get_mirror(md); 896522a0c82SLukasz Lasek 897522a0c82SLukasz Lasek md->mirror_enabled = true; 8987a7ac2afSArtur Paszkiewicz 8997a7ac2afSArtur Paszkiewicz /* Set callback and context in mirror */ 900522a0c82SLukasz Lasek md_mirror->cb = persist_mirror_cb; 901522a0c82SLukasz Lasek md_mirror->owner.private = md; 9027a7ac2afSArtur Paszkiewicz 9037a7ac2afSArtur Paszkiewicz /* First persist the mirror */ 904522a0c82SLukasz Lasek ftl_md_persist(md_mirror); 9057a7ac2afSArtur Paszkiewicz return; 9067a7ac2afSArtur Paszkiewicz } 9077a7ac2afSArtur Paszkiewicz 9087a7ac2afSArtur Paszkiewicz if (0 == io_init(md, FTL_MD_OP_PERSIST)) { 9097a7ac2afSArtur Paszkiewicz io_submit(md); 9107a7ac2afSArtur Paszkiewicz } else { 9117a7ac2afSArtur Paszkiewicz spdk_thread_send_msg(spdk_get_thread(), exception, md); 9127a7ac2afSArtur Paszkiewicz } 9137a7ac2afSArtur Paszkiewicz } 9147a7ac2afSArtur Paszkiewicz 9157a7ac2afSArtur Paszkiewicz static void 9167a7ac2afSArtur Paszkiewicz restore_mirror_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status) 9177a7ac2afSArtur Paszkiewicz { 9187a7ac2afSArtur Paszkiewicz struct ftl_md *primary = md->owner.private; 9197a7ac2afSArtur Paszkiewicz 9207a7ac2afSArtur Paszkiewicz if (status) { 9217a7ac2afSArtur Paszkiewicz /* Cannot restore the object from the mirror too, mark error and fail */ 9227a7ac2afSArtur Paszkiewicz primary->io.status = -EIO; 9237a7ac2afSArtur Paszkiewicz io_done(primary); 9247a7ac2afSArtur Paszkiewicz } else { 9257a7ac2afSArtur Paszkiewicz /* 9267a7ac2afSArtur Paszkiewicz * Restoring from the mirror successful. Synchronize mirror to the primary. 9277a7ac2afSArtur Paszkiewicz * Because we read MD content from the mirror, we can disable it, only the primary 9287a7ac2afSArtur Paszkiewicz * requires persisting. 9297a7ac2afSArtur Paszkiewicz */ 9307a7ac2afSArtur Paszkiewicz primary->io.status = 0; 9317a7ac2afSArtur Paszkiewicz primary->mirror_enabled = false; 9327a7ac2afSArtur Paszkiewicz io_cleanup(primary); 9337a7ac2afSArtur Paszkiewicz ftl_md_persist(primary); 9347a7ac2afSArtur Paszkiewicz primary->mirror_enabled = true; 9357a7ac2afSArtur Paszkiewicz } 9367a7ac2afSArtur Paszkiewicz } 9377a7ac2afSArtur Paszkiewicz 938c6880a39SArtur Paszkiewicz static void 939c6880a39SArtur Paszkiewicz restore_sync_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status) 940c6880a39SArtur Paszkiewicz { 941c6880a39SArtur Paszkiewicz struct ftl_md *primary = md->owner.private; 942c6880a39SArtur Paszkiewicz 943c6880a39SArtur Paszkiewicz if (status) { 944c6880a39SArtur Paszkiewicz /* Cannot sync the object from the primary to the mirror, mark error and fail */ 945c6880a39SArtur Paszkiewicz primary->io.status = -EIO; 946c6880a39SArtur Paszkiewicz io_done(primary); 947c6880a39SArtur Paszkiewicz } else { 948c6880a39SArtur Paszkiewicz primary->cb(dev, primary, primary->io.status); 949c6880a39SArtur Paszkiewicz io_cleanup(primary); 950c6880a39SArtur Paszkiewicz } 951c6880a39SArtur Paszkiewicz } 952c6880a39SArtur Paszkiewicz 9537a7ac2afSArtur Paszkiewicz static int 9547a7ac2afSArtur Paszkiewicz restore_done(struct ftl_md *md) 9557a7ac2afSArtur Paszkiewicz { 9567a7ac2afSArtur Paszkiewicz if (-EAGAIN == md->io.status) { 9577a7ac2afSArtur Paszkiewicz /* Failed to read MD from primary region, try it from mirror. 9587a7ac2afSArtur Paszkiewicz * At the moment read the mirror entirely, (TODO) in the 9597a7ac2afSArtur Paszkiewicz * feature we can restore from primary and mirror region 9607a7ac2afSArtur Paszkiewicz * with finer granularity. 9617a7ac2afSArtur Paszkiewicz */ 9627a7ac2afSArtur Paszkiewicz 9637a7ac2afSArtur Paszkiewicz if (has_mirror(md)) { 964522a0c82SLukasz Lasek struct ftl_md *md_mirror = ftl_md_get_mirror(md); 965522a0c82SLukasz Lasek 966522a0c82SLukasz Lasek md->mirror_enabled = true; 9677a7ac2afSArtur Paszkiewicz 9687a7ac2afSArtur Paszkiewicz /* Set callback and context in mirror */ 969522a0c82SLukasz Lasek md_mirror->cb = restore_mirror_cb; 970522a0c82SLukasz Lasek md_mirror->owner.private = md; 9717a7ac2afSArtur Paszkiewicz 9727a7ac2afSArtur Paszkiewicz /* First persist the mirror */ 973522a0c82SLukasz Lasek ftl_md_restore(md_mirror); 9747a7ac2afSArtur Paszkiewicz return -EAGAIN; 9757a7ac2afSArtur Paszkiewicz } else { 9767a7ac2afSArtur Paszkiewicz return -EIO; 9777a7ac2afSArtur Paszkiewicz } 978c6880a39SArtur Paszkiewicz } else if (0 == md->io.status && false == md->dev->sb->clean) { 979c6880a39SArtur Paszkiewicz if (has_mirror(md)) { 980522a0c82SLukasz Lasek struct ftl_md *md_mirror = ftl_md_get_mirror(md); 981c6880a39SArtur Paszkiewicz /* There was a dirty shutdown, synchronize primary to mirror */ 982c6880a39SArtur Paszkiewicz 983c6880a39SArtur Paszkiewicz /* Set callback and context in the mirror */ 984522a0c82SLukasz Lasek md_mirror->cb = restore_sync_cb; 985522a0c82SLukasz Lasek md_mirror->owner.private = md; 986c6880a39SArtur Paszkiewicz 987c6880a39SArtur Paszkiewicz /* First persist the mirror */ 988522a0c82SLukasz Lasek ftl_md_persist(md_mirror); 989c6880a39SArtur Paszkiewicz return -EAGAIN; 990c6880a39SArtur Paszkiewicz } 9917a7ac2afSArtur Paszkiewicz } 9927a7ac2afSArtur Paszkiewicz 9937a7ac2afSArtur Paszkiewicz return md->io.status; 9947a7ac2afSArtur Paszkiewicz } 9957a7ac2afSArtur Paszkiewicz 9967a7ac2afSArtur Paszkiewicz static void 9977a7ac2afSArtur Paszkiewicz io_done(struct ftl_md *md) 9987a7ac2afSArtur Paszkiewicz { 9997a7ac2afSArtur Paszkiewicz int status; 10007a7ac2afSArtur Paszkiewicz 10017a7ac2afSArtur Paszkiewicz if (md->io.op == FTL_MD_OP_RESTORE) { 10027a7ac2afSArtur Paszkiewicz status = restore_done(md); 10037a7ac2afSArtur Paszkiewicz } else { 10047a7ac2afSArtur Paszkiewicz status = md->io.status; 10057a7ac2afSArtur Paszkiewicz } 10067a7ac2afSArtur Paszkiewicz 10077a7ac2afSArtur Paszkiewicz if (status != -EAGAIN) { 10089f42898aSLukasz Lasek /* The MD instance may be destroyed in ctx of md->cb(), e.g. upon region upgrade. */ 10099f42898aSLukasz Lasek /* Need to cleanup DMA bufs first. */ 10107a7ac2afSArtur Paszkiewicz io_cleanup(md); 10119f42898aSLukasz Lasek md->cb(md->dev, md, status); 10127a7ac2afSArtur Paszkiewicz } 10137a7ac2afSArtur Paszkiewicz } 10147a7ac2afSArtur Paszkiewicz 10157a7ac2afSArtur Paszkiewicz void 10167a7ac2afSArtur Paszkiewicz ftl_md_restore(struct ftl_md *md) 10177a7ac2afSArtur Paszkiewicz { 10187a7ac2afSArtur Paszkiewicz if (0 == io_init(md, FTL_MD_OP_RESTORE)) { 10197a7ac2afSArtur Paszkiewicz io_submit(md); 10207a7ac2afSArtur Paszkiewicz } else { 10217a7ac2afSArtur Paszkiewicz spdk_thread_send_msg(spdk_get_thread(), exception, md); 10227a7ac2afSArtur Paszkiewicz } 10237a7ac2afSArtur Paszkiewicz } 10247a7ac2afSArtur Paszkiewicz 10257a7ac2afSArtur Paszkiewicz static int 10267a7ac2afSArtur Paszkiewicz pattern_prepare(struct ftl_md *md, 10277a7ac2afSArtur Paszkiewicz int data_pattern, union ftl_md_vss *vss_pattern) 10287a7ac2afSArtur Paszkiewicz { 10297a7ac2afSArtur Paszkiewicz void *data = md->io.data; 10307a7ac2afSArtur Paszkiewicz uint64_t data_size = xfer_size(md); 10317a7ac2afSArtur Paszkiewicz 10327a7ac2afSArtur Paszkiewicz memset(data, data_pattern, data_size); 10337a7ac2afSArtur Paszkiewicz 10347a7ac2afSArtur Paszkiewicz if (md->io.md) { 10357a7ac2afSArtur Paszkiewicz if (vss_pattern) { 10367a7ac2afSArtur Paszkiewicz /* store the VSS pattern... */ 10377a7ac2afSArtur Paszkiewicz ftl_md_vss_buf_init(md->io.md, ftl_md_xfer_blocks(md->dev), vss_pattern); 10387a7ac2afSArtur Paszkiewicz } else { 10397a7ac2afSArtur Paszkiewicz /* ...or default init VSS to 0 */ 10407a7ac2afSArtur Paszkiewicz union ftl_md_vss vss = {0}; 10417a7ac2afSArtur Paszkiewicz 10427a7ac2afSArtur Paszkiewicz vss.version.md_version = md->region->current.version; 10437a7ac2afSArtur Paszkiewicz ftl_md_vss_buf_init(md->io.md, ftl_md_xfer_blocks(md->dev), &vss); 10447a7ac2afSArtur Paszkiewicz } 10457a7ac2afSArtur Paszkiewicz } 10467a7ac2afSArtur Paszkiewicz 10477a7ac2afSArtur Paszkiewicz return 0; 10487a7ac2afSArtur Paszkiewicz } 10497a7ac2afSArtur Paszkiewicz 10507a7ac2afSArtur Paszkiewicz static void 10517a7ac2afSArtur Paszkiewicz clear_mirror_cb(struct spdk_ftl_dev *dev, struct ftl_md *secondary, int status) 10527a7ac2afSArtur Paszkiewicz { 10537a7ac2afSArtur Paszkiewicz struct ftl_md *primary = secondary->owner.private; 10547a7ac2afSArtur Paszkiewicz 10557a7ac2afSArtur Paszkiewicz if (status) { 10567a7ac2afSArtur Paszkiewicz /* We got an error, stop persist procedure immediately */ 10577a7ac2afSArtur Paszkiewicz primary->io.status = status; 10587a7ac2afSArtur Paszkiewicz io_done(primary); 10597a7ac2afSArtur Paszkiewicz } else { 10607a7ac2afSArtur Paszkiewicz /* Now continue the persist procedure on the primary MD object */ 10617a7ac2afSArtur Paszkiewicz io_submit(primary); 10627a7ac2afSArtur Paszkiewicz } 10637a7ac2afSArtur Paszkiewicz } 10647a7ac2afSArtur Paszkiewicz 10657a7ac2afSArtur Paszkiewicz void 10667a7ac2afSArtur Paszkiewicz ftl_md_clear(struct ftl_md *md, int data_pattern, union ftl_md_vss *vss_pattern) 10677a7ac2afSArtur Paszkiewicz { 10687a7ac2afSArtur Paszkiewicz if (has_mirror(md)) { 1069522a0c82SLukasz Lasek struct ftl_md *md_mirror = ftl_md_get_mirror(md); 1070522a0c82SLukasz Lasek 1071522a0c82SLukasz Lasek md->mirror_enabled = true; 10727a7ac2afSArtur Paszkiewicz 10737a7ac2afSArtur Paszkiewicz /* Set callback and context in mirror */ 1074522a0c82SLukasz Lasek md_mirror->cb = clear_mirror_cb; 1075522a0c82SLukasz Lasek md_mirror->owner.private = md; 10767a7ac2afSArtur Paszkiewicz 1077db085261SMateusz Kozlowski /* The pattern bufs will not be available outside of this fn context */ 1078db085261SMateusz Kozlowski /* Configure the IO for the primary region now */ 1079db085261SMateusz Kozlowski if (0 == io_init(md, FTL_MD_OP_CLEAR) && 0 == pattern_prepare(md, data_pattern, vss_pattern)) { 10807a7ac2afSArtur Paszkiewicz /* First persist the mirror */ 1081522a0c82SLukasz Lasek ftl_md_clear(md_mirror, data_pattern, vss_pattern); 1082db085261SMateusz Kozlowski } else { 1083db085261SMateusz Kozlowski spdk_thread_send_msg(spdk_get_thread(), exception, md); 1084db085261SMateusz Kozlowski } 10857a7ac2afSArtur Paszkiewicz return; 10867a7ac2afSArtur Paszkiewicz } 10877a7ac2afSArtur Paszkiewicz 10887a7ac2afSArtur Paszkiewicz if (0 == io_init(md, FTL_MD_OP_CLEAR) && 0 == pattern_prepare(md, data_pattern, vss_pattern)) { 10897a7ac2afSArtur Paszkiewicz io_submit(md); 10907a7ac2afSArtur Paszkiewicz } else { 10917a7ac2afSArtur Paszkiewicz spdk_thread_send_msg(spdk_get_thread(), exception, md); 10927a7ac2afSArtur Paszkiewicz } 10937a7ac2afSArtur Paszkiewicz } 10947a7ac2afSArtur Paszkiewicz 10957a7ac2afSArtur Paszkiewicz const struct ftl_layout_region * 10967a7ac2afSArtur Paszkiewicz ftl_md_get_region(struct ftl_md *md) 10977a7ac2afSArtur Paszkiewicz { 10987a7ac2afSArtur Paszkiewicz return md->region; 10997a7ac2afSArtur Paszkiewicz } 11007a7ac2afSArtur Paszkiewicz 1101522a0c82SLukasz Lasek void 11027a7ac2afSArtur Paszkiewicz ftl_md_set_region(struct ftl_md *md, 11037a7ac2afSArtur Paszkiewicz const struct ftl_layout_region *region) 11047a7ac2afSArtur Paszkiewicz { 11057a7ac2afSArtur Paszkiewicz assert(region->current.blocks <= md->data_blocks); 11067a7ac2afSArtur Paszkiewicz md->region = region; 11077a7ac2afSArtur Paszkiewicz 11087a7ac2afSArtur Paszkiewicz if (md->vss_data) { 11097a7ac2afSArtur Paszkiewicz union ftl_md_vss vss = {0}; 11107a7ac2afSArtur Paszkiewicz vss.version.md_version = region->current.version; 11117a7ac2afSArtur Paszkiewicz ftl_md_vss_buf_init(md->vss_data, md->data_blocks, &vss); 11127a7ac2afSArtur Paszkiewicz if (region->entry_size) { 11137a7ac2afSArtur Paszkiewicz assert(md->entry_vss_dma_buf); 11147a7ac2afSArtur Paszkiewicz ftl_md_vss_buf_init(md->entry_vss_dma_buf, region->entry_size, &vss); 11157a7ac2afSArtur Paszkiewicz } 11167a7ac2afSArtur Paszkiewicz } 11177a7ac2afSArtur Paszkiewicz 11187a7ac2afSArtur Paszkiewicz if (has_mirror(md)) { 1119522a0c82SLukasz Lasek md->mirror_enabled = true; 11207a7ac2afSArtur Paszkiewicz } 11217a7ac2afSArtur Paszkiewicz } 1122811a027eSKozlowski Mateusz 1123811a027eSKozlowski Mateusz int 1124811a027eSKozlowski Mateusz ftl_md_create_region_flags(struct spdk_ftl_dev *dev, int region_type) 1125811a027eSKozlowski Mateusz { 1126811a027eSKozlowski Mateusz int flags = FTL_MD_CREATE_SHM; 1127811a027eSKozlowski Mateusz 1128811a027eSKozlowski Mateusz switch (region_type) { 1129811a027eSKozlowski Mateusz case FTL_LAYOUT_REGION_TYPE_SB: 1130811a027eSKozlowski Mateusz if (dev->conf.mode & SPDK_FTL_MODE_CREATE) { 1131811a027eSKozlowski Mateusz flags |= FTL_MD_CREATE_SHM_NEW; 1132811a027eSKozlowski Mateusz } 1133811a027eSKozlowski Mateusz break; 1134811a027eSKozlowski Mateusz 1135811a027eSKozlowski Mateusz case FTL_LAYOUT_REGION_TYPE_BAND_MD: 1136811a027eSKozlowski Mateusz case FTL_LAYOUT_REGION_TYPE_NVC_MD: 11371e904e2bSArtur Paszkiewicz if (!ftl_fast_startup(dev)) { 1138811a027eSKozlowski Mateusz flags |= FTL_MD_CREATE_SHM_NEW; 11391e904e2bSArtur Paszkiewicz } 1140811a027eSKozlowski Mateusz break; 1141cea8dadeSArtur Paszkiewicz case FTL_LAYOUT_REGION_TYPE_VALID_MAP: 114278c3cbf4SArtur Paszkiewicz case FTL_LAYOUT_REGION_TYPE_TRIM_MD: 11432d613454SMateusz Kozlowski case FTL_LAYOUT_REGION_TYPE_TRIM_LOG: 1144cea8dadeSArtur Paszkiewicz if (!ftl_fast_startup(dev) && !ftl_fast_recovery(dev)) { 1145cea8dadeSArtur Paszkiewicz flags |= FTL_MD_CREATE_SHM_NEW; 1146cea8dadeSArtur Paszkiewicz } 1147cea8dadeSArtur Paszkiewicz break; 11484061ed11SMateusz Kozlowski case FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC: 11494061ed11SMateusz Kozlowski case FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC_NEXT: 11504061ed11SMateusz Kozlowski case FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP: 11514061ed11SMateusz Kozlowski case FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP_NEXT: 11524061ed11SMateusz Kozlowski return FTL_MD_CREATE_SPDK_BUF; 1153811a027eSKozlowski Mateusz default: 1154811a027eSKozlowski Mateusz return FTL_MD_CREATE_HEAP; 1155811a027eSKozlowski Mateusz } 1156811a027eSKozlowski Mateusz 1157811a027eSKozlowski Mateusz return flags; 1158811a027eSKozlowski Mateusz } 1159811a027eSKozlowski Mateusz 1160811a027eSKozlowski Mateusz int 11610e33da49SKozlowski Mateusz ftl_md_destroy_region_flags(struct spdk_ftl_dev *dev, int region_type) 11620e33da49SKozlowski Mateusz { 11630e33da49SKozlowski Mateusz switch (region_type) { 11640e33da49SKozlowski Mateusz case FTL_LAYOUT_REGION_TYPE_SB: 11650e33da49SKozlowski Mateusz case FTL_LAYOUT_REGION_TYPE_BAND_MD: 1166cea8dadeSArtur Paszkiewicz case FTL_LAYOUT_REGION_TYPE_VALID_MAP: 11670e33da49SKozlowski Mateusz case FTL_LAYOUT_REGION_TYPE_NVC_MD: 116878c3cbf4SArtur Paszkiewicz case FTL_LAYOUT_REGION_TYPE_TRIM_MD: 11692d613454SMateusz Kozlowski case FTL_LAYOUT_REGION_TYPE_TRIM_LOG: 11700e33da49SKozlowski Mateusz if (dev->conf.fast_shutdown) { 11710e33da49SKozlowski Mateusz return FTL_MD_DESTROY_SHM_KEEP; 11720e33da49SKozlowski Mateusz } 11730e33da49SKozlowski Mateusz break; 11744061ed11SMateusz Kozlowski case FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC: 11754061ed11SMateusz Kozlowski case FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC_NEXT: 11764061ed11SMateusz Kozlowski case FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP: 11774061ed11SMateusz Kozlowski case FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP_NEXT: 11784061ed11SMateusz Kozlowski return FTL_MD_DESTROY_SPDK_BUF; 11790e33da49SKozlowski Mateusz default: 11800e33da49SKozlowski Mateusz break; 11810e33da49SKozlowski Mateusz } 11820e33da49SKozlowski Mateusz return 0; 11830e33da49SKozlowski Mateusz } 11840e33da49SKozlowski Mateusz 11850e33da49SKozlowski Mateusz int 1186811a027eSKozlowski Mateusz ftl_md_create_shm_flags(struct spdk_ftl_dev *dev) 1187811a027eSKozlowski Mateusz { 11881e904e2bSArtur Paszkiewicz int flags = FTL_MD_CREATE_SHM; 1189811a027eSKozlowski Mateusz 11901e904e2bSArtur Paszkiewicz if (!ftl_fast_startup(dev) && !ftl_fast_recovery(dev)) { 11911e904e2bSArtur Paszkiewicz flags |= FTL_MD_CREATE_SHM_NEW; 11921e904e2bSArtur Paszkiewicz } 1193811a027eSKozlowski Mateusz return flags; 1194811a027eSKozlowski Mateusz } 11950e33da49SKozlowski Mateusz 11960e33da49SKozlowski Mateusz int 11970e33da49SKozlowski Mateusz ftl_md_destroy_shm_flags(struct spdk_ftl_dev *dev) 11980e33da49SKozlowski Mateusz { 11990e33da49SKozlowski Mateusz return (dev->conf.fast_shutdown) ? FTL_MD_DESTROY_SHM_KEEP : 0; 12000e33da49SKozlowski Mateusz } 1201