Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright 2023 Solidigm All Rights Reserved
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include "spdk/string.h"
7 : :
8 : : #include "ftl_sb_v5.h"
9 : : #include "ftl_core.h"
10 : : #include "ftl_layout.h"
11 : : #include "ftl_band.h"
12 : : #include "upgrade/ftl_sb_prev.h"
13 : : #include "upgrade/ftl_sb_upgrade.h"
14 : : #include "upgrade/ftl_layout_upgrade.h"
15 : : #include "utils/ftl_layout_tracker_bdev.h"
16 : :
17 : : typedef size_t (*blob_store_fn)(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_buf_sz);
18 : : typedef int (*blob_load_fn)(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_sz);
19 : :
20 : : bool
21 : 33 : ftl_superblock_v5_is_blob_area_empty(union ftl_superblock_ver *sb_ver)
22 : : {
23 [ # # # # : 33 : return sb_ver->v5.blob_area_end == 0;
# # ]
24 : : }
25 : :
26 : : static bool
27 : 63 : validate_blob_area(struct ftl_superblock_v5_md_blob_hdr *sb_blob_hdr,
28 : : ftl_df_obj_id sb_blob_area_end)
29 : : {
30 [ + - # # : 126 : return sb_blob_hdr->df_id <= sb_blob_area_end &&
# # ]
31 [ + - # # : 63 : (sb_blob_hdr->df_id + sb_blob_hdr->blob_sz) <= sb_blob_area_end;
# # # # ]
32 : : }
33 : :
34 : : bool
35 : 21 : ftl_superblock_v5_validate_blob_area(struct spdk_ftl_dev *dev)
36 : : {
37 [ # # # # ]: 21 : union ftl_superblock_ver *sb_ver = (union ftl_superblock_ver *)dev->sb;
38 : :
39 [ + - # # : 42 : return validate_blob_area(&sb_ver->v5.md_layout_nvc, sb_ver->v5.blob_area_end) &&
# # # # #
# # # ]
40 [ + - + - : 42 : validate_blob_area(&sb_ver->v5.md_layout_base, sb_ver->v5.blob_area_end) &&
# # # # #
# # # ]
41 [ # # # # : 21 : validate_blob_area(&sb_ver->v5.layout_params, sb_ver->v5.blob_area_end);
# # # # #
# ]
42 : : }
43 : :
44 : : static size_t
45 : 99 : sb_blob_store(struct spdk_ftl_dev *dev, struct ftl_superblock_v5_md_blob_hdr *sb_blob_hdr,
46 : : blob_store_fn blob_store, void *sb_blob_area)
47 : : {
48 [ # # # # ]: 99 : struct ftl_superblock_v5 *sb = (struct ftl_superblock_v5 *)dev->sb;
49 [ # # ]: 99 : uintptr_t sb_end = ((uintptr_t)sb) + FTL_SUPERBLOCK_SIZE;
50 : 99 : size_t blob_sz = sb_end - (uintptr_t)sb_blob_area;
51 : :
52 : : /* Test SB blob area overflow */
53 [ - + # # ]: 99 : if ((uintptr_t)sb_blob_area < (uintptr_t)sb->blob_area) {
54 [ # # ]: 0 : ftl_bug(true);
55 : 0 : return 0;
56 : : }
57 [ - + ]: 99 : if ((uintptr_t)sb_blob_area >= sb_end) {
58 [ # # ]: 0 : ftl_bug(true);
59 : 0 : return 0;
60 : : }
61 : :
62 [ # # # # ]: 99 : blob_sz = blob_store(dev, sb_blob_area, blob_sz);
63 [ # # # # ]: 99 : sb_blob_hdr->blob_sz = blob_sz;
64 [ # # # # : 99 : sb_blob_hdr->df_id = ftl_df_get_obj_id(sb->blob_area, sb_blob_area);
# # ]
65 : 99 : return blob_sz;
66 : 0 : }
67 : :
68 : : static size_t
69 : 33 : base_blob_store(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_buf_sz)
70 : : {
71 [ # # # # ]: 33 : return ftl_layout_tracker_bdev_blob_store(dev->base_layout_tracker, blob_buf, blob_buf_sz);
72 : : }
73 : :
74 : : static size_t
75 : 33 : nvc_blob_store(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_buf_sz)
76 : : {
77 [ # # # # ]: 33 : return ftl_layout_tracker_bdev_blob_store(dev->nvc_layout_tracker, blob_buf, blob_buf_sz);
78 : : }
79 : :
80 : : int
81 : 33 : ftl_superblock_v5_store_blob_area(struct spdk_ftl_dev *dev)
82 : : {
83 [ # # # # ]: 33 : struct ftl_superblock_v5 *sb = (struct ftl_superblock_v5 *)dev->sb;
84 : : void *sb_blob_area;
85 : : size_t blob_sz;
86 : :
87 : : /* Store the NVC-backed FTL MD layout info */
88 [ # # ]: 33 : sb_blob_area = ftl_df_get_obj_ptr(sb->blob_area, 0);
89 [ # # # # : 33 : spdk_strcpy_pad(sb->nvc_dev_name, dev->nv_cache.nvc_type->name,
# # # # #
# # # ]
90 : : SPDK_COUNTOF(sb->nvc_dev_name), '\0');
91 [ # # ]: 33 : blob_sz = sb_blob_store(dev, &sb->md_layout_nvc, nvc_blob_store, sb_blob_area);
92 [ + - # # : 33 : FTL_NOTICELOG(dev, "nvc layout blob store 0x%"PRIx64" bytes\n", blob_sz);
# # # # ]
93 [ - + ]: 33 : if (!blob_sz) {
94 : 0 : return -1;
95 : : }
96 : :
97 : : /* Store the base dev-backed FTL MD layout info */
98 : 33 : sb_blob_area += blob_sz;
99 [ # # # # : 33 : spdk_strcpy_pad(sb->base_dev_name, dev->base_type->name, SPDK_COUNTOF(sb->base_dev_name), '\0');
# # # # #
# ]
100 [ # # ]: 33 : blob_sz = sb_blob_store(dev, &sb->md_layout_base, base_blob_store, sb_blob_area);
101 [ + - # # : 33 : FTL_NOTICELOG(dev, "base layout blob store 0x%"PRIx64" bytes\n", blob_sz);
# # # # ]
102 [ - + ]: 33 : if (!blob_sz) {
103 : 0 : return -1;
104 : : }
105 : :
106 : : /* Store the region props */
107 : 33 : sb_blob_area += blob_sz;
108 [ # # ]: 33 : blob_sz = sb_blob_store(dev, &sb->layout_params, ftl_layout_blob_store, sb_blob_area);
109 [ + - # # : 33 : FTL_NOTICELOG(dev, "layout blob store 0x%"PRIx64" bytes\n", blob_sz);
# # # # ]
110 [ - + ]: 33 : if (!blob_sz) {
111 : 0 : return -1;
112 : : }
113 : :
114 : : /* Update the blob area end */
115 : 33 : sb_blob_area += blob_sz;
116 [ # # # # : 33 : sb->blob_area_end = ftl_df_get_obj_id(sb->blob_area, sb_blob_area);
# # ]
117 : :
118 : 33 : return 0;
119 : 0 : }
120 : :
121 : : static const struct ftl_layout_tracker_bdev_region_props *
122 : 42 : sb_md_layout_find_oldest_region(struct spdk_ftl_dev *dev,
123 : : struct ftl_layout_tracker_bdev *layout_tracker,
124 : : enum ftl_layout_region_type reg_type, void *find_filter)
125 : : {
126 : 42 : const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL;
127 : 42 : const struct ftl_layout_tracker_bdev_region_props *reg_oldest = NULL;
128 : : uint32_t ver_oldest;
129 : :
130 : 0 : while (true) {
131 : 72 : ftl_layout_tracker_bdev_find_next_region(layout_tracker, reg_type, ®_search_ctx);
132 [ + + ]: 72 : if (!reg_search_ctx) {
133 : 42 : break;
134 : : }
135 : :
136 [ + + ]: 30 : if (!reg_oldest) {
137 : 21 : reg_oldest = reg_search_ctx;
138 [ # # # # ]: 21 : ver_oldest = reg_search_ctx->ver;
139 : 21 : continue;
140 : : }
141 : :
142 [ - + # # : 9 : ftl_bug(ver_oldest == reg_search_ctx->ver);
# # # # ]
143 [ + + # # : 9 : if (ver_oldest > reg_search_ctx->ver) {
# # ]
144 : 3 : reg_oldest = reg_search_ctx;
145 [ # # # # ]: 3 : ver_oldest = reg_search_ctx->ver;
146 : 0 : }
147 : : }
148 : :
149 : 42 : return reg_oldest;
150 : : }
151 : :
152 : : static const struct ftl_layout_tracker_bdev_region_props *
153 : 30 : sb_md_layout_find_latest_region(struct spdk_ftl_dev *dev,
154 : : struct ftl_layout_tracker_bdev *layout_tracker, enum ftl_layout_region_type reg_type,
155 : : void *find_filter)
156 : : {
157 : 30 : const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL;
158 : 30 : const struct ftl_layout_tracker_bdev_region_props *reg_latest = NULL;
159 : : uint32_t ver_latest;
160 : :
161 : 0 : while (true) {
162 : 51 : ftl_layout_tracker_bdev_find_next_region(layout_tracker, reg_type, ®_search_ctx);
163 [ + + ]: 51 : if (!reg_search_ctx) {
164 : 30 : break;
165 : : }
166 : :
167 [ + + ]: 21 : if (!reg_latest) {
168 : 15 : reg_latest = reg_search_ctx;
169 [ # # # # ]: 15 : ver_latest = reg_search_ctx->ver;
170 : 15 : continue;
171 : : }
172 : :
173 [ - + # # : 6 : ftl_bug(ver_latest == reg_search_ctx->ver);
# # # # ]
174 [ + + # # : 6 : if (ver_latest < reg_search_ctx->ver) {
# # ]
175 : 3 : reg_latest = reg_search_ctx;
176 [ # # # # ]: 3 : ver_latest = reg_search_ctx->ver;
177 : 0 : }
178 : : }
179 : :
180 : 30 : return reg_latest;
181 : : }
182 : :
183 : : static const struct ftl_layout_tracker_bdev_region_props *
184 : 24 : sb_md_layout_find_region_version(struct spdk_ftl_dev *dev,
185 : : struct ftl_layout_tracker_bdev *layout_tracker, enum ftl_layout_region_type reg_type,
186 : : void *find_filter)
187 : : {
188 : 24 : const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL;
189 : 24 : uint32_t *reg_ver = find_filter;
190 : :
191 [ + + # # ]: 24 : assert(reg_ver);
192 : :
193 : 0 : while (true) {
194 : 36 : ftl_layout_tracker_bdev_find_next_region(layout_tracker, reg_type, ®_search_ctx);
195 [ + + ]: 36 : if (!reg_search_ctx) {
196 : 18 : break;
197 : : }
198 : :
199 [ + + # # : 18 : if (reg_search_ctx->ver == *reg_ver) {
# # # # ]
200 : 6 : break;
201 : : }
202 : : }
203 : :
204 : 24 : return reg_search_ctx;
205 : : }
206 : :
207 : : typedef const struct ftl_layout_tracker_bdev_region_props *(*sb_md_layout_find_fn)(
208 : : struct spdk_ftl_dev *dev, struct ftl_layout_tracker_bdev *layout_tracker,
209 : : enum ftl_layout_region_type reg_type, void *find_filter);
210 : :
211 : : static const struct ftl_layout_tracker_bdev_region_props *
212 : 48 : sb_md_layout_find_region(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type,
213 : : sb_md_layout_find_fn find_fn, void *find_filter)
214 : : {
215 : : const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx;
216 [ # # # # ]: 48 : struct ftl_layout_tracker_bdev *nvc_layout_tracker = dev->nvc_layout_tracker;
217 [ # # # # ]: 48 : struct ftl_layout_tracker_bdev *base_layout_tracker = dev->base_layout_tracker;
218 : :
219 [ # # # # ]: 48 : reg_search_ctx = find_fn(dev, nvc_layout_tracker, reg_type, find_filter);
220 [ + + ]: 48 : if (reg_search_ctx) {
221 [ - + # # : 42 : assert(find_fn(dev, base_layout_tracker, reg_type, find_filter) == NULL);
# # # # ]
222 : 42 : return reg_search_ctx;
223 : : }
224 : :
225 [ # # # # ]: 6 : reg_search_ctx = find_fn(dev, base_layout_tracker, reg_type, find_filter);
226 : 6 : return reg_search_ctx;
227 : 0 : }
228 : :
229 : : static int
230 : 150 : sb_blob_load(struct spdk_ftl_dev *dev, struct ftl_superblock_v5_md_blob_hdr *sb_blob_hdr,
231 : : blob_load_fn blob_load)
232 : : {
233 [ # # # # ]: 150 : struct ftl_superblock_v5 *sb = (struct ftl_superblock_v5 *)dev->sb;
234 [ # # ]: 150 : uintptr_t sb_end = ((uintptr_t)sb) + FTL_SUPERBLOCK_SIZE;
235 : : void *blob_area;
236 : :
237 [ + + # # : 150 : if (sb_blob_hdr->df_id == FTL_DF_OBJ_ID_INVALID) {
# # ]
238 : : /* Uninitialized blob */
239 : 6 : return -1;
240 : : }
241 : :
242 [ # # # # : 144 : blob_area = ftl_df_get_obj_ptr(sb->blob_area, sb_blob_hdr->df_id);
# # ]
243 : :
244 : : /* Test SB blob area overflow */
245 [ - + # # ]: 144 : if ((uintptr_t)blob_area < (uintptr_t)sb->blob_area) {
246 [ # # ]: 0 : ftl_bug(true);
247 : 0 : return -1;
248 : : }
249 [ - + # # : 144 : if ((uintptr_t)blob_area + sb_blob_hdr->blob_sz >= sb_end) {
# # ]
250 [ # # ]: 0 : ftl_bug(true);
251 : 0 : return -1;
252 : : }
253 : :
254 [ # # # # : 144 : return blob_load(dev, blob_area, sb_blob_hdr->blob_sz);
# # # # ]
255 : 0 : }
256 : :
257 : : static int
258 : 45 : base_blob_load(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_sz)
259 : : {
260 [ # # # # ]: 45 : return ftl_layout_tracker_bdev_blob_load(dev->base_layout_tracker, blob_buf, blob_sz);
261 : : }
262 : :
263 : : static int
264 : 57 : nvc_blob_load(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_sz)
265 : : {
266 [ # # # # ]: 57 : return ftl_layout_tracker_bdev_blob_load(dev->nvc_layout_tracker, blob_buf, blob_sz);
267 : : }
268 : :
269 : : int
270 : 63 : ftl_superblock_v5_load_blob_area(struct spdk_ftl_dev *dev)
271 : : {
272 [ # # # # ]: 63 : struct ftl_superblock_v5 *sb = (struct ftl_superblock_v5 *)dev->sb;
273 : :
274 : : /* Load the NVC-backed FTL MD layout info */
275 [ - + - + : 63 : if (strncmp(sb->nvc_dev_name, dev->nv_cache.nvc_type->name, SPDK_COUNTOF(sb->nvc_dev_name))) {
- + # # #
# # # # #
# # # # ]
276 : 0 : return -1;
277 : : }
278 [ + - # # : 63 : FTL_NOTICELOG(dev, "nvc layout blob load 0x%"PRIx64" bytes\n", (uint64_t)sb->md_layout_nvc.blob_sz);
# # # # #
# # # #
# ]
279 [ + + # # ]: 63 : if (sb_blob_load(dev, &sb->md_layout_nvc, nvc_blob_load)) {
280 : 18 : return -1;
281 : : }
282 : :
283 : : /* Load the base dev-backed FTL MD layout info */
284 [ - + - + : 45 : if (strncmp(sb->base_dev_name, dev->base_type->name, SPDK_COUNTOF(sb->base_dev_name))) {
- + # # #
# # # # #
# # ]
285 : 0 : return -1;
286 : : }
287 [ + - # # : 45 : FTL_NOTICELOG(dev, "base layout blob load 0x%"PRIx64" bytes\n",
# # # # #
# # # #
# ]
288 : : (uint64_t)sb->md_layout_base.blob_sz);
289 [ + + # # ]: 45 : if (sb_blob_load(dev, &sb->md_layout_base, base_blob_load)) {
290 : 3 : return -1;
291 : : }
292 : :
293 : : /* Load the region props */
294 [ + - # # : 42 : FTL_NOTICELOG(dev, "layout blob load 0x%"PRIx64" bytes\n", (uint64_t)sb->layout_params.blob_sz);
# # # # #
# # # #
# ]
295 [ + + # # ]: 42 : if (sb_blob_load(dev, &sb->layout_params, ftl_layout_blob_load)) {
296 : 3 : return -1;
297 : : }
298 : :
299 : 39 : return 0;
300 : 0 : }
301 : :
302 : : static struct ftl_layout_tracker_bdev *
303 : 9 : sb_get_md_layout_tracker(struct spdk_ftl_dev *dev, struct ftl_layout_region *reg)
304 : : {
305 [ - + # # : 9 : return (reg->bdev_desc == dev->base_bdev_desc) ? dev->base_layout_tracker : dev->nvc_layout_tracker;
# # # # #
# # # # #
# # # # ]
306 : : }
307 : :
308 : : static void
309 : 3 : sb_md_layout_delete_prev_region(struct spdk_ftl_dev *dev, struct ftl_layout_region *reg)
310 : : {
311 : : int rc;
312 : 3 : struct ftl_layout_tracker_bdev *layout_tracker = sb_get_md_layout_tracker(dev, reg);
313 : :
314 [ # # # # : 3 : rc = ftl_layout_tracker_bdev_rm_region(layout_tracker, reg->type, reg->current.version);
# # # # #
# ]
315 : : /* Version 0 indicates a placeholder for creation of a new region */
316 [ + - - + : 3 : ftl_bug(reg->current.version != 0 && rc != 0);
# # # # #
# # # ]
317 : 3 : }
318 : :
319 : : static void
320 : 6 : sb_md_layout_update_prev_region(struct spdk_ftl_dev *dev, struct ftl_layout_region *reg,
321 : : uint32_t new_version)
322 : : {
323 : : int rc;
324 : 6 : const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL;
325 : 6 : struct ftl_layout_tracker_bdev *layout_tracker = sb_get_md_layout_tracker(dev, reg);
326 : : struct ftl_layout_tracker_bdev_region_props reg_props;
327 : :
328 : : /* Get region properties */
329 [ # # # # ]: 6 : ftl_layout_tracker_bdev_find_next_region(layout_tracker, reg->type, ®_search_ctx);
330 [ - + # # ]: 6 : ftl_bug(reg_search_ctx == NULL);
331 : 6 : reg_props = *reg_search_ctx;
332 : :
333 : : /* Delete the region */
334 [ # # ]: 6 : rc = ftl_layout_tracker_bdev_rm_region(layout_tracker, reg_props.type, reg_props.ver);
335 [ - + # # ]: 6 : ftl_bug(rc != 0);
336 : :
337 : : /* Insert the same region with new version */
338 : 6 : reg_search_ctx = ftl_layout_tracker_bdev_insert_region(layout_tracker, reg_props.type, new_version,
339 [ # # # # ]: 0 : reg_props.blk_offs, reg_props.blk_sz);
340 [ - + # # ]: 6 : ftl_bug(reg_search_ctx == NULL);
341 : :
342 : : /* Verify the oldest region version stored in the SB is the new_version */
343 : 6 : reg_search_ctx = sb_md_layout_find_region(dev, reg_props.type, sb_md_layout_find_oldest_region,
344 : : NULL);
345 [ - + # # ]: 6 : ftl_bug(reg_search_ctx == NULL);
346 [ - + # # : 6 : ftl_bug(reg_search_ctx->ver != new_version);
# # # # ]
347 : 6 : }
348 : :
349 : : int
350 : 9 : ftl_superblock_v5_md_layout_upgrade_region(struct spdk_ftl_dev *dev, struct ftl_layout_region *reg,
351 : : uint32_t new_version)
352 : : {
353 : 9 : const struct ftl_layout_tracker_bdev_region_props *reg_next = NULL;
354 : : uint64_t latest_ver;
355 : :
356 [ - + # # : 9 : ftl_bug(reg->current.version >= new_version);
# # # # #
# ]
357 : :
358 [ # # # # ]: 9 : reg_next = sb_md_layout_find_region(dev, reg->type, sb_md_layout_find_region_version, &new_version);
359 [ + + ]: 9 : if (reg_next) {
360 : : /**
361 : : * Major upgrade.
362 : : * Found a new MD region allocated for upgrade to the next version.
363 : : * Destroy the previous version now that the upgrade is completed.
364 : : */
365 [ - + # # : 3 : ftl_bug(reg_next->ver != new_version);
# # # # ]
366 [ - + # # : 3 : ftl_bug(reg_next->type != reg->type);
# # # # #
# # # ]
367 : 3 : sb_md_layout_delete_prev_region(dev, reg);
368 [ # # # # : 3 : reg->current.offset = reg_next->blk_offs;
# # # # #
# ]
369 [ # # # # : 3 : reg->current.blocks = reg_next->blk_sz;
# # # # #
# ]
370 : 0 : } else {
371 : : /**
372 : : * Minor upgrade.
373 : : * Upgraded the MD region in place.
374 : : * Update the version in place.
375 : : */
376 : 6 : sb_md_layout_update_prev_region(dev, reg, new_version);
377 : : }
378 : :
379 [ # # # # : 9 : reg->current.version = new_version;
# # ]
380 [ # # # # ]: 9 : latest_ver = ftl_layout_upgrade_region_get_latest_version(reg->type);
381 [ + + ]: 9 : if (new_version == latest_ver) {
382 : : /* Audit the only region version stored in the SB */
383 [ # # # # ]: 3 : reg_next = sb_md_layout_find_region(dev, reg->type, sb_md_layout_find_latest_region, NULL);
384 [ - + # # ]: 3 : ftl_bug(reg_next == NULL);
385 [ - + # # : 3 : ftl_bug(reg_next->ver != new_version);
# # # # ]
386 : :
387 [ # # # # ]: 3 : reg_next = sb_md_layout_find_region(dev, reg->type, sb_md_layout_find_oldest_region, NULL);
388 [ - + # # ]: 3 : ftl_bug(reg_next == NULL);
389 [ - + # # : 3 : ftl_bug(reg_next->ver != new_version);
# # # # ]
390 : :
391 [ # # # # ]: 3 : reg_next = sb_md_layout_find_region(dev, reg->type, sb_md_layout_find_region_version, &new_version);
392 [ - + # # : 3 : ftl_bug(reg->type != reg_next->type);
# # # # #
# # # ]
393 [ - + # # : 3 : ftl_bug(reg->current.version != reg_next->ver);
# # # # #
# # # #
# ]
394 [ - + # # : 3 : ftl_bug(reg->current.offset != reg_next->blk_offs);
# # # # #
# # # #
# ]
395 [ - + # # : 3 : ftl_bug(reg->current.blocks != reg_next->blk_sz);
# # # # #
# # # #
# ]
396 : 0 : }
397 : :
398 : 9 : return 0;
399 : : }
400 : :
401 : : void
402 : 27 : ftl_superblock_v5_md_layout_dump(struct spdk_ftl_dev *dev)
403 : : {
404 [ # # # # ]: 27 : struct ftl_layout_tracker_bdev *nvc_layout_tracker = dev->nvc_layout_tracker;
405 [ # # # # ]: 27 : struct ftl_layout_tracker_bdev *base_layout_tracker = dev->base_layout_tracker;
406 : 27 : const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL;
407 : :
408 [ + - # # : 27 : FTL_NOTICELOG(dev, "SB metadata layout - nvc:\n");
# # # # ]
409 : 0 : while (true) {
410 : 432 : ftl_layout_tracker_bdev_find_next_region(nvc_layout_tracker, FTL_LAYOUT_REGION_TYPE_INVALID,
411 : : ®_search_ctx);
412 [ + + ]: 432 : if (!reg_search_ctx) {
413 : 27 : break;
414 : : }
415 : :
416 [ + - # # : 405 : FTL_NOTICELOG(dev,
# # # # #
# # # # #
# # # # #
# # # #
# ]
417 : : "Region type:0x%"PRIx32" ver:%"PRIu32" blk_offs:0x%"PRIx64" blk_sz:0x%"PRIx64"\n",
418 : : reg_search_ctx->type, reg_search_ctx->ver, reg_search_ctx->blk_offs, reg_search_ctx->blk_sz);
419 : : }
420 : :
421 : 27 : reg_search_ctx = NULL;
422 [ + - # # : 27 : FTL_NOTICELOG(dev, "SB metadata layout - base dev:\n");
# # # # ]
423 : 0 : while (true) {
424 : 162 : ftl_layout_tracker_bdev_find_next_region(base_layout_tracker, FTL_LAYOUT_REGION_TYPE_INVALID,
425 : : ®_search_ctx);
426 [ + + ]: 162 : if (!reg_search_ctx) {
427 : 27 : break;
428 : : }
429 : :
430 [ + - # # : 135 : FTL_NOTICELOG(dev,
# # # # #
# # # # #
# # # # #
# # # #
# ]
431 : : "Region type:0x%"PRIx32" ver:%"PRIu32" blk_offs:0x%"PRIx64" blk_sz:0x%"PRIx64"\n",
432 : : reg_search_ctx->type, reg_search_ctx->ver, reg_search_ctx->blk_offs, reg_search_ctx->blk_sz);
433 : : }
434 : 27 : }
435 : :
436 : : static int
437 : 42 : layout_apply_from_sb_blob(struct spdk_ftl_dev *dev, struct ftl_layout_tracker_bdev *layout_tracker,
438 : : int (*filter_region_type_fn)(enum ftl_layout_region_type))
439 : : {
440 : : struct ftl_layout_region *reg;
441 : 42 : const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL;
442 : :
443 : 0 : while (true) {
444 : 462 : ftl_layout_tracker_bdev_find_next_region(layout_tracker, FTL_LAYOUT_REGION_TYPE_INVALID,
445 : : ®_search_ctx);
446 [ + + ]: 462 : if (!reg_search_ctx) {
447 : 42 : break;
448 : : }
449 [ + + # # : 420 : if (reg_search_ctx->type == FTL_LAYOUT_REGION_TYPE_FREE) {
# # ]
450 : 63 : continue;
451 : : }
452 [ - + # # : 357 : if (filter_region_type_fn(reg_search_ctx->type)) {
# # # # #
# ]
453 [ # # # # : 0 : FTL_ERRLOG(dev, "Unknown region found in layout blob: type 0x%"PRIx32"\n", reg_search_ctx->type);
# # # # #
# # # ]
454 : 0 : return -1;
455 : : }
456 : :
457 [ # # # # : 357 : reg = &dev->layout.region[reg_search_ctx->type];
# # # # #
# # # ]
458 : :
459 : : /* First region of a given type found */
460 [ + + # # : 357 : if (reg->type == FTL_LAYOUT_REGION_TYPE_INVALID) {
# # ]
461 [ # # # # : 315 : reg->type = reg_search_ctx->type;
# # # # ]
462 [ # # # # : 315 : reg->current.version = reg_search_ctx->ver;
# # # # #
# ]
463 [ # # # # : 315 : reg->current.offset = reg_search_ctx->blk_offs;
# # # # #
# ]
464 [ # # # # : 315 : reg->current.blocks = reg_search_ctx->blk_sz;
# # # # #
# ]
465 : 315 : continue;
466 : : }
467 : :
468 : : /* Update to the oldest region version found */
469 [ - + # # : 42 : if (reg_search_ctx->ver < reg->current.version) {
# # # # #
# # # ]
470 [ # # # # : 0 : reg->current.version = reg_search_ctx->ver;
# # # # #
# ]
471 [ # # # # : 0 : reg->current.offset = reg_search_ctx->blk_offs;
# # # # #
# ]
472 [ # # # # : 0 : reg->current.blocks = reg_search_ctx->blk_sz;
# # # # #
# ]
473 : 0 : continue;
474 : : }
475 : :
476 : : /* Skip newer region versions */
477 [ - + # # : 42 : if (reg_search_ctx->ver > reg->current.version) {
# # # # #
# # # ]
478 : 0 : continue;
479 : : }
480 : :
481 : : /* Current region version already found */
482 [ - + # # : 42 : assert(reg_search_ctx->ver == reg->current.version);
# # # # #
# # # #
# ]
483 [ + - # # : 42 : if (reg->current.offset != reg_search_ctx->blk_offs ||
# # # # #
# # # #
# ]
484 [ - + # # : 42 : reg->current.blocks != reg_search_ctx->blk_sz) {
# # # # #
# ]
485 [ # # # # : 0 : FTL_ERRLOG(dev, "Corrupted layout blob: reg type 0x%"PRIx32"\n", reg_search_ctx->type);
# # # # #
# # # ]
486 : 0 : return -1;
487 : : }
488 : : }
489 : 42 : return 0;
490 : 0 : }
491 : :
492 : : static int
493 : 420 : layout_region_verify(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type)
494 : : {
495 : 420 : struct ftl_layout_region *reg = ftl_layout_region_get(dev, reg_type);
496 [ + + ]: 420 : if (!reg) {
497 : 63 : return -ENOENT;
498 : : }
499 : :
500 : : /* Unknown version found in the blob */
501 [ - + # # : 357 : if (reg->current.version > ftl_layout_upgrade_get_latest_version(reg_type)) {
# # # # ]
502 [ # # # # : 0 : FTL_ERRLOG(dev, "Unknown region version found in layout blob: reg type 0x%"PRIx32"\n",
# # # # ]
503 : : reg_type);
504 : 0 : return -EINVAL;
505 : : }
506 : :
507 : 357 : return 0;
508 : 0 : }
509 : :
510 : : static int
511 : 0 : layout_fixup_reg_data_base(struct spdk_ftl_dev *dev)
512 : : {
513 [ # # # # : 0 : const struct ftl_md_layout_ops *base_md_ops = &dev->base_type->ops.md_layout_ops;
# # # # ]
514 [ # # # # : 0 : struct ftl_layout_region *reg = &dev->layout.region[FTL_LAYOUT_REGION_TYPE_DATA_BASE];
# # # # ]
515 : 0 : const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL;
516 : :
517 [ # # # # : 0 : assert(reg->type == FTL_LAYOUT_REGION_TYPE_INVALID);
# # # # ]
518 : :
519 [ # # # # : 0 : FTL_NOTICELOG(dev, "Adding a region\n");
# # # # ]
520 : :
521 : : /* Add the region */
522 [ # # # # : 0 : if (base_md_ops->region_create(dev, FTL_LAYOUT_REGION_TYPE_DATA_BASE, 0,
# # # # #
# # # ]
523 : 0 : ftl_layout_base_offset(dev))) {
524 : 0 : return -1;
525 : : }
526 [ # # # # : 0 : if (base_md_ops->region_open(dev, FTL_LAYOUT_REGION_TYPE_DATA_BASE, 0, FTL_BLOCK_SIZE,
# # # # #
# # # ]
527 : 0 : ftl_layout_base_offset(dev), reg)) {
528 : 0 : return -1;
529 : : }
530 : :
531 [ # # # # ]: 0 : ftl_layout_tracker_bdev_find_next_region(dev->base_layout_tracker, FTL_LAYOUT_REGION_TYPE_DATA_BASE,
532 : : ®_search_ctx);
533 [ # # # # ]: 0 : assert(reg_search_ctx);
534 : 0 : return 0;
535 : 0 : }
536 : :
537 : : static int
538 : 21 : layout_fixup_base(struct spdk_ftl_dev *dev)
539 : : {
540 : : struct ftl_layout_region_descr {
541 : : enum ftl_layout_region_type type;
542 : : uint32_t ver;
543 : : int (*on_reg_miss)(struct spdk_ftl_dev *dev);
544 : : };
545 : : struct ftl_layout_region_descr *reg_descr;
546 : : static struct ftl_layout_region_descr nvc_regs[] = {
547 : : { .type = FTL_LAYOUT_REGION_TYPE_SB_BASE, .ver = FTL_SB_VERSION_CURRENT },
548 : : { .type = FTL_LAYOUT_REGION_TYPE_DATA_BASE, .ver = 0, .on_reg_miss = layout_fixup_reg_data_base },
549 : : { .type = FTL_LAYOUT_REGION_TYPE_VALID_MAP, .ver = 0 },
550 : : { .type = FTL_LAYOUT_REGION_TYPE_INVALID, .ver = 0 },
551 : : };
552 : :
553 [ + + # # : 84 : for (reg_descr = nvc_regs; reg_descr->type != FTL_LAYOUT_REGION_TYPE_INVALID; reg_descr++) {
# # # # ]
554 : : struct ftl_layout_region *region;
555 : :
556 [ - + # # : 63 : if (layout_region_verify(dev, reg_descr->type) &&
# # # # ]
557 [ # # # # : 0 : reg_descr->on_reg_miss && reg_descr->on_reg_miss(dev)) {
# # # # #
# # # #
# ]
558 : 0 : return -1;
559 : : }
560 : :
561 [ # # # # : 63 : region = &dev->layout.region[reg_descr->type];
# # # # #
# # # ]
562 [ # # # # : 63 : region->type = reg_descr->type;
# # # # ]
563 [ # # # # ]: 63 : region->mirror_type = FTL_LAYOUT_REGION_TYPE_INVALID;
564 [ # # # # : 63 : region->name = ftl_md_region_name(reg_descr->type);
# # # # ]
565 : :
566 [ # # # # : 63 : region->bdev_desc = dev->base_bdev_desc;
# # # # ]
567 [ # # # # : 63 : region->ioch = dev->base_ioch;
# # # # ]
568 [ # # # # ]: 63 : region->vss_blksz = 0;
569 : 0 : }
570 : :
571 : 21 : return 0;
572 : 0 : }
573 : :
574 : : static int
575 : 21 : layout_fixup_nvc(struct spdk_ftl_dev *dev)
576 : : {
577 : : int rc;
578 : : struct ftl_layout_region_descr {
579 : : enum ftl_layout_region_type type;
580 : : bool deprecated;
581 : : enum ftl_layout_region_type mirror_type;
582 : : };
583 : : struct ftl_layout_region_descr *reg_descr;
584 : : static struct ftl_layout_region_descr nvc_regs[] = {
585 : : { .type = FTL_LAYOUT_REGION_TYPE_SB, .mirror_type = FTL_LAYOUT_REGION_TYPE_SB_BASE },
586 : : { .type = FTL_LAYOUT_REGION_TYPE_L2P },
587 : : { .type = FTL_LAYOUT_REGION_TYPE_BAND_MD, .mirror_type = FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR },
588 : : { .type = FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR },
589 : : { .type = FTL_LAYOUT_REGION_TYPE_TRIM_MD, .mirror_type = FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR },
590 : : { .type = FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR },
591 : : { .type = FTL_LAYOUT_REGION_TYPE_TRIM_LOG, .mirror_type = FTL_LAYOUT_REGION_TYPE_TRIM_LOG_MIRROR },
592 : : { .type = FTL_LAYOUT_REGION_TYPE_TRIM_LOG_MIRROR },
593 : : { .type = FTL_LAYOUT_REGION_TYPE_NVC_MD, .mirror_type = FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR },
594 : : { .type = FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR },
595 : : { .type = FTL_LAYOUT_REGION_TYPE_DATA_NVC, .deprecated = true },
596 : : { .type = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC },
597 : : { .type = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC_NEXT },
598 : : { .type = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP },
599 : : { .type = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP_NEXT },
600 : : { .type = FTL_LAYOUT_REGION_TYPE_P2L_LOG_IO_MIN },
601 : : { .type = FTL_LAYOUT_REGION_TYPE_P2L_LOG_IO_MAX },
602 : : { .type = FTL_LAYOUT_REGION_TYPE_INVALID },
603 : : };
604 : :
605 [ + + # # : 378 : for (reg_descr = nvc_regs; reg_descr->type != FTL_LAYOUT_REGION_TYPE_INVALID; reg_descr++) {
# # # # ]
606 : : struct ftl_layout_region *region;
607 : :
608 [ # # # # ]: 357 : rc = layout_region_verify(dev, reg_descr->type);
609 [ + + ]: 357 : if (rc == -ENOENT) {
610 [ - + + + : 63 : if (reg_descr->deprecated) {
# # # # ]
611 : 21 : continue;
612 : : }
613 : :
614 [ # # # # : 42 : ftl_layout_upgrade_add_region_placeholder(dev, dev->nvc_layout_tracker, reg_descr->type);
# # # # ]
615 [ - + ]: 294 : } else if (rc) {
616 : 0 : return -1;
617 : : }
618 : :
619 [ - + - + : 336 : if (reg_descr->deprecated) {
# # # # ]
620 [ # # # # : 0 : rc = ftl_layout_upgrade_drop_region(dev, dev->nvc_layout_tracker, reg_descr->type,
# # # # ]
621 [ # # # # : 0 : dev->layout.region[reg_descr->type].current.version);
# # # # #
# # # # #
# # # # ]
622 [ # # ]: 0 : if (rc) {
623 : 0 : return rc;
624 : : }
625 : 0 : continue;
626 : : }
627 : :
628 [ # # # # : 336 : region = &dev->layout.region[reg_descr->type];
# # # # #
# # # ]
629 [ # # # # : 336 : region->type = reg_descr->type;
# # # # ]
630 [ + + # # : 336 : region->mirror_type = (reg_descr->mirror_type) ? reg_descr->mirror_type :
# # # # #
# # # #
# ]
631 : : FTL_LAYOUT_REGION_TYPE_INVALID;
632 [ # # # # : 336 : region->name = ftl_md_region_name(reg_descr->type);
# # # # ]
633 : :
634 [ # # # # : 336 : region->bdev_desc = dev->nv_cache.bdev_desc;
# # # # #
# ]
635 [ # # # # : 336 : region->ioch = dev->nv_cache.cache_ioch;
# # # # #
# ]
636 [ # # # # : 336 : region->vss_blksz = dev->nv_cache.md_size;
# # # # #
# ]
637 : 0 : }
638 : :
639 : 21 : return 0;
640 : 0 : }
641 : :
642 : : static int
643 : 357 : filter_region_type_base(enum ftl_layout_region_type reg_type)
644 : : {
645 [ + + ]: 357 : switch (reg_type) {
646 : 63 : case FTL_LAYOUT_REGION_TYPE_SB_BASE:
647 : : case FTL_LAYOUT_REGION_TYPE_DATA_BASE:
648 : : case FTL_LAYOUT_REGION_TYPE_VALID_MAP:
649 : 63 : return 0;
650 : :
651 : 294 : default:
652 : 294 : return 1;
653 : : }
654 : 0 : }
655 : :
656 : : static int
657 : 294 : filter_region_type_nvc(enum ftl_layout_region_type reg_type)
658 : : {
659 : 294 : return filter_region_type_base(reg_type) ? 0 : 1;
660 : : }
661 : :
662 : : static int
663 : 21 : layout_apply_nvc(struct spdk_ftl_dev *dev)
664 : : {
665 [ + - - + : 42 : if (layout_apply_from_sb_blob(dev, dev->nvc_layout_tracker, filter_region_type_nvc) ||
# # # # ]
666 : 21 : layout_fixup_nvc(dev)) {
667 : 0 : return -1;
668 : : }
669 : 21 : return 0;
670 : 0 : }
671 : :
672 : : static int
673 : 21 : layout_apply_base(struct spdk_ftl_dev *dev)
674 : : {
675 [ + - - + : 42 : if (layout_apply_from_sb_blob(dev, dev->base_layout_tracker, filter_region_type_base) ||
# # # # ]
676 : 21 : layout_fixup_base(dev)) {
677 : 0 : return -1;
678 : : }
679 : 21 : return 0;
680 : 0 : }
681 : :
682 : : int
683 : 21 : ftl_superblock_v5_md_layout_apply(struct spdk_ftl_dev *dev)
684 : : {
685 [ + - - + ]: 21 : if (layout_apply_nvc(dev) || layout_apply_base(dev)) {
686 : 0 : return -1;
687 : : }
688 : 21 : return 0;
689 : 0 : }
|