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 ftl_superblock_v3_check_magic(union ftl_superblock_ver *sb_ver) 14 { 15 return sb_ver->header.magic == FTL_SUPERBLOCK_MAGIC; 16 } 17 18 bool 19 ftl_superblock_v3_md_layout_is_empty(union ftl_superblock_ver *sb_ver) 20 { 21 return sb_ver->v3.md_layout_head.type == FTL_LAYOUT_REGION_TYPE_INVALID; 22 } 23 24 static bool 25 md_region_is_fixed(int reg_type) 26 { 27 switch (reg_type) { 28 case FTL_LAYOUT_REGION_TYPE_SB: 29 case FTL_LAYOUT_REGION_TYPE_SB_BASE: 30 case FTL_LAYOUT_REGION_TYPE_DATA_BASE: 31 return true; 32 33 default: 34 return false; 35 } 36 } 37 38 bool 39 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 if ((uintptr_t)sb_reg < (uintptr_t)dev->sb) { 44 return true; 45 } 46 47 /* Make sure the entry doesn't overflow the pointer value (probably overkill to check) */ 48 if (UINT64_MAX - (uintptr_t)sb_reg <= sizeof(*sb_reg)) { 49 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 if ((uintptr_t)(sb_reg + 1) > ((uintptr_t)(dev->sb) + FTL_SUPERBLOCK_SIZE)) { 54 return true; 55 } 56 57 return false; 58 } 59 60 int 61 ftl_superblock_v3_md_layout_load_all(struct spdk_ftl_dev *dev) 62 { 63 struct ftl_superblock_v3 *sb = (struct ftl_superblock_v3 *)dev->sb; 64 struct ftl_superblock_v3_md_region *sb_reg = &sb->md_layout_head; 65 struct ftl_layout *layout = &dev->layout; 66 uint32_t regs_found; 67 uint32_t n; 68 ftl_df_obj_id df_sentinel = FTL_DF_OBJ_ID_INVALID; 69 ftl_df_obj_id df_prev = ftl_df_get_obj_id(sb, sb_reg); 70 71 for (n = 0; n < FTL_LAYOUT_REGION_TYPE_MAX_V3; n++) { 72 if (md_region_is_fixed(n)) { 73 continue; 74 } 75 layout->region[n].type = FTL_LAYOUT_REGION_TYPE_INVALID; 76 } 77 78 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 if (sb_reg->type == FTL_LAYOUT_REGION_TYPE_FREE_NVC || 83 sb_reg->type == FTL_LAYOUT_REGION_TYPE_FREE_BASE) { 84 goto next_sb_reg; 85 } 86 87 if (sb_reg->type >= FTL_LAYOUT_REGION_TYPE_MAX_V3) { 88 FTL_ERRLOG(dev, "Invalid MD region type found\n"); 89 return -1; 90 } 91 92 if (md_region_is_fixed(sb_reg->type)) { 93 FTL_ERRLOG(dev, "Unsupported MD region type found\n"); 94 return -1; 95 } 96 97 reg = &layout->region[sb_reg->type]; 98 /* Find the oldest region version */ 99 if (reg->type == FTL_LAYOUT_REGION_TYPE_INVALID || sb_reg->version < reg->current.version) { 100 reg->type = sb_reg->type; 101 reg->current.offset = sb_reg->blk_offs; 102 reg->current.blocks = sb_reg->blk_sz; 103 reg->current.version = sb_reg->version; 104 } else if (sb_reg->version == reg->current.version) { 105 FTL_ERRLOG(dev, "Multiple/looping regions found\n"); 106 return -EAGAIN; 107 } 108 109 next_sb_reg: 110 if (sb_reg->df_next == FTL_DF_OBJ_ID_INVALID) { 111 break; 112 } 113 114 if (UINT64_MAX - (uintptr_t)sb <= sb_reg->df_next) { 115 FTL_ERRLOG(dev, "Buffer overflow\n"); 116 return -EOVERFLOW; 117 } 118 119 if (sb_reg->df_next <= df_prev) { 120 df_sentinel = df_prev; 121 } 122 df_prev = sb_reg->df_next; 123 124 if (df_sentinel != FTL_DF_OBJ_ID_INVALID && sb_reg->df_next == df_sentinel) { 125 FTL_ERRLOG(dev, "Looping regions found\n"); 126 return -ELOOP; 127 } 128 129 sb_reg = ftl_df_get_obj_ptr(sb, sb_reg->df_next); 130 if (ftl_superblock_v3_md_region_overflow(dev, sb_reg)) { 131 FTL_ERRLOG(dev, "Buffer overflow\n"); 132 return -EOVERFLOW; 133 } 134 } 135 136 for (regs_found = 0, n = 0; n < FTL_LAYOUT_REGION_TYPE_MAX_V3; n++) { 137 if (layout->region[n].type == n) { 138 regs_found++; 139 } 140 } 141 142 if (regs_found != FTL_LAYOUT_REGION_TYPE_MAX_V3) { 143 FTL_ERRLOG(dev, "Missing regions\n"); 144 return -1; 145 } 146 147 return 0; 148 } 149 150 void 151 ftl_superblock_v3_md_layout_dump(struct spdk_ftl_dev *dev) 152 { 153 struct ftl_superblock_v3 *sb = (struct ftl_superblock_v3 *)dev->sb; 154 struct ftl_superblock_v3_md_region *sb_reg = &sb->md_layout_head; 155 156 FTL_NOTICELOG(dev, "SB metadata layout:\n"); 157 while (sb_reg->type != FTL_LAYOUT_REGION_TYPE_INVALID) { 158 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 if (sb_reg->df_next == FTL_DF_OBJ_ID_INVALID) { 163 break; 164 } 165 166 sb_reg = ftl_df_get_obj_ptr(sb, sb_reg->df_next); 167 if (ftl_superblock_v3_md_region_overflow(dev, sb_reg)) { 168 FTL_ERRLOG(dev, "Buffer overflow\n"); 169 return; 170 } 171 } 172 } 173