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 "ftl_sb_v3.h" 8 : #include "ftl_core.h" 9 : #include "ftl_layout.h" 10 : #include "upgrade/ftl_sb_upgrade.h" 11 : 12 : bool 13 0 : ftl_superblock_v3_check_magic(union ftl_superblock_ver *sb_ver) 14 : { 15 0 : return sb_ver->header.magic == FTL_SUPERBLOCK_MAGIC; 16 : } 17 : 18 : bool 19 3 : ftl_superblock_v3_md_layout_is_empty(union ftl_superblock_ver *sb_ver) 20 : { 21 3 : return sb_ver->v3.md_layout_head.type == FTL_LAYOUT_REGION_TYPE_INVALID; 22 : } 23 : 24 : static bool 25 326 : md_region_is_fixed(int reg_type) 26 : { 27 326 : switch (reg_type) { 28 49 : case FTL_LAYOUT_REGION_TYPE_SB: 29 : case FTL_LAYOUT_REGION_TYPE_SB_BASE: 30 : case FTL_LAYOUT_REGION_TYPE_DATA_BASE: 31 49 : return true; 32 : 33 277 : default: 34 277 : return false; 35 : } 36 : } 37 : 38 : bool 39 85 : ftl_superblock_v3_md_region_overflow(struct spdk_ftl_dev *dev, 40 : struct ftl_superblock_v3_md_region *sb_reg) 41 : { 42 : /* sb_reg is part of the sb structure - the pointer should be at a positive offset */ 43 85 : if ((uintptr_t)sb_reg < (uintptr_t)dev->sb) { 44 0 : return true; 45 : } 46 : 47 : /* Make sure the entry doesn't overflow the pointer value (probably overkill to check) */ 48 85 : if (UINT64_MAX - (uintptr_t)sb_reg <= sizeof(*sb_reg)) { 49 0 : return true; 50 : } 51 : 52 : /* There's only a finite (FTL_SUPERBLOCK_SIZE) amount of space in the superblock. Make sure the region wholly fits in that space. */ 53 85 : if ((uintptr_t)(sb_reg + 1) > ((uintptr_t)(dev->sb) + FTL_SUPERBLOCK_SIZE)) { 54 1 : return true; 55 : } 56 : 57 84 : return false; 58 : } 59 : 60 : int 61 15 : ftl_superblock_v3_md_layout_load_all(struct spdk_ftl_dev *dev) 62 : { 63 15 : struct ftl_superblock_v3 *sb = (struct ftl_superblock_v3 *)dev->sb; 64 15 : struct ftl_superblock_v3_md_region *sb_reg = &sb->md_layout_head; 65 15 : struct ftl_layout *layout = &dev->layout; 66 : uint32_t regs_found; 67 : uint32_t n; 68 15 : ftl_df_obj_id df_sentinel = FTL_DF_OBJ_ID_INVALID; 69 15 : ftl_df_obj_id df_prev = ftl_df_get_obj_id(sb, sb_reg); 70 : 71 255 : for (n = 0; n < FTL_LAYOUT_REGION_TYPE_MAX_V3; n++) { 72 240 : if (md_region_is_fixed(n)) { 73 45 : continue; 74 : } 75 195 : layout->region[n].type = FTL_LAYOUT_REGION_TYPE_INVALID; 76 : } 77 : 78 81 : while (sb_reg->type != FTL_LAYOUT_REGION_TYPE_INVALID) { 79 : struct ftl_layout_region *reg; 80 : 81 : /* TODO: major upgrades: add free regions tracking */ 82 80 : if (sb_reg->type == FTL_LAYOUT_REGION_TYPE_FREE_NVC || 83 76 : sb_reg->type == FTL_LAYOUT_REGION_TYPE_FREE_BASE) { 84 8 : goto next_sb_reg; 85 : } 86 : 87 72 : if (sb_reg->type >= FTL_LAYOUT_REGION_TYPE_MAX_V3) { 88 2 : FTL_ERRLOG(dev, "Invalid MD region type found\n"); 89 2 : return -1; 90 : } 91 : 92 70 : if (md_region_is_fixed(sb_reg->type)) { 93 1 : FTL_ERRLOG(dev, "Unsupported MD region type found\n"); 94 1 : return -1; 95 : } 96 : 97 69 : reg = &layout->region[sb_reg->type]; 98 : /* Find the oldest region version */ 99 69 : if (reg->type == FTL_LAYOUT_REGION_TYPE_INVALID || sb_reg->version < reg->current.version) { 100 65 : reg->type = sb_reg->type; 101 65 : reg->current.offset = sb_reg->blk_offs; 102 65 : reg->current.blocks = sb_reg->blk_sz; 103 65 : reg->current.version = sb_reg->version; 104 4 : } else if (sb_reg->version == reg->current.version) { 105 2 : FTL_ERRLOG(dev, "Multiple/looping regions found\n"); 106 2 : return -EAGAIN; 107 : } 108 : 109 2 : next_sb_reg: 110 75 : if (sb_reg->df_next == FTL_DF_OBJ_ID_INVALID) { 111 4 : break; 112 : } 113 : 114 71 : if (UINT64_MAX - (uintptr_t)sb <= sb_reg->df_next) { 115 2 : FTL_ERRLOG(dev, "Buffer overflow\n"); 116 2 : return -EOVERFLOW; 117 : } 118 : 119 69 : if (sb_reg->df_next <= df_prev) { 120 6 : df_sentinel = df_prev; 121 : } 122 69 : df_prev = sb_reg->df_next; 123 : 124 69 : if (df_sentinel != FTL_DF_OBJ_ID_INVALID && sb_reg->df_next == df_sentinel) { 125 2 : FTL_ERRLOG(dev, "Looping regions found\n"); 126 2 : return -ELOOP; 127 : } 128 : 129 67 : sb_reg = ftl_df_get_obj_ptr(sb, sb_reg->df_next); 130 67 : if (ftl_superblock_v3_md_region_overflow(dev, sb_reg)) { 131 1 : FTL_ERRLOG(dev, "Buffer overflow\n"); 132 1 : return -EOVERFLOW; 133 : } 134 : } 135 : 136 85 : for (regs_found = 0, n = 0; n < FTL_LAYOUT_REGION_TYPE_MAX_V3; n++) { 137 80 : if (layout->region[n].type == n) { 138 67 : regs_found++; 139 : } 140 : } 141 : 142 5 : if (regs_found != FTL_LAYOUT_REGION_TYPE_MAX_V3) { 143 1 : FTL_ERRLOG(dev, "Missing regions\n"); 144 1 : return -1; 145 : } 146 : 147 4 : return 0; 148 : } 149 : 150 : void 151 0 : ftl_superblock_v3_md_layout_dump(struct spdk_ftl_dev *dev) 152 : { 153 0 : struct ftl_superblock_v3 *sb = (struct ftl_superblock_v3 *)dev->sb; 154 0 : struct ftl_superblock_v3_md_region *sb_reg = &sb->md_layout_head; 155 : 156 0 : FTL_NOTICELOG(dev, "SB metadata layout:\n"); 157 0 : while (sb_reg->type != FTL_LAYOUT_REGION_TYPE_INVALID) { 158 0 : FTL_NOTICELOG(dev, 159 : "Region df:0x%"PRIx64" type:0x%"PRIx32" ver:%"PRIu32" blk_offs:0x%"PRIx64" blk_sz:0x%"PRIx64"\n", 160 : ftl_df_get_obj_id(sb, sb_reg), sb_reg->type, sb_reg->version, sb_reg->blk_offs, sb_reg->blk_sz); 161 : 162 0 : if (sb_reg->df_next == FTL_DF_OBJ_ID_INVALID) { 163 0 : break; 164 : } 165 : 166 0 : sb_reg = ftl_df_get_obj_ptr(sb, sb_reg->df_next); 167 0 : if (ftl_superblock_v3_md_region_overflow(dev, sb_reg)) { 168 0 : FTL_ERRLOG(dev, "Buffer overflow\n"); 169 0 : return; 170 : } 171 : } 172 : }