xref: /spdk/lib/ftl/upgrade/ftl_sb_upgrade.c (revision 42fd001310188f0635a3953f3b0ea0b33a840902)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (C) 2022 Intel Corporation.
3  *   All rights reserved.
4  */
5 
6 #include "ftl_sb_upgrade.h"
7 #include "ftl_layout_upgrade.h"
8 #include "ftl_layout.h"
9 #include "ftl_core.h"
10 #include "ftl_sb_v3.h"
11 #include "utils/ftl_df.h"
12 #include "utils/ftl_layout_tracker_bdev.h"
13 
14 static int
15 sb_v4_to_v5_verify(struct spdk_ftl_dev *dev, struct ftl_layout_region *region)
16 {
17 	struct ftl_layout_region *reg;
18 	uint32_t reg_no;
19 	int rc = ftl_region_upgrade_enabled(dev, region);
20 
21 	if (rc) {
22 		return rc;
23 	}
24 
25 	/* Verify there are no pending major upgrades */
26 	for (reg_no = 0; reg_no < FTL_LAYOUT_REGION_TYPE_MAX; reg_no++) {
27 		reg = ftl_layout_region_get(dev, reg_no);
28 		if (!reg) {
29 			/* This region does not exist */
30 			continue;
31 		}
32 
33 		if (reg->current.version <= ftl_layout_upgrade_region_get_latest_version(reg->type)) {
34 			/* Only latest region version found */
35 			continue;
36 		}
37 
38 		/* Previous version found, major upgrade */
39 		FTL_WARNLOG(dev, "FTL superblock upgrade v4 to v5 disabled: " \
40 			    "cannot upgrade region type 0x%"PRIx32" v%"PRId64" to v%"PRId64", " \
41 			    "offs 0x%"PRIx64", blks 0x%"PRIx64"\n",
42 			    reg->type, reg->current.version, ftl_layout_upgrade_region_get_latest_version(reg->type),
43 			    reg->current.offset, reg->current.blocks);
44 		return -1;
45 	}
46 
47 	return 0;
48 }
49 
50 static bool
51 sb_v3_md_region_is_fixed(int reg_type)
52 {
53 	switch (reg_type) {
54 	case FTL_LAYOUT_REGION_TYPE_SB:
55 	case FTL_LAYOUT_REGION_TYPE_SB_BASE:
56 	case FTL_LAYOUT_REGION_TYPE_DATA_BASE:
57 		return true;
58 
59 	default:
60 		return false;
61 	}
62 }
63 
64 static bool
65 sb_v3_md_region_is_nvc(int reg_type)
66 {
67 	switch (reg_type) {
68 	case FTL_LAYOUT_REGION_TYPE_SB_BASE:
69 	case FTL_LAYOUT_REGION_TYPE_VALID_MAP:
70 	case FTL_LAYOUT_REGION_TYPE_DATA_BASE:
71 		return false;
72 
73 	default:
74 		return true;
75 	}
76 }
77 
78 static int
79 sb_v3_md_layout_convert(struct spdk_ftl_dev *dev)
80 {
81 	struct ftl_superblock_v3 *sb = (struct ftl_superblock_v3 *)dev->sb;
82 	struct ftl_superblock_v3_md_region *sb_reg = &sb->md_layout_head;
83 	const struct ftl_layout_tracker_bdev_region_props *reg_props;
84 
85 	while (sb_reg->type != FTL_LAYOUT_REGION_TYPE_INVALID) {
86 		if (sb_reg->type == FTL_LAYOUT_REGION_TYPE_FREE_NVC ||
87 		    sb_reg->type == FTL_LAYOUT_REGION_TYPE_FREE_BASE) {
88 			goto next_sb_reg;
89 		}
90 
91 		if (sb_reg->type >= FTL_LAYOUT_REGION_TYPE_MAX) {
92 			FTL_ERRLOG(dev, "Invalid MD region type found\n");
93 			return -1;
94 		}
95 
96 		if (sb_v3_md_region_is_fixed(sb_reg->type)) {
97 			FTL_ERRLOG(dev, "Unsupported MD region type found\n");
98 			return -1;
99 		}
100 
101 		if (sb_v3_md_region_is_nvc(sb_reg->type)) {
102 			reg_props = ftl_layout_tracker_bdev_insert_region(dev->nvc_layout_tracker, sb_reg->type,
103 					sb_reg->version, sb_reg->blk_offs, sb_reg->blk_sz);
104 		} else {
105 			reg_props = ftl_layout_tracker_bdev_insert_region(dev->base_layout_tracker, sb_reg->type,
106 					sb_reg->version, sb_reg->blk_offs, sb_reg->blk_sz);
107 		}
108 		if (!reg_props) {
109 			FTL_ERRLOG(dev, "Cannot upgrade SB MD layout - region type 0x%"PRIx32" v%"PRId32" " \
110 				   "offs 0x%"PRIx64" blks 0x%"PRIx64"\n",
111 				   sb_reg->type, sb_reg->version, sb_reg->blk_offs, sb_reg->blk_sz);
112 		}
113 
114 next_sb_reg:
115 		if (sb_reg->df_next == FTL_DF_OBJ_ID_INVALID) {
116 			break;
117 		}
118 
119 		if (UINT64_MAX - (uintptr_t)sb <= sb_reg->df_next) {
120 			FTL_ERRLOG(dev, "Buffer overflow\n");
121 			return -EOVERFLOW;
122 		}
123 
124 		sb_reg = ftl_df_get_obj_ptr(sb, sb_reg->df_next);
125 		if (ftl_superblock_v3_md_region_overflow(dev, sb_reg)) {
126 			FTL_ERRLOG(dev, "Buffer overflow\n");
127 			return -EOVERFLOW;
128 		}
129 	}
130 
131 	return 0;
132 }
133 
134 static int
135 sb_v4_to_v5_upgrade(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx)
136 {
137 	union ftl_superblock_ver *sb = (union ftl_superblock_ver *)dev->sb;
138 
139 	FTL_NOTICELOG(dev, "FTL superblock upgrade v4 to v5\n");
140 
141 	/* Convert v3 MD layout */
142 	if (ftl_superblock_is_blob_area_empty(dev->sb)) {
143 		FTL_ERRLOG(dev, "SBv3 MD layout empty\n");
144 		return -1;
145 	}
146 	if (sb_v3_md_layout_convert(dev)) {
147 		FTL_ERRLOG(dev, "SBv3 MD layout load failed\n");
148 		return -1;
149 	}
150 
151 	/* Bump up the version */
152 	sb->v5.header.version = FTL_SB_VERSION_5;
153 	sb->v5.blob_area_end = 0;
154 
155 	/* Keep v5 layout empty */
156 	memset(sb->v5.nvc_dev_name, 0, sizeof(sb->v5.nvc_dev_name));
157 	memset(&sb->v5.md_layout_nvc, 0, sizeof(sb->v5.md_layout_nvc));
158 	memset(sb->v5.base_dev_name, 0, sizeof(sb->v5.base_dev_name));
159 	memset(&sb->v5.md_layout_base, 0, sizeof(sb->v5.md_layout_base));
160 	memset(&sb->v5.layout_params, 0, sizeof(sb->v5.layout_params));
161 
162 	return 0;
163 }
164 
165 struct ftl_region_upgrade_desc sb_upgrade_desc[] = {
166 	[FTL_SB_VERSION_0] = {.verify = ftl_region_upgrade_disabled},
167 	[FTL_SB_VERSION_1] = {.verify = ftl_region_upgrade_disabled},
168 	[FTL_SB_VERSION_2] = {.verify = ftl_region_upgrade_disabled},
169 	[FTL_SB_VERSION_3] = {.verify = ftl_region_upgrade_disabled},
170 	[FTL_SB_VERSION_4] = {.verify = sb_v4_to_v5_verify, .upgrade = sb_v4_to_v5_upgrade, .new_version = FTL_SB_VERSION_5},
171 };
172 
173 SPDK_STATIC_ASSERT(SPDK_COUNTOF(sb_upgrade_desc) == FTL_SB_VERSION_CURRENT,
174 		   "Missing SB region upgrade descriptors");
175