1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (C) 2022 Intel Corporation. 3 * All rights reserved. 4 */ 5 6 #include "ftl_layout_upgrade.h" 7 #include "ftl_layout.h" 8 #include "ftl_sb_current.h" 9 #include "ftl_sb_prev.h" 10 #include "ftl_core.h" 11 #include "ftl_band.h" 12 13 int 14 ftl_region_upgrade_disabled(struct spdk_ftl_dev *dev, struct ftl_layout_region *region) 15 { 16 return -1; 17 } 18 19 int 20 ftl_region_upgrade_enabled(struct spdk_ftl_dev *dev, struct ftl_layout_region *region) 21 { 22 if (!(dev->sb->clean == 1 && dev->sb_shm->shm_clean == 0)) { 23 FTL_ERRLOG(dev, "FTL region upgrade: SB dirty\n"); 24 return -1; 25 } 26 return 0; 27 } 28 29 #ifndef UTEST 30 extern struct ftl_region_upgrade_desc sb_upgrade_desc[]; 31 extern struct ftl_region_upgrade_desc p2l_upgrade_desc[]; 32 extern struct ftl_region_upgrade_desc nvc_upgrade_desc[]; 33 extern struct ftl_region_upgrade_desc band_upgrade_desc[]; 34 35 static struct ftl_layout_upgrade_desc_list layout_upgrade_desc[] = { 36 [FTL_LAYOUT_REGION_TYPE_SB] = { 37 .count = FTL_SB_VERSION_CURRENT, 38 .desc = sb_upgrade_desc, 39 }, 40 [FTL_LAYOUT_REGION_TYPE_SB_BASE] = { 41 .count = FTL_SB_VERSION_CURRENT, 42 .desc = sb_upgrade_desc, 43 }, 44 [FTL_LAYOUT_REGION_TYPE_L2P] = {}, 45 [FTL_LAYOUT_REGION_TYPE_BAND_MD] = { 46 .count = FTL_BAND_VERSION_CURRENT, 47 .desc = band_upgrade_desc, 48 }, 49 [FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR] = { 50 .count = FTL_BAND_VERSION_CURRENT, 51 .desc = band_upgrade_desc, 52 }, 53 [FTL_LAYOUT_REGION_TYPE_VALID_MAP] = {}, 54 [FTL_LAYOUT_REGION_TYPE_NVC_MD] = { 55 .count = FTL_NVC_VERSION_CURRENT, 56 .desc = nvc_upgrade_desc, 57 }, 58 [FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR] = { 59 .count = FTL_NVC_VERSION_CURRENT, 60 .desc = nvc_upgrade_desc, 61 }, 62 [FTL_LAYOUT_REGION_TYPE_DATA_NVC] = {}, 63 [FTL_LAYOUT_REGION_TYPE_DATA_BASE] = {}, 64 [FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC] = { 65 .count = FTL_P2L_VERSION_CURRENT, 66 .desc = p2l_upgrade_desc, 67 }, 68 [FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC_NEXT] = { 69 .count = FTL_P2L_VERSION_CURRENT, 70 .desc = p2l_upgrade_desc, 71 }, 72 [FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP] = { 73 .count = FTL_P2L_VERSION_CURRENT, 74 .desc = p2l_upgrade_desc, 75 }, 76 [FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP_NEXT] = { 77 .count = FTL_P2L_VERSION_CURRENT, 78 .desc = p2l_upgrade_desc, 79 }, 80 [FTL_LAYOUT_REGION_TYPE_TRIM_MD] = {}, 81 [FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR] = {}, 82 #ifdef SPDK_FTL_VSS_EMU 83 [FTL_LAYOUT_REGION_TYPE_VSS] = {}, 84 #endif 85 }; 86 87 SPDK_STATIC_ASSERT(sizeof(layout_upgrade_desc) / sizeof(*layout_upgrade_desc) == 88 FTL_LAYOUT_REGION_TYPE_MAX, 89 "Missing layout upgrade descriptors"); 90 #endif 91 92 static int 93 region_verify(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx) 94 { 95 uint64_t ver; 96 97 assert(ctx->reg); 98 assert(ctx->reg->current.version == ctx->upgrade->count); 99 ver = ctx->reg->prev.version; 100 if (ver > ctx->upgrade->count) { 101 FTL_ERRLOG(dev, "Unknown region version\n"); 102 return -1; 103 } 104 105 while (ver < ctx->reg->current.version) { 106 int rc = ctx->upgrade->desc[ver].verify(dev, ctx->reg); 107 if (rc) { 108 return rc; 109 } 110 ver = ctx->upgrade->desc[ver].new_version; 111 } 112 return 0; 113 } 114 115 int 116 ftl_region_upgrade(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx) 117 { 118 int rc = 0; 119 uint64_t ver; 120 121 assert(ctx->reg); 122 assert(ctx->reg->prev.version <= ctx->reg->current.version); 123 assert(ctx->reg->current.version == ctx->upgrade->count); 124 ver = ctx->reg->prev.version; 125 if (ver < ctx->upgrade->count) { 126 ctx->next_reg_ver = ctx->upgrade->desc[ver].new_version; 127 rc = ctx->upgrade->desc[ver].upgrade(dev, ctx); 128 } 129 return rc; 130 } 131 132 void 133 ftl_region_upgrade_completed(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx, 134 int status) 135 { 136 assert(ctx->reg); 137 assert(ctx->reg->prev.version < ctx->next_reg_ver); 138 assert(ctx->next_reg_ver <= ctx->reg->current.version); 139 140 /* SB MD isn't tracked in SB MD region list */ 141 if (!status) { 142 if (ctx->reg->prev.sb_md_reg) { 143 int rc = ftl_superblock_md_layout_upgrade_region(dev, ctx->reg->prev.sb_md_reg, ctx->next_reg_ver); 144 ftl_bug(rc != 0); 145 } 146 147 ctx->reg->prev.version = ctx->next_reg_ver; 148 } 149 150 if (ctx->cb) { 151 ctx->cb(dev, ctx->cb_ctx, status); 152 } 153 } 154 155 int 156 ftl_layout_verify(struct spdk_ftl_dev *dev) 157 { 158 int rc = 0; 159 struct ftl_layout *layout = &dev->layout; 160 struct ftl_layout_upgrade_ctx ctx = {0}; 161 162 if (ftl_superblock_md_layout_is_empty(dev->sb)) { 163 rc = ftl_superblock_md_layout_build(dev); 164 goto exit; 165 } 166 167 if (ftl_superblock_md_layout_load_all(dev)) { 168 return -1; 169 } 170 171 if (ftl_validate_regions(dev, layout)) { 172 return -1; 173 } 174 175 ctx.reg = &dev->layout.region[0]; 176 ctx.upgrade = &layout_upgrade_desc[0]; 177 178 while (true) { 179 if (region_verify(dev, &ctx)) { 180 return -1; 181 } 182 183 if (ctx.reg->type == FTL_LAYOUT_REGION_TYPE_MAX - 1) { 184 break; 185 } 186 187 ctx.reg++; 188 ctx.upgrade++; 189 } 190 191 exit: 192 return rc; 193 } 194 195 int 196 ftl_upgrade_layout_dump(struct spdk_ftl_dev *dev) 197 { 198 if (ftl_validate_regions(dev, &dev->layout)) { 199 return -1; 200 } 201 202 ftl_layout_dump(dev); 203 ftl_superblock_md_layout_dump(dev); 204 return 0; 205 } 206 207 int 208 ftl_superblock_upgrade(struct spdk_ftl_dev *dev) 209 { 210 struct ftl_layout_upgrade_ctx ctx = {0}; 211 struct ftl_layout_region *reg = &dev->layout.region[FTL_LAYOUT_REGION_TYPE_SB]; 212 int rc; 213 214 ctx.reg = reg; 215 ctx.upgrade = &layout_upgrade_desc[FTL_LAYOUT_REGION_TYPE_SB]; 216 reg->prev.version = dev->sb->header.version; 217 218 rc = region_verify(dev, &ctx); 219 if (rc) { 220 return rc; 221 } 222 223 while (reg->prev.version < reg->current.version) { 224 rc = ftl_region_upgrade(dev, &ctx); 225 if (rc) { 226 return rc; 227 } 228 /* SB upgrades are all synchronous */ 229 ftl_region_upgrade_completed(dev, &ctx, rc); 230 } 231 232 dev->layout.region[FTL_LAYOUT_REGION_TYPE_SB_BASE].prev.version = reg->prev.version; 233 return 0; 234 } 235 236 static int 237 layout_upgrade_select_next_region(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx) 238 { 239 struct ftl_layout_region *reg; 240 uint64_t reg_ver; 241 uint32_t reg_type = ctx->reg->type; 242 243 while (reg_type != FTL_LAYOUT_REGION_TYPE_MAX) { 244 assert(ctx->reg); 245 assert(ctx->upgrade); 246 reg = ctx->reg; 247 reg_ver = reg->prev.version; 248 249 if (reg_ver < reg->current.version) { 250 /* qualify region version to upgrade */ 251 return FTL_LAYOUT_UPGRADE_CONTINUE; 252 } else if (reg_ver == reg->current.version) { 253 /* select the next region to upgrade */ 254 reg_type++; 255 if (reg_type == FTL_LAYOUT_REGION_TYPE_MAX) { 256 break; 257 } 258 ctx->reg++; 259 ctx->upgrade++; 260 } else { 261 /* unknown version */ 262 assert(reg_ver > reg->current.version); 263 FTL_ERRLOG(dev, "Region %d upgrade fault: version %"PRIu64"/%"PRIu64"\n", reg_type, reg_ver, 264 reg->current.version); 265 return FTL_LAYOUT_UPGRADE_FAULT; 266 } 267 } 268 269 return FTL_LAYOUT_UPGRADE_DONE; 270 } 271 272 int 273 ftl_layout_upgrade_init_ctx(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx) 274 { 275 if (!ctx->reg) { 276 ctx->reg = &dev->layout.region[0]; 277 ctx->upgrade = &layout_upgrade_desc[0]; 278 } 279 280 return layout_upgrade_select_next_region(dev, ctx); 281 } 282