Branch data 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 "spdk/bdev.h"
8 : :
9 : : #include "ftl_core.h"
10 : : #include "ftl_utils.h"
11 : : #include "ftl_band.h"
12 : : #include "ftl_layout.h"
13 : : #include "ftl_nv_cache.h"
14 : : #include "ftl_sb.h"
15 : : #include "nvc/ftl_nvc_dev.h"
16 : : #include "utils/ftl_layout_tracker_bdev.h"
17 : : #include "upgrade/ftl_layout_upgrade.h"
18 : :
19 : : enum ftl_layout_setup_mode {
20 : : FTL_LAYOUT_SETUP_MODE_LOAD_CURRENT = 0,
21 : : FTL_LAYOUT_SETUP_MODE_NO_RESTRICT,
22 : : FTL_LAYOUT_SETUP_MODE_LEGACY_DEFAULT,
23 : : };
24 : :
25 : : static inline float
26 : 792 : blocks2mib(uint64_t blocks)
27 : : {
28 : : float result;
29 : :
30 : 792 : result = blocks;
31 : 792 : result *= FTL_BLOCK_SIZE;
32 : 792 : result /= 1024UL;
33 : 792 : result /= 1024UL;
34 : :
35 : 792 : return result;
36 : : }
37 : :
38 : : static uint64_t
39 : 1203 : superblock_region_size(struct spdk_ftl_dev *dev)
40 : : {
41 [ # # # # ]: 1203 : const struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(dev->base_bdev_desc);
42 : 1203 : uint64_t wus = spdk_bdev_get_write_unit_size(bdev) * FTL_BLOCK_SIZE;
43 : :
44 [ - + # # ]: 1203 : if (wus > FTL_SUPERBLOCK_SIZE) {
45 : 0 : return wus;
46 : : } else {
47 [ # # ]: 1203 : return wus * spdk_divide_round_up(FTL_SUPERBLOCK_SIZE, wus);
48 : : }
49 : 0 : }
50 : :
51 : : static uint64_t
52 : 889 : superblock_region_blocks(struct spdk_ftl_dev *dev)
53 : : {
54 [ # # ]: 889 : return superblock_region_size(dev) / FTL_BLOCK_SIZE;
55 : : }
56 : :
57 : : uint64_t
58 : 270 : ftl_md_region_blocks(struct spdk_ftl_dev *dev, uint64_t bytes)
59 : : {
60 : 270 : const uint64_t alignment = superblock_region_size(dev);
61 : : uint64_t result;
62 : :
63 : 270 : result = spdk_divide_round_up(bytes, alignment);
64 : 270 : result *= alignment;
65 [ # # ]: 270 : result /= FTL_BLOCK_SIZE;
66 : :
67 : 270 : return result;
68 : : }
69 : :
70 : : uint64_t
71 : 119 : ftl_md_region_align_blocks(struct spdk_ftl_dev *dev, uint64_t blocks)
72 : : {
73 : 119 : const uint64_t alignment = superblock_region_blocks(dev);
74 : : uint64_t result;
75 : :
76 : 119 : result = spdk_divide_round_up(blocks, alignment);
77 : 119 : result *= alignment;
78 : :
79 : 119 : return result;
80 : : }
81 : :
82 : : const char *
83 : 447 : ftl_md_region_name(enum ftl_layout_region_type reg_type)
84 : : {
85 : : static const char *md_region_name[FTL_LAYOUT_REGION_TYPE_MAX] = {
86 : : [FTL_LAYOUT_REGION_TYPE_SB] = "sb",
87 : : [FTL_LAYOUT_REGION_TYPE_SB_BASE] = "sb_mirror",
88 : : [FTL_LAYOUT_REGION_TYPE_L2P] = "l2p",
89 : : [FTL_LAYOUT_REGION_TYPE_BAND_MD] = "band_md",
90 : : [FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR] = "band_md_mirror",
91 : : [FTL_LAYOUT_REGION_TYPE_VALID_MAP] = "vmap",
92 : : [FTL_LAYOUT_REGION_TYPE_NVC_MD] = "nvc_md",
93 : : [FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR] = "nvc_md_mirror",
94 : : [FTL_LAYOUT_REGION_TYPE_DATA_NVC] = "data_nvc",
95 : : [FTL_LAYOUT_REGION_TYPE_DATA_BASE] = "data_btm",
96 : : [FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC] = "p2l0",
97 : : [FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC_NEXT] = "p2l1",
98 : : [FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP] = "p2l2",
99 : : [FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP_NEXT] = "p2l3",
100 : : [FTL_LAYOUT_REGION_TYPE_TRIM_MD] = "trim_md",
101 : : [FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR] = "trim_md_mirror",
102 : : [FTL_LAYOUT_REGION_TYPE_TRIM_LOG] = "trim_log",
103 : : [FTL_LAYOUT_REGION_TYPE_TRIM_LOG_MIRROR] = "trim_log_mirror",
104 : : [FTL_LAYOUT_REGION_TYPE_P2L_LOG_IO_MIN] = "p2l_log_io1",
105 : : [FTL_LAYOUT_REGION_TYPE_P2L_LOG_IO_MAX] = "p2l_log_io2",
106 : : };
107 [ # # # # : 447 : const char *reg_name = md_region_name[reg_type];
# # ]
108 : :
109 [ - + # # ]: 447 : assert(reg_type < FTL_LAYOUT_REGION_TYPE_MAX);
110 [ - + # # ]: 447 : assert(reg_name != NULL);
111 : 447 : return reg_name;
112 : : }
113 : :
114 : : static bool
115 : 22440 : is_region_disabled(struct ftl_layout_region *region)
116 : : {
117 [ + + + - : 22440 : return region->current.blocks == 0 && region->current.offset == FTL_ADDR_INVALID;
# # # # #
# # # #
# ]
118 : : }
119 : :
120 : : static void
121 : 408 : dump_region(struct spdk_ftl_dev *dev, struct ftl_layout_region *region)
122 : : {
123 [ + + ]: 408 : if (is_region_disabled(region)) {
124 : 34 : return;
125 : : }
126 : :
127 [ - + - + : 374 : assert(!(region->current.offset % superblock_region_blocks(dev)));
# # # # #
# # # ]
128 [ - + - + : 374 : assert(!(region->current.blocks % superblock_region_blocks(dev)));
# # # # #
# # # ]
129 : :
130 [ + - # # : 374 : FTL_NOTICELOG(dev, "Region %s\n", region->name);
# # # # #
# # # ]
131 [ + - # # : 374 : FTL_NOTICELOG(dev, " offset: %.2f MiB\n",
# # # # #
# # # #
# ]
132 : : blocks2mib(region->current.offset));
133 [ + - # # : 374 : FTL_NOTICELOG(dev, " blocks: %.2f MiB\n",
# # # # #
# # # #
# ]
134 : : blocks2mib(region->current.blocks));
135 : 0 : }
136 : :
137 : : int
138 : 66 : ftl_validate_regions(struct spdk_ftl_dev *dev, struct ftl_layout *layout)
139 : : {
140 : : enum ftl_layout_region_type i, j;
141 : :
142 : : /* Validate if regions doesn't overlap each other */
143 [ + + ]: 1386 : for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; i++) {
144 : 1320 : struct ftl_layout_region *r1 = ftl_layout_region_get(dev, i);
145 : :
146 [ + + + + ]: 1320 : if (!r1 || is_region_disabled(r1)) {
147 : 198 : continue;
148 : : }
149 : :
150 [ + + ]: 23562 : for (j = 0; j < FTL_LAYOUT_REGION_TYPE_MAX; j++) {
151 : 22440 : struct ftl_layout_region *r2 = ftl_layout_region_get(dev, j);
152 : :
153 [ + + + + ]: 22440 : if (!r2 || is_region_disabled(r2)) {
154 : 3366 : continue;
155 : : }
156 : :
157 [ + + # # : 19074 : if (r1->bdev_desc != r2->bdev_desc) {
# # # # #
# ]
158 : 5544 : continue;
159 : : }
160 : :
161 [ + + ]: 13530 : if (i == j) {
162 : 1122 : continue;
163 : : }
164 : :
165 [ # # # # : 12408 : uint64_t r1_begin = r1->current.offset;
# # ]
166 [ # # # # : 12408 : uint64_t r1_end = r1->current.offset + r1->current.blocks - 1;
# # # # #
# # # ]
167 [ # # # # : 12408 : uint64_t r2_begin = r2->current.offset;
# # ]
168 [ # # # # : 12408 : uint64_t r2_end = r2->current.offset + r2->current.blocks - 1;
# # # # #
# # # ]
169 : :
170 [ - + # # : 12408 : if (spdk_max(r1_begin, r2_begin) <= spdk_min(r1_end, r2_end)) {
# # ]
171 [ # # # # : 0 : FTL_ERRLOG(dev, "Layout initialization ERROR, two regions overlap, "
# # # # #
# # # # #
# # ]
172 : : "%s and %s\n", r1->name, r2->name);
173 : 0 : return -1;
174 : : }
175 : 0 : }
176 : 0 : }
177 : :
178 : 66 : return 0;
179 : 0 : }
180 : :
181 : : static uint64_t
182 : 22 : get_num_user_lbas(struct spdk_ftl_dev *dev)
183 : : {
184 : : uint64_t blocks;
185 : :
186 [ # # # # ]: 22 : blocks = dev->num_bands * ftl_get_num_blocks_in_band(dev);
187 [ # # # # : 22 : blocks = (blocks * (100 - dev->conf.overprovisioning)) / 100;
# # # # ]
188 : :
189 : 22 : return blocks;
190 : : }
191 : :
192 : : struct ftl_layout_region *
193 : 45631241 : ftl_layout_region_get(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type)
194 : : {
195 [ # # # # : 45631241 : struct ftl_layout_region *reg = &dev->layout.region[reg_type];
# # # # ]
196 : :
197 [ - + # # ]: 45631241 : assert(reg_type < FTL_LAYOUT_REGION_TYPE_MAX);
198 [ + + # # : 45631241 : return reg->type == reg_type ? reg : NULL;
# # ]
199 : : }
200 : :
201 : : uint64_t
202 : 5 : ftl_layout_base_offset(struct spdk_ftl_dev *dev)
203 : : {
204 [ # # # # ]: 5 : return dev->num_bands * ftl_get_num_blocks_in_band(dev);
205 : : }
206 : :
207 : : static int
208 : 87 : layout_region_create_nvc(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type,
209 : : uint32_t reg_version, size_t entry_size, size_t entry_count)
210 : : {
211 [ # # # # : 87 : const struct ftl_md_layout_ops *md_ops = &dev->nv_cache.nvc_type->ops.md_layout_ops;
# # # # #
# ]
212 : 87 : size_t reg_blks = ftl_md_region_blocks(dev, entry_count * entry_size);
213 : :
214 [ - + # # : 87 : if (md_ops->region_create(dev, reg_type, reg_version, reg_blks)) {
# # # # #
# ]
215 : 0 : return -1;
216 : : }
217 [ - + # # : 174 : if (md_ops->region_open(dev, reg_type, reg_version, entry_size, entry_count,
# # # # #
# ]
218 [ # # # # : 87 : &dev->layout.region[reg_type])) {
# # # # ]
219 : 0 : return -1;
220 : : }
221 : 87 : return 0;
222 : 0 : }
223 : :
224 : : static int
225 : 32 : layout_region_create_base(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type,
226 : : uint32_t reg_version, size_t entry_size, size_t entry_count)
227 : : {
228 [ # # # # : 32 : const struct ftl_md_layout_ops *md_ops = &dev->base_type->ops.md_layout_ops;
# # # # ]
229 : 32 : size_t reg_blks = ftl_md_region_blocks(dev, entry_count * entry_size);
230 : :
231 [ - + # # : 32 : if (md_ops->region_create(dev, reg_type, reg_version, reg_blks)) {
# # # # #
# ]
232 : 0 : return -1;
233 : : }
234 [ - + # # : 64 : if (md_ops->region_open(dev, reg_type, reg_version, entry_size, entry_count,
# # # # #
# ]
235 [ # # # # : 32 : &dev->layout.region[reg_type])) {
# # # # ]
236 : 0 : return -1;
237 : : }
238 : 32 : return 0;
239 : 0 : }
240 : :
241 : : static void
242 : 0 : legacy_layout_verify_region(struct ftl_layout_tracker_bdev *layout_tracker,
243 : : enum ftl_layout_region_type reg_type, uint32_t reg_version)
244 : : {
245 : 0 : const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL;
246 : 0 : const struct ftl_layout_tracker_bdev_region_props *reg_found = NULL;
247 : :
248 : 0 : while (true) {
249 : 0 : ftl_layout_tracker_bdev_find_next_region(layout_tracker, reg_type, ®_search_ctx);
250 [ # # ]: 0 : if (!reg_search_ctx) {
251 : 0 : break;
252 : : }
253 : :
254 : : /* Only a single region version is present in upgrade from the legacy layout */
255 [ # # # # : 0 : ftl_bug(reg_search_ctx->ver != reg_version);
# # # # ]
256 [ # # # # ]: 0 : ftl_bug(reg_found != NULL);
257 : :
258 : 0 : reg_found = reg_search_ctx;
259 : : }
260 : 0 : }
261 : :
262 : : static int
263 : 0 : legacy_layout_region_open_nvc(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type,
264 : : uint32_t reg_version, size_t entry_size, size_t entry_count)
265 : : {
266 [ # # # # : 0 : struct ftl_layout_region *reg = &dev->layout.region[reg_type];
# # # # ]
267 [ # # # # : 0 : const struct ftl_md_layout_ops *md_ops = &dev->nv_cache.nvc_type->ops.md_layout_ops;
# # # # #
# ]
268 : :
269 [ # # # # ]: 0 : legacy_layout_verify_region(dev->nvc_layout_tracker, reg_type, reg_version);
270 [ # # # # : 0 : return md_ops->region_open(dev, reg_type, reg_version, entry_size, entry_count, reg);
# # # # ]
271 : : }
272 : :
273 : : static int
274 : 0 : legacy_layout_region_open_base(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type,
275 : : uint32_t reg_version, size_t entry_size, size_t entry_count)
276 : : {
277 [ # # # # : 0 : struct ftl_layout_region *reg = &dev->layout.region[reg_type];
# # # # ]
278 [ # # # # : 0 : const struct ftl_md_layout_ops *md_ops = &dev->base_type->ops.md_layout_ops;
# # # # ]
279 : :
280 [ # # # # ]: 0 : legacy_layout_verify_region(dev->nvc_layout_tracker, reg_type, reg_version);
281 [ # # # # : 0 : return md_ops->region_open(dev, reg_type, reg_version, entry_size, entry_count, reg);
# # # # ]
282 : : }
283 : :
284 : : static int
285 : 0 : layout_setup_legacy_default_nvc(struct spdk_ftl_dev *dev)
286 : : {
287 : : int region_type;
288 : : uint64_t blocks, chunk_count;
289 [ # # ]: 0 : struct ftl_layout *layout = &dev->layout;
290 : 0 : const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL;
291 : :
292 : : /* Initialize L2P region */
293 [ # # # # : 0 : blocks = ftl_md_region_blocks(dev, layout->l2p.addr_size * dev->num_lbas);
# # # # #
# ]
294 [ # # # # ]: 0 : if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_L2P, 0, FTL_BLOCK_SIZE,
295 : 0 : blocks)) {
296 : 0 : goto error;
297 : : }
298 : :
299 : : /* Initialize band info metadata */
300 [ # # # # ]: 0 : if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_BAND_MD, FTL_BAND_VERSION_1,
301 : 0 : sizeof(struct ftl_band_md), ftl_get_num_bands(dev))) {
302 : 0 : goto error;
303 : : }
304 : :
305 : : /* Initialize band info metadata mirror */
306 [ # # # # ]: 0 : if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR, FTL_BAND_VERSION_1,
307 : 0 : sizeof(struct ftl_band_md), ftl_get_num_bands(dev))) {
308 : 0 : goto error;
309 : : }
310 [ # # # # : 0 : layout->region[FTL_LAYOUT_REGION_TYPE_BAND_MD].mirror_type = FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR;
# # # # #
# ]
311 : :
312 : : /*
313 : : * Initialize P2L checkpointing regions
314 : : */
315 [ # # ]: 0 : for (region_type = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MIN;
316 [ # # ]: 0 : region_type <= FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MAX;
317 [ # # ]: 0 : region_type++) {
318 : 0 : const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL;
319 : :
320 : : /* Get legacy number of blocks */
321 [ # # # # ]: 0 : ftl_layout_tracker_bdev_find_next_region(dev->nvc_layout_tracker, region_type, ®_search_ctx);
322 [ # # # # : 0 : if (!reg_search_ctx || reg_search_ctx->ver != FTL_P2L_VERSION_1) {
# # # # ]
323 : 0 : goto error;
324 : : }
325 [ # # # # ]: 0 : blocks = reg_search_ctx->blk_sz;
326 : :
327 [ # # ]: 0 : if (legacy_layout_region_open_nvc(dev, region_type, FTL_P2L_VERSION_1, FTL_BLOCK_SIZE, blocks)) {
328 : 0 : goto error;
329 : : }
330 : 0 : }
331 : :
332 : : /*
333 : : * Initialize trim metadata region
334 : : */
335 [ # # # # : 0 : blocks = layout->region[FTL_LAYOUT_REGION_TYPE_L2P].current.blocks;
# # # # #
# # # ]
336 [ # # # # ]: 0 : if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_TRIM_MD, 0, sizeof(uint64_t),
337 : 0 : blocks)) {
338 : 0 : goto error;
339 : : }
340 : :
341 : : /* Initialize trim metadata mirror region */
342 [ # # # # ]: 0 : if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR, 0, sizeof(uint64_t),
343 : 0 : blocks)) {
344 : 0 : goto error;
345 : : }
346 [ # # # # : 0 : layout->region[FTL_LAYOUT_REGION_TYPE_TRIM_MD].mirror_type = FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR;
# # # # #
# ]
347 : :
348 : : /* Restore chunk count */
349 [ # # # # ]: 0 : ftl_layout_tracker_bdev_find_next_region(dev->nvc_layout_tracker, FTL_LAYOUT_REGION_TYPE_DATA_NVC,
350 : : ®_search_ctx);
351 [ # # # # : 0 : if (!reg_search_ctx || reg_search_ctx->ver != 0) {
# # # # ]
352 : 0 : goto error;
353 : : }
354 [ # # # # ]: 0 : blocks = reg_search_ctx->blk_sz;
355 [ # # ]: 0 : chunk_count = blocks / ftl_get_num_blocks_in_band(dev);
356 [ # # ]: 0 : if (0 == chunk_count) {
357 : 0 : goto error;
358 : : }
359 : :
360 : : /*
361 : : * Initialize NV Cache metadata
362 : : */
363 [ # # # # ]: 0 : if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_NVC_MD, FTL_NVC_VERSION_1,
364 : 0 : sizeof(struct ftl_nv_cache_chunk_md), chunk_count)) {
365 : 0 : goto error;
366 : : }
367 : :
368 : : /*
369 : : * Initialize NV Cache metadata mirror
370 : : */
371 [ # # # # ]: 0 : if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR, FTL_NVC_VERSION_1,
372 : 0 : sizeof(struct ftl_nv_cache_chunk_md), chunk_count)) {
373 : 0 : goto error;
374 : : }
375 [ # # # # : 0 : layout->region[FTL_LAYOUT_REGION_TYPE_NVC_MD].mirror_type = FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR;
# # # # #
# ]
376 : :
377 : : /*
378 : : * Initialize data region on NV cache
379 : : */
380 [ # # ]: 0 : if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_DATA_NVC, 0,
381 [ # # # # : 0 : layout->nvc.chunk_data_blocks * FTL_BLOCK_SIZE, chunk_count)) {
# # ]
382 : 0 : goto error;
383 : : }
384 : :
385 : : /* Here is the place to add necessary region placeholders for the creation of new regions */
386 [ # # # # ]: 0 : ftl_layout_upgrade_add_region_placeholder(dev, dev->nvc_layout_tracker,
387 : : FTL_LAYOUT_REGION_TYPE_TRIM_LOG);
388 [ # # # # ]: 0 : ftl_layout_upgrade_add_region_placeholder(dev, dev->nvc_layout_tracker,
389 : : FTL_LAYOUT_REGION_TYPE_TRIM_LOG_MIRROR);
390 : :
391 : 0 : return 0;
392 : :
393 : 0 : error:
394 [ # # # # : 0 : FTL_ERRLOG(dev, "Invalid legacy NV Cache metadata layout\n");
# # # # ]
395 : 0 : return -1;
396 : 0 : }
397 : :
398 : : static int
399 : 0 : layout_setup_legacy_default_base(struct spdk_ftl_dev *dev)
400 : : {
401 [ # # ]: 0 : struct ftl_layout *layout = &dev->layout;
402 : :
403 : : /* Base device layout is as follows:
404 : : * - superblock
405 : : * - data
406 : : * - valid map
407 : : */
408 [ # # # # ]: 0 : if (layout_region_create_base(dev, FTL_LAYOUT_REGION_TYPE_DATA_BASE, 0, FTL_BLOCK_SIZE,
409 : 0 : ftl_layout_base_offset(dev))) {
410 : 0 : return -1;
411 : : }
412 : :
413 [ # # ]: 0 : if (legacy_layout_region_open_base(dev, FTL_LAYOUT_REGION_TYPE_VALID_MAP, 0, FTL_BLOCK_SIZE,
414 [ # # # # : 0 : ftl_md_region_blocks(dev, spdk_divide_round_up(layout->base.total_blocks + layout->nvc.total_blocks,
# # # # #
# # # ]
415 : : 8)))) {
416 : 0 : return -1;
417 : : }
418 : :
419 : 0 : return 0;
420 : 0 : }
421 : :
422 : : static int
423 : 0 : layout_setup_legacy_default(struct spdk_ftl_dev *dev)
424 : : {
425 [ # # # # ]: 0 : if (layout_setup_legacy_default_nvc(dev) || layout_setup_legacy_default_base(dev)) {
426 : 0 : return -1;
427 : : }
428 : 0 : return 0;
429 : 0 : }
430 : :
431 : : static int
432 : 5 : layout_setup_default_nvc(struct spdk_ftl_dev *dev)
433 : : {
434 : : int region_type;
435 : : uint64_t blocks;
436 [ # # ]: 5 : struct ftl_layout *layout = &dev->layout;
437 : :
438 : : /* Initialize L2P region */
439 [ # # # # : 5 : blocks = ftl_md_region_blocks(dev, layout->l2p.addr_size * dev->num_lbas);
# # # # #
# ]
440 [ - + ]: 5 : if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_L2P, 0, FTL_BLOCK_SIZE, blocks)) {
441 : 0 : goto error;
442 : : }
443 : :
444 : : /* Initialize band info metadata */
445 [ - + # # ]: 5 : if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_BAND_MD, FTL_BAND_VERSION_CURRENT,
446 : 0 : sizeof(struct ftl_band_md), ftl_get_num_bands(dev))) {
447 : 0 : goto error;
448 : : }
449 : :
450 : : /* Initialize band info metadata mirror */
451 [ - + # # ]: 5 : if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR, FTL_BAND_VERSION_CURRENT,
452 : 0 : sizeof(struct ftl_band_md), ftl_get_num_bands(dev))) {
453 : 0 : goto error;
454 : : }
455 [ # # # # : 5 : layout->region[FTL_LAYOUT_REGION_TYPE_BAND_MD].mirror_type = FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR;
# # # # #
# ]
456 : :
457 : : /*
458 : : * Initialize P2L checkpointing regions
459 : : */
460 [ # # ]: 5 : for (region_type = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MIN;
461 [ + + ]: 25 : region_type <= FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MAX;
462 [ # # ]: 20 : region_type++) {
463 [ - + ]: 20 : if (layout_region_create_nvc(dev, region_type, FTL_P2L_VERSION_CURRENT, FTL_BLOCK_SIZE,
464 [ # # # # : 0 : layout->p2l.ckpt_pages)) {
# # ]
465 : 0 : goto error;
466 : : }
467 : 0 : }
468 : :
469 : : /*
470 : : * Initialize trim metadata region
471 : : */
472 [ # # # # : 5 : blocks = layout->region[FTL_LAYOUT_REGION_TYPE_L2P].current.blocks;
# # # # #
# # # ]
473 : 5 : blocks = spdk_divide_round_up(blocks * sizeof(uint64_t), FTL_BLOCK_SIZE);
474 [ - + ]: 5 : if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_TRIM_MD, 0, FTL_BLOCK_SIZE, blocks)) {
475 : 0 : goto error;
476 : : }
477 : :
478 : : /* Initialize trim metadata mirror region */
479 [ - + # # ]: 5 : if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR, 0, FTL_BLOCK_SIZE,
480 : 0 : blocks)) {
481 : 0 : goto error;
482 : : }
483 [ # # # # : 5 : layout->region[FTL_LAYOUT_REGION_TYPE_TRIM_MD].mirror_type = FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR;
# # # # #
# ]
484 : :
485 : : /*
486 : : * Initialize trim log region
487 : : */
488 [ - + ]: 5 : if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_TRIM_LOG, FTL_TRIM_LOG_VERSION_CURRENT,
489 : : sizeof(struct ftl_trim_log), 1)) {
490 : 0 : goto error;
491 : : }
492 : :
493 : : /* Initialize trim log mirror region */
494 [ - + ]: 5 : if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_TRIM_LOG_MIRROR,
495 : : FTL_TRIM_LOG_VERSION_CURRENT,
496 : : sizeof(struct ftl_trim_log), 1)) {
497 : 0 : goto error;
498 : : }
499 [ # # # # : 5 : layout->region[FTL_LAYOUT_REGION_TYPE_TRIM_LOG].mirror_type =
# # # # #
# ]
500 : : FTL_LAYOUT_REGION_TYPE_TRIM_LOG_MIRROR;
501 : :
502 : : /*
503 : : * Initialize NV Cache metadata
504 : : */
505 [ - + # # : 5 : if (0 == layout->nvc.chunk_count) {
# # # # ]
506 : 0 : goto error;
507 : : }
508 [ - + ]: 5 : if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_NVC_MD, FTL_NVC_VERSION_CURRENT,
509 [ # # # # : 0 : sizeof(struct ftl_nv_cache_chunk_md), layout->nvc.chunk_count)) {
# # ]
510 : 0 : goto error;
511 : : }
512 : :
513 : : /*
514 : : * Initialize NV Cache metadata mirror
515 : : */
516 [ - + ]: 5 : if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR, FTL_NVC_VERSION_CURRENT,
517 [ # # # # : 0 : sizeof(struct ftl_nv_cache_chunk_md), layout->nvc.chunk_count)) {
# # ]
518 : 0 : goto error;
519 : : }
520 [ # # # # : 5 : layout->region[FTL_LAYOUT_REGION_TYPE_NVC_MD].mirror_type = FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR;
# # # # #
# ]
521 : :
522 [ - + # # : 5 : if (dev->nv_cache.nvc_type->ops.setup_layout) {
# # # # #
# # # #
# ]
523 [ # # # # : 0 : return dev->nv_cache.nvc_type->ops.setup_layout(dev);
# # # # #
# # # # #
# # ]
524 : : }
525 : :
526 : 5 : return 0;
527 : :
528 : 0 : error:
529 [ # # # # : 0 : FTL_ERRLOG(dev, "Insufficient NV Cache capacity to preserve metadata\n");
# # # # ]
530 : 0 : return -1;
531 : 0 : }
532 : :
533 : : static int
534 : 5 : layout_setup_default_base(struct spdk_ftl_dev *dev)
535 : : {
536 [ # # ]: 5 : struct ftl_layout *layout = &dev->layout;
537 : : uint64_t valid_map_size;
538 : :
539 : : /* Base device layout is as follows:
540 : : * - superblock
541 : : * - data
542 : : * - valid map
543 : : */
544 [ - + # # ]: 5 : if (layout_region_create_base(dev, FTL_LAYOUT_REGION_TYPE_DATA_BASE, 0, FTL_BLOCK_SIZE,
545 : 0 : ftl_layout_base_offset(dev))) {
546 : 0 : return -1;
547 : : }
548 : :
549 [ # # # # : 5 : valid_map_size = spdk_divide_round_up(layout->base.total_blocks + layout->nvc.total_blocks, 8);
# # # # #
# # # ]
550 [ - + # # ]: 5 : if (layout_region_create_base(dev, FTL_LAYOUT_REGION_TYPE_VALID_MAP, 0, FTL_BLOCK_SIZE,
551 : 0 : ftl_md_region_blocks(dev, valid_map_size))) {
552 : 0 : return -1;
553 : : }
554 : :
555 : 5 : return 0;
556 : 0 : }
557 : :
558 : : static int
559 : 5 : layout_setup_default(struct spdk_ftl_dev *dev)
560 : : {
561 [ + - - + ]: 5 : if (layout_setup_default_nvc(dev) || layout_setup_default_base(dev)) {
562 : 0 : return -1;
563 : : }
564 : 5 : return 0;
565 : 0 : }
566 : :
567 : : static int
568 : 17 : layout_load(struct spdk_ftl_dev *dev)
569 : : {
570 [ - + ]: 17 : if (ftl_superblock_load_blob_area(dev)) {
571 : 0 : return -1;
572 : : }
573 [ - + ]: 17 : if (ftl_superblock_md_layout_apply(dev)) {
574 : 0 : return -1;
575 : : }
576 : 17 : return 0;
577 : 0 : }
578 : :
579 : : int
580 : 22 : ftl_layout_setup(struct spdk_ftl_dev *dev)
581 : : {
582 [ # # ]: 22 : struct ftl_layout *layout = &dev->layout;
583 : : uint64_t i;
584 : : uint64_t num_lbas;
585 : : enum ftl_layout_setup_mode setup_mode;
586 : : int rc;
587 : :
588 : : /*
589 : : * SB v5 adds the ability to create MD regions dynamically, i.e. depending on the underlying device type.
590 : : * For compatibility reasons:
591 : : * 1. When upgrading from pre-v5 SB, only the legacy default layout is created.
592 : : * Pre-v5: some regions were static and not stored in the SB layout. These must be created to match
593 : : * the legacy default layout.
594 : : * v5: all regions are stored in the SB layout. Upon the SB upgrade, the legacy default layout
595 : : * is updated with pre-v5 layout stored in the SB. The whole layout is then stored in v5 SB.
596 : : *
597 : : * 2. When SB v5 or later was loaded, the layout is instantiated from the nvc and base layout blobs.
598 : : * No default layout is created.
599 : : *
600 : : * 3. When the FTL layout is being created for the first time, there are no restrictions.
601 : : *
602 : : * Any new regions to be created in cases (1) and (2) can only be placed in the unallocated area
603 : : * of the underlying device.
604 : : */
605 : :
606 [ + + # # : 22 : if (dev->conf.mode & SPDK_FTL_MODE_CREATE) {
# # # # ]
607 : 5 : setup_mode = FTL_LAYOUT_SETUP_MODE_NO_RESTRICT;
608 [ - + # # : 17 : } else if (ftl_superblock_is_blob_area_empty(dev->sb)) {
# # ]
609 : 0 : setup_mode = FTL_LAYOUT_SETUP_MODE_LEGACY_DEFAULT;
610 : 0 : } else {
611 : 17 : setup_mode = FTL_LAYOUT_SETUP_MODE_LOAD_CURRENT;
612 : : }
613 [ + - # # : 22 : FTL_NOTICELOG(dev, "FTL layout setup mode %d\n", (int)setup_mode);
# # # # ]
614 : :
615 : : /* Invalidate all regions */
616 [ + + ]: 462 : for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; ++i) {
617 [ + + + + ]: 440 : if (i == FTL_LAYOUT_REGION_TYPE_SB || i == FTL_LAYOUT_REGION_TYPE_SB_BASE) {
618 : : /* Super block has been already initialized */
619 : 44 : continue;
620 : : }
621 : :
622 [ # # # # : 396 : layout->region[i].mirror_type = FTL_LAYOUT_REGION_TYPE_INVALID;
# # # # #
# ]
623 : : /* Mark the region inactive */
624 [ # # # # : 396 : layout->region[i].type = FTL_LAYOUT_REGION_TYPE_INVALID;
# # # # #
# ]
625 : 0 : }
626 : :
627 : : /*
628 : : * Initialize L2P information
629 : : */
630 : 22 : num_lbas = get_num_user_lbas(dev);
631 [ + + # # : 22 : if (dev->num_lbas == 0) {
# # ]
632 [ - + # # : 5 : assert(dev->conf.mode & SPDK_FTL_MODE_CREATE);
# # # # #
# ]
633 [ # # # # ]: 5 : dev->num_lbas = num_lbas;
634 [ # # # # : 5 : dev->sb->lba_cnt = num_lbas;
# # # # ]
635 [ - + # # : 17 : } else if (dev->num_lbas != num_lbas) {
# # ]
636 [ # # # # : 0 : FTL_ERRLOG(dev, "Mismatched FTL num_lbas\n");
# # # # ]
637 : 0 : return -EINVAL;
638 : : }
639 [ # # # # : 22 : layout->l2p.addr_length = spdk_u64log2(layout->base.total_blocks + layout->nvc.total_blocks) + 1;
# # # # #
# # # # #
# # # # ]
640 [ - + # # : 22 : layout->l2p.addr_size = layout->l2p.addr_length > 32 ? 8 : 4;
# # # # #
# # # ]
641 [ - + # # : 22 : layout->l2p.lbas_in_page = FTL_BLOCK_SIZE / layout->l2p.addr_size;
# # # # #
# # # #
# ]
642 : :
643 : : /* Setup P2L ckpt */
644 [ # # # # : 22 : layout->p2l.pages_per_xfer = spdk_divide_round_up(dev->xfer_size, FTL_NUM_P2L_ENTRIES_NO_VSS);
# # # # #
# ]
645 [ # # # # : 44 : layout->p2l.ckpt_pages = spdk_divide_round_up(ftl_get_num_blocks_in_band(dev),
# # ]
646 [ # # # # : 22 : dev->xfer_size) * layout->p2l.pages_per_xfer;
# # # # #
# # # ]
647 : :
648 [ # # # # : 22 : layout->nvc.chunk_data_blocks = ftl_get_num_blocks_in_band(dev);
# # ]
649 [ - + # # : 22 : layout->nvc.chunk_count = layout->nvc.total_blocks / ftl_get_num_blocks_in_band(dev);
# # # # #
# # # #
# ]
650 [ # # # # : 22 : layout->nvc.chunk_tail_md_num_blocks = ftl_nv_cache_chunk_tail_md_num_blocks(&dev->nv_cache);
# # # # ]
651 : :
652 [ # # # # : 22 : layout->base.num_usable_blocks = ftl_get_num_blocks_in_band(dev);
# # ]
653 [ # # # # : 22 : layout->base.user_blocks = ftl_band_user_blocks(dev->bands);
# # # # #
# ]
654 : :
655 [ - + + - ]: 22 : switch (setup_mode) {
656 : 0 : case FTL_LAYOUT_SETUP_MODE_LEGACY_DEFAULT:
657 [ # # ]: 0 : if (layout_setup_legacy_default(dev)) {
658 : 0 : return -EINVAL;
659 : : }
660 : 0 : break;
661 : :
662 : 17 : case FTL_LAYOUT_SETUP_MODE_LOAD_CURRENT:
663 [ - + ]: 17 : if (layout_load(dev)) {
664 : 0 : return -EINVAL;
665 : : }
666 : 17 : break;
667 : :
668 : 5 : case FTL_LAYOUT_SETUP_MODE_NO_RESTRICT:
669 [ - + ]: 5 : if (layout_setup_default(dev)) {
670 : 0 : return -EINVAL;
671 : : }
672 : 5 : break;
673 : :
674 : 0 : default:
675 [ # # ]: 0 : ftl_abort();
676 : 0 : break;
677 : : }
678 : :
679 [ - + ]: 22 : if (ftl_validate_regions(dev, layout)) {
680 : 0 : return -EINVAL;
681 : : }
682 : :
683 : 22 : rc = ftl_superblock_store_blob_area(dev);
684 : :
685 [ + - # # : 22 : FTL_NOTICELOG(dev, "Base device capacity: %.2f MiB\n",
# # # # #
# # # #
# ]
686 : : blocks2mib(layout->base.total_blocks));
687 [ + - # # : 22 : FTL_NOTICELOG(dev, "NV cache device capacity: %.2f MiB\n",
# # # # #
# # # #
# ]
688 : : blocks2mib(layout->nvc.total_blocks));
689 [ + - # # : 22 : FTL_NOTICELOG(dev, "L2P entries: %"PRIu64"\n", dev->num_lbas);
# # # # #
# # # ]
690 [ + - # # : 22 : FTL_NOTICELOG(dev, "L2P address size: %"PRIu64"\n", layout->l2p.addr_size);
# # # # #
# # # #
# ]
691 [ + - # # : 22 : FTL_NOTICELOG(dev, "P2L checkpoint pages: %"PRIu64"\n", layout->p2l.ckpt_pages);
# # # # #
# # # #
# ]
692 [ + - # # : 22 : FTL_NOTICELOG(dev, "NV cache chunk count %"PRIu64"\n", dev->layout.nvc.chunk_count);
# # # # #
# # # # #
# # ]
693 : :
694 : 22 : return rc;
695 : 0 : }
696 : :
697 : : int
698 : 22 : ftl_layout_setup_superblock(struct spdk_ftl_dev *dev)
699 : : {
700 : : const struct spdk_bdev *bdev;
701 [ # # ]: 22 : struct ftl_layout *layout = &dev->layout;
702 [ # # # # : 22 : struct ftl_layout_region *region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB];
# # ]
703 : : uint64_t total_blocks, offset, left;
704 : :
705 [ - + # # : 22 : assert(layout->md[FTL_LAYOUT_REGION_TYPE_SB] == NULL);
# # # # #
# ]
706 : :
707 [ # # # # ]: 22 : bdev = spdk_bdev_desc_get_bdev(dev->base_bdev_desc);
708 [ # # # # : 22 : layout->base.total_blocks = spdk_bdev_get_num_blocks(bdev);
# # ]
709 : :
710 [ # # # # : 22 : bdev = spdk_bdev_desc_get_bdev(dev->nv_cache.bdev_desc);
# # ]
711 [ # # # # : 22 : layout->nvc.total_blocks = spdk_bdev_get_num_blocks(bdev);
# # ]
712 : :
713 : : /* Initialize superblock region */
714 [ - + # # ]: 22 : if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_SB, FTL_SB_VERSION_CURRENT,
715 : 0 : superblock_region_size(dev), 1)) {
716 [ # # # # : 0 : FTL_ERRLOG(dev, "Error when setting up primary super block\n");
# # # # ]
717 : 0 : return -1;
718 : : }
719 : :
720 [ - + # # : 22 : assert(region->bdev_desc != NULL);
# # # # ]
721 [ - + # # : 22 : assert(region->ioch != NULL);
# # # # ]
722 [ - + # # : 22 : assert(region->current.offset == 0);
# # # # #
# ]
723 : :
724 [ - + # # ]: 22 : if (layout_region_create_base(dev, FTL_LAYOUT_REGION_TYPE_SB_BASE, FTL_SB_VERSION_CURRENT,
725 : 0 : superblock_region_size(dev), 1)) {
726 [ # # # # : 0 : FTL_ERRLOG(dev, "Error when setting up secondary super block\n");
# # # # ]
727 : 0 : return -1;
728 : : }
729 [ # # # # : 22 : layout->region[FTL_LAYOUT_REGION_TYPE_SB].mirror_type = FTL_LAYOUT_REGION_TYPE_SB_BASE;
# # # # #
# ]
730 : :
731 [ # # # # : 22 : region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB_BASE];
# # ]
732 [ - + # # : 22 : assert(region->current.offset == 0);
# # # # #
# ]
733 : :
734 : : /* Check if SB can be stored at the end of base device */
735 : 22 : total_blocks = spdk_bdev_get_num_blocks(
736 [ # # # # ]: 22 : spdk_bdev_desc_get_bdev(dev->base_bdev_desc));
737 [ # # # # : 22 : offset = region->current.offset + region->current.blocks;
# # # # #
# # # ]
738 : 22 : left = total_blocks - offset;
739 [ + - - + ]: 22 : if ((left > total_blocks) || (offset > total_blocks)) {
740 [ # # # # : 0 : FTL_ERRLOG(dev, "Error when setup base device super block\n");
# # # # ]
741 : 0 : return -1;
742 : : }
743 : :
744 : 22 : return 0;
745 : 0 : }
746 : :
747 : : int
748 : 0 : ftl_layout_clear_superblock(struct spdk_ftl_dev *dev)
749 : : {
750 : : int rc;
751 : :
752 [ # # # # ]: 0 : rc = ftl_layout_tracker_bdev_rm_region(dev->nvc_layout_tracker, FTL_LAYOUT_REGION_TYPE_SB,
753 : : FTL_SB_VERSION_CURRENT);
754 [ # # ]: 0 : if (rc) {
755 : 0 : return rc;
756 : : }
757 : :
758 [ # # # # ]: 0 : return ftl_layout_tracker_bdev_rm_region(dev->base_layout_tracker, FTL_LAYOUT_REGION_TYPE_SB_BASE,
759 : : FTL_SB_VERSION_CURRENT);
760 : 0 : }
761 : :
762 : : void
763 : 22 : ftl_layout_dump(struct spdk_ftl_dev *dev)
764 : : {
765 : : struct ftl_layout_region *reg;
766 : : enum ftl_layout_region_type i;
767 : :
768 [ + - # # : 22 : FTL_NOTICELOG(dev, "NV cache layout:\n");
# # # # ]
769 [ + + ]: 462 : for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; ++i) {
770 : 440 : reg = ftl_layout_region_get(dev, i);
771 [ + + + + : 440 : if (reg && reg->bdev_desc == dev->nv_cache.bdev_desc) {
# # # # #
# # # #
# ]
772 : 342 : dump_region(dev, reg);
773 : 0 : }
774 : 0 : }
775 [ + - # # : 22 : FTL_NOTICELOG(dev, "Base device layout:\n");
# # # # ]
776 [ + + ]: 462 : for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; ++i) {
777 : 440 : reg = ftl_layout_region_get(dev, i);
778 [ + + + + : 440 : if (reg && reg->bdev_desc == dev->base_bdev_desc) {
# # # # #
# # # ]
779 : 66 : dump_region(dev, reg);
780 : 0 : }
781 : 0 : }
782 : 22 : }
783 : :
784 : : uint64_t
785 : 22 : ftl_layout_base_md_blocks(struct spdk_ftl_dev *dev)
786 : : {
787 : : const struct spdk_bdev *bdev;
788 : 22 : uint64_t md_blocks = 0, total_blocks = 0;
789 : :
790 [ # # # # ]: 22 : bdev = spdk_bdev_desc_get_bdev(dev->base_bdev_desc);
791 : 22 : total_blocks += spdk_bdev_get_num_blocks(bdev);
792 : :
793 [ # # # # : 22 : bdev = spdk_bdev_desc_get_bdev(dev->nv_cache.bdev_desc);
# # ]
794 : 22 : total_blocks += spdk_bdev_get_num_blocks(bdev);
795 : :
796 : : /* Count space needed for validity map */
797 : 22 : md_blocks += ftl_md_region_blocks(dev, spdk_divide_round_up(total_blocks, 8));
798 : :
799 : : /* Count space needed for superblock */
800 : 22 : md_blocks += superblock_region_blocks(dev);
801 : 22 : return md_blocks;
802 : : }
803 : :
804 : : struct layout_blob_entry {
805 : : uint32_t type;
806 : : uint64_t entry_size;
807 : : uint64_t num_entries;
808 : : } __attribute__((packed));
809 : :
810 : : size_t
811 : 28 : ftl_layout_blob_store(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_buf_sz)
812 : : {
813 : 28 : struct layout_blob_entry *blob_entry = blob_buf;
814 : : struct ftl_layout_region *reg;
815 : : enum ftl_layout_region_type reg_type;
816 : 28 : size_t blob_sz = 0;
817 : :
818 [ + + ]: 588 : for (reg_type = 0; reg_type < FTL_LAYOUT_REGION_TYPE_MAX; reg_type++) {
819 [ - + ]: 560 : if (blob_sz + sizeof(*blob_entry) > blob_buf_sz) {
820 : 0 : return 0;
821 : : }
822 : :
823 [ # # # # : 560 : reg = &dev->layout.region[reg_type];
# # # # ]
824 [ # # # # ]: 560 : blob_entry->type = reg_type;
825 [ # # # # : 560 : blob_entry->entry_size = reg->entry_size;
# # # # ]
826 [ # # # # : 560 : blob_entry->num_entries = reg->num_entries;
# # # # ]
827 : :
828 [ # # ]: 560 : blob_entry++;
829 : 560 : blob_sz += sizeof(*blob_entry);
830 : 0 : }
831 : :
832 : 28 : return blob_sz;
833 : 0 : }
834 : :
835 : : int
836 : 38 : ftl_layout_blob_load(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_sz)
837 : : {
838 : 38 : struct layout_blob_entry *blob_entry = blob_buf;
839 [ # # ]: 38 : size_t blob_entry_num = blob_sz / sizeof(*blob_entry);
840 [ # # ]: 38 : struct layout_blob_entry *blob_entry_end = blob_entry + blob_entry_num;
841 : : struct ftl_layout_region *reg;
842 : :
843 [ - + # # ]: 38 : if (blob_sz % sizeof(*blob_entry) != 0) {
844 : : /* Invalid blob size */
845 : 0 : return -1;
846 : : }
847 : :
848 [ + + # # ]: 747 : for (; blob_entry < blob_entry_end; blob_entry++) {
849 : : /* Verify the type */
850 [ + + # # : 712 : if (blob_entry->type >= FTL_LAYOUT_REGION_TYPE_MAX) {
# # ]
851 : 3 : return -1;
852 : : }
853 : :
854 : : /* Load the entry */
855 [ # # # # : 709 : reg = &dev->layout.region[blob_entry->type];
# # # # #
# # # ]
856 [ # # # # : 709 : reg->entry_size = blob_entry->entry_size;
# # # # ]
857 [ # # # # : 709 : reg->num_entries = blob_entry->num_entries;
# # # # ]
858 : 0 : }
859 : :
860 : 35 : return 0;
861 : 0 : }
862 : :
863 : : void
864 : 34 : ftl_layout_upgrade_add_region_placeholder(struct spdk_ftl_dev *dev,
865 : : struct ftl_layout_tracker_bdev *layout_tracker, enum ftl_layout_region_type reg_type)
866 : : {
867 : 34 : const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL;
868 : :
869 : 34 : ftl_layout_tracker_bdev_find_next_region(layout_tracker, reg_type, ®_search_ctx);
870 [ - + ]: 34 : if (reg_search_ctx) {
871 : 0 : return;
872 : : }
873 : :
874 [ # # # # : 34 : dev->layout.region[reg_type].type = reg_type;
# # # # #
# # # ]
875 [ # # # # : 34 : dev->layout.region[reg_type].current.version = 0;
# # # # #
# # # #
# ]
876 [ # # # # : 34 : dev->layout.region[reg_type].current.offset = UINT64_MAX;
# # # # #
# # # #
# ]
877 [ # # # # : 34 : dev->layout.region[reg_type].current.blocks = 0;
# # # # #
# # # #
# ]
878 : 0 : }
|