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/env.h"
8 : : #include "spdk/bdev_module.h"
9 : :
10 : : #include "ftl_core.h"
11 : : #include "ftl_md.h"
12 : : #include "ftl_nv_cache_io.h"
13 : :
14 : : struct ftl_md;
15 : : static void io_submit(struct ftl_md *md);
16 : : static void io_done(struct ftl_md *md);
17 : :
18 : : static bool
19 : 7204 : has_mirror(struct ftl_md *md)
20 : : {
21 [ + - ]: 7204 : if (md->region) {
22 [ + + ]: 7204 : if (md->region->mirror_type != FTL_LAYOUT_REGION_TYPE_INVALID) {
23 [ - + ]: 639 : return md->mirror_enabled;
24 : : }
25 : : }
26 : :
27 : 6565 : return false;
28 : : }
29 : :
30 : : static struct ftl_md *
31 : 316 : ftl_md_get_mirror(struct ftl_md *md)
32 : : {
33 [ + - ]: 316 : if (has_mirror(md)) {
34 : 316 : return md->dev->layout.md[md->region->mirror_type];
35 : : }
36 : :
37 : 0 : return NULL;
38 : : }
39 : :
40 : : uint64_t
41 : 22751 : ftl_md_xfer_blocks(struct spdk_ftl_dev *dev)
42 : : {
43 : 22751 : return 4ULL * dev->xfer_size;
44 : : }
45 : :
46 : : static uint64_t
47 : 528 : xfer_size(struct ftl_md *md)
48 : : {
49 : 528 : return ftl_md_xfer_blocks(md->dev) * FTL_BLOCK_SIZE;
50 : : }
51 : :
52 : : static void
53 : 88 : ftl_md_create_heap(struct ftl_md *md, uint64_t vss_blksz)
54 : : {
55 : 88 : md->shm_fd = -1;
56 : 88 : md->vss_data = NULL;
57 : 88 : md->data = calloc(md->data_blocks, FTL_BLOCK_SIZE + vss_blksz);
58 : :
59 [ + - + - ]: 88 : if (md->data && vss_blksz) {
60 : 88 : md->vss_data = ((char *)md->data) + md->data_blocks * FTL_BLOCK_SIZE;
61 : : }
62 : 88 : }
63 : :
64 : : static void
65 : 176 : ftl_md_destroy_heap(struct ftl_md *md)
66 : : {
67 [ + + ]: 176 : if (md->data) {
68 : 88 : free(md->data);
69 : 88 : md->data = NULL;
70 : 88 : md->vss_data = NULL;
71 : : }
72 : 176 : }
73 : :
74 : : static int
75 : 258 : ftl_wrapper_open(const char *name, int of, mode_t m)
76 : : {
77 [ - + ]: 258 : return open(name, of, m);
78 : : }
79 : :
80 : : static void
81 : 258 : ftl_md_setup_obj(struct ftl_md *md, int flags,
82 : : const char *name)
83 : : {
84 : 258 : char uuid_str[SPDK_UUID_STRING_LEN];
85 : : const char *fmt;
86 : :
87 [ - + ]: 258 : if (!(flags & FTL_MD_CREATE_SHM)) {
88 : 0 : assert(false);
89 : : return;
90 : : }
91 : :
92 : : /* TODO: temporary, define a proper hugetlbfs mountpoint */
93 : 258 : fmt = "/dev/hugepages/ftl_%s_%s";
94 : 258 : md->shm_mmap_flags = MAP_SHARED;
95 : 258 : md->shm_open = ftl_wrapper_open;
96 : 258 : md->shm_unlink = unlink;
97 : :
98 [ + - + - ]: 516 : if (name == NULL ||
99 : 258 : spdk_uuid_fmt_lower(uuid_str, SPDK_UUID_STRING_LEN, &md->dev->conf.uuid) ||
100 [ - + - + ]: 258 : snprintf(md->name, sizeof(md->name) / sizeof(md->name[0]),
101 : : fmt, uuid_str, name) <= 0) {
102 : 0 : md->name[0] = 0;
103 : : }
104 : : }
105 : :
106 : : static void
107 : 16 : ftl_md_invalidate_shm(struct ftl_md *md)
108 : : {
109 [ - + - - : 16 : if (md->dev->sb_shm && md->dev->sb_shm->shm_ready) {
- - ]
110 : 0 : md->dev->init_retry = true;
111 : 0 : md->dev->sb_shm->shm_ready = false;
112 : : }
113 : 16 : }
114 : :
115 : : static void
116 : 258 : ftl_md_create_shm(struct ftl_md *md, uint64_t vss_blksz, int flags)
117 : : {
118 : 258 : struct stat shm_stat;
119 : : size_t vss_blk_offs;
120 : : void *shm_ptr;
121 : 258 : int open_flags = O_RDWR;
122 : 258 : mode_t open_mode = S_IRUSR | S_IWUSR;
123 : :
124 [ + - + - ]: 258 : assert(md->shm_open && md->shm_unlink);
125 : 258 : md->data = NULL;
126 : 258 : md->vss_data = NULL;
127 : 258 : md->shm_sz = 0;
128 : :
129 : : /* Must have an object name */
130 [ - + ]: 258 : if (md->name[0] == 0) {
131 : 0 : assert(false);
132 : 0 : return;
133 : : }
134 : :
135 : : /* If specified, unlink before create a new SHM object */
136 [ + + ]: 258 : if (flags & FTL_MD_CREATE_SHM_NEW) {
137 [ + + - + ]: 233 : if (md->shm_unlink(md->name) < 0 && errno != ENOENT) {
138 : 0 : ftl_md_invalidate_shm(md);
139 : 0 : return;
140 : : }
141 : 233 : open_flags += O_CREAT | O_TRUNC;
142 : : }
143 : :
144 : : /* Open existing or create a new SHM object, then query its props */
145 : 258 : md->shm_fd = md->shm_open(md->name, open_flags, open_mode);
146 [ + + - + ]: 258 : if (md->shm_fd < 0 || fstat(md->shm_fd, &shm_stat) < 0) {
147 : 16 : goto err_shm;
148 : : }
149 : :
150 : : /* Verify open mode hasn't changed */
151 [ - + ]: 242 : if ((shm_stat.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO)) != open_mode) {
152 : 0 : goto err_shm;
153 : : }
154 : :
155 : : /* Round up the SHM obj size to the nearest blk size (i.e. page size) */
156 : 242 : md->shm_sz = spdk_divide_round_up(md->data_blocks * FTL_BLOCK_SIZE, shm_stat.st_blksize);
157 : :
158 : : /* Add some blks for VSS metadata */
159 : 242 : vss_blk_offs = md->shm_sz;
160 : :
161 [ + + ]: 242 : if (vss_blksz) {
162 : 88 : md->shm_sz += spdk_divide_round_up(md->data_blocks * vss_blksz,
163 : 88 : shm_stat.st_blksize);
164 : : }
165 : :
166 : : /* Total SHM obj size */
167 : 242 : md->shm_sz *= shm_stat.st_blksize;
168 : :
169 : : /* Set or check the object size - zero init`d in case of set (FTL_MD_CREATE_SHM_NEW) */
170 [ + + + - ]: 242 : if ((shm_stat.st_size == 0 && (ftruncate(md->shm_fd, md->shm_sz) < 0 ||
171 [ + - ]: 233 : (flags & FTL_MD_CREATE_SHM_NEW) == 0))
172 [ + + - + ]: 242 : || (shm_stat.st_size > 0 && (size_t)shm_stat.st_size != md->shm_sz)) {
173 : 0 : goto err_shm;
174 : : }
175 : :
176 : : /* Create a virtual memory mapping for the object */
177 : 242 : shm_ptr = mmap(NULL, md->shm_sz, PROT_READ | PROT_WRITE, md->shm_mmap_flags,
178 : : md->shm_fd, 0);
179 [ - + ]: 242 : if (shm_ptr == MAP_FAILED) {
180 : 0 : goto err_shm;
181 : : }
182 : :
183 : 242 : md->data = shm_ptr;
184 [ + + ]: 242 : if (vss_blksz) {
185 : 88 : md->vss_data = ((char *)shm_ptr) + vss_blk_offs * shm_stat.st_blksize;
186 : : }
187 : :
188 : : /* Lock the pages in memory (i.e. prevent the pages to be paged out) */
189 [ - + ]: 242 : if (mlock(md->data, md->shm_sz) < 0) {
190 : 0 : goto err_map;
191 : : }
192 : :
193 [ - + ]: 242 : if (spdk_mem_register(md->data, md->shm_sz)) {
194 : 0 : goto err_mlock;
195 : : }
196 : 242 : md->mem_reg = true;
197 : :
198 : 242 : return;
199 : :
200 : : /* Cleanup upon fault */
201 : 0 : err_mlock:
202 : 0 : munlock(md->data, md->shm_sz);
203 : :
204 : 0 : err_map:
205 : 0 : munmap(md->data, md->shm_sz);
206 : 0 : md->data = NULL;
207 : 0 : md->vss_data = NULL;
208 : 0 : md->shm_sz = 0;
209 : :
210 : 16 : err_shm:
211 [ - + ]: 16 : if (md->shm_fd >= 0) {
212 : 0 : close(md->shm_fd);
213 : 0 : md->shm_unlink(md->name);
214 : 0 : md->shm_fd = -1;
215 : : }
216 : 16 : ftl_md_invalidate_shm(md);
217 : : }
218 : :
219 : : static void
220 : 308 : ftl_md_destroy_shm(struct ftl_md *md, int flags)
221 : : {
222 [ + + ]: 308 : if (!md->data) {
223 : 66 : return;
224 : : }
225 : :
226 [ - + ]: 242 : assert(md->shm_sz > 0);
227 [ - + + - ]: 242 : if (md->mem_reg) {
228 : 242 : spdk_mem_unregister(md->data, md->shm_sz);
229 : 242 : md->mem_reg = false;
230 : : }
231 : :
232 : : /* Unlock the pages in memory */
233 : 242 : munlock(md->data, md->shm_sz);
234 : :
235 : : /* Remove the virtual memory mapping for the object */
236 : 242 : munmap(md->data, md->shm_sz);
237 : :
238 : : /* Close SHM object fd */
239 : 242 : close(md->shm_fd);
240 : :
241 : 242 : md->data = NULL;
242 : 242 : md->vss_data = NULL;
243 : :
244 : : /* If specified, keep the object in SHM */
245 [ - + ]: 242 : if (flags & FTL_MD_DESTROY_SHM_KEEP) {
246 : 0 : return;
247 : : }
248 : :
249 : : /* Otherwise destroy/unlink the object */
250 [ + - + - ]: 242 : assert(md->name[0] != 0 && md->shm_unlink != NULL);
251 : 242 : md->shm_unlink(md->name);
252 : : }
253 : :
254 : 500 : struct ftl_md *ftl_md_create(struct spdk_ftl_dev *dev, uint64_t blocks,
255 : : uint64_t vss_blksz, const char *name, int flags,
256 : : const struct ftl_layout_region *region)
257 : : {
258 : : struct ftl_md *md;
259 : :
260 : 500 : md = calloc(1, sizeof(*md));
261 [ - + ]: 500 : if (!md) {
262 : 0 : return NULL;
263 : : }
264 : 500 : md->dev = dev;
265 : 500 : md->data_blocks = blocks;
266 : 500 : md->mirror_enabled = true;
267 : :
268 [ + + ]: 500 : if (flags != FTL_MD_CREATE_NO_MEM) {
269 [ + + ]: 346 : if (flags & FTL_MD_CREATE_SHM) {
270 : 258 : ftl_md_setup_obj(md, flags, name);
271 : 258 : ftl_md_create_shm(md, vss_blksz, flags);
272 : : } else {
273 [ - + ]: 88 : assert((flags & FTL_MD_CREATE_HEAP) == FTL_MD_CREATE_HEAP);
274 : 88 : ftl_md_create_heap(md, vss_blksz);
275 : : }
276 : :
277 [ + + ]: 346 : if (!md->data) {
278 : 16 : free(md);
279 : 16 : return NULL;
280 : : }
281 : : }
282 : :
283 [ + + ]: 484 : if (region) {
284 : 352 : size_t entry_vss_buf_size = vss_blksz * region->entry_size;
285 : :
286 [ + + ]: 352 : if (entry_vss_buf_size) {
287 : 242 : md->entry_vss_dma_buf = spdk_malloc(entry_vss_buf_size, FTL_BLOCK_SIZE,
288 : : NULL, SPDK_ENV_LCORE_ID_ANY,
289 : : SPDK_MALLOC_DMA);
290 [ - + ]: 242 : if (!md->entry_vss_dma_buf) {
291 : 0 : goto err;
292 : : }
293 : : }
294 : :
295 : 352 : ftl_md_set_region(md, region);
296 : : }
297 : :
298 : 484 : return md;
299 : 0 : err:
300 : 0 : ftl_md_destroy(md, ftl_md_destroy_region_flags(dev, region->type));
301 : 0 : return NULL;
302 : : }
303 : :
304 : : int
305 : 0 : ftl_md_unlink(struct spdk_ftl_dev *dev, const char *name, int flags)
306 : : {
307 : 0 : struct ftl_md md = { 0 };
308 : :
309 [ # # ]: 0 : if (0 == (flags & FTL_MD_CREATE_SHM)) {
310 : : /* Unlink can be called for shared memory only */
311 : 0 : return -EINVAL;
312 : : }
313 : :
314 : 0 : md.dev = dev;
315 : 0 : ftl_md_setup_obj(&md, flags, name);
316 : :
317 : 0 : return md.shm_unlink(md.name);
318 : : }
319 : :
320 : : void
321 : 485 : ftl_md_destroy(struct ftl_md *md, int flags)
322 : : {
323 [ + + ]: 485 : if (!md) {
324 : 1 : return;
325 : : }
326 : :
327 [ - + + + ]: 484 : if (!md->is_mirror) {
328 : 396 : ftl_md_free_buf(md, flags);
329 : 396 : spdk_free(md->entry_vss_dma_buf);
330 : : }
331 : 484 : free(md);
332 : : }
333 : :
334 : : void
335 : 484 : ftl_md_free_buf(struct ftl_md *md, int flags)
336 : : {
337 [ - + ]: 484 : if (!md) {
338 : 0 : return;
339 : : }
340 : :
341 [ + + ]: 484 : if (md->shm_fd < 0) {
342 [ - + ]: 176 : assert(flags == 0);
343 : 176 : ftl_md_destroy_heap(md);
344 : : } else {
345 : 308 : ftl_md_destroy_shm(md, flags);
346 : : }
347 : : }
348 : :
349 : : void *
350 : 1805090 : ftl_md_get_buffer(struct ftl_md *md)
351 : : {
352 : 1805090 : return md->data;
353 : : }
354 : :
355 : : uint64_t
356 : 329 : ftl_md_get_buffer_size(struct ftl_md *md)
357 : : {
358 : 329 : return md->data_blocks * FTL_BLOCK_SIZE;
359 : : }
360 : :
361 : : static void
362 : 438 : ftl_md_vss_buf_init(union ftl_md_vss *buf, uint32_t count,
363 : : const union ftl_md_vss *vss_pattern)
364 : : {
365 [ + + ]: 207354 : while (count) {
366 : 206916 : count--;
367 : 206916 : buf[count] = *vss_pattern;
368 : : }
369 : 438 : }
370 : :
371 : 88 : union ftl_md_vss *ftl_md_vss_buf_alloc(struct ftl_layout_region *region, uint32_t count)
372 : : {
373 : 88 : union ftl_md_vss *buf = spdk_zmalloc(count * FTL_MD_VSS_SZ, FTL_BLOCK_SIZE, NULL,
374 : : SPDK_ENV_LCORE_ID_ANY,
375 : : SPDK_MALLOC_DMA);
376 : :
377 [ - + ]: 88 : if (!buf) {
378 : 0 : return NULL;
379 : : }
380 : :
381 : 88 : union ftl_md_vss vss_buf = {0};
382 : 88 : vss_buf.version.md_version = region->current.version;
383 : 88 : ftl_md_vss_buf_init(buf, count, &vss_buf);
384 : 88 : return buf;
385 : : }
386 : :
387 : 11 : union ftl_md_vss *ftl_md_get_vss_buffer(struct ftl_md *md)
388 : : {
389 : 11 : return md->vss_data;
390 : : }
391 : :
392 : : static void
393 : 508 : io_cleanup(struct ftl_md *md)
394 : : {
395 : 508 : spdk_dma_free(md->io.data);
396 : 508 : md->io.data = NULL;
397 : :
398 : 508 : spdk_dma_free(md->io.md);
399 : 508 : md->io.md = NULL;
400 : 508 : }
401 : :
402 : : static void
403 : 0 : exception(void *arg)
404 : : {
405 : 0 : struct ftl_md *md = arg;
406 : :
407 : 0 : md->cb(md->dev, md, -EINVAL);
408 : 0 : io_cleanup(md);
409 : 0 : }
410 : :
411 : : static inline enum ftl_stats_type
412 : 11958 : get_bdev_io_ftl_stats_type(struct spdk_ftl_dev *dev, struct spdk_bdev_io *bdev_io) {
413 : 11958 : struct spdk_bdev *nvc = spdk_bdev_desc_get_bdev(dev->nv_cache.bdev_desc);
414 : :
415 [ + + ]: 11958 : if (bdev_io->bdev == nvc)
416 : : {
417 : 11854 : return FTL_STATS_TYPE_MD_NV_CACHE;
418 : : } else
419 : : {
420 : 104 : return FTL_STATS_TYPE_MD_BASE;
421 : : }
422 : : }
423 : :
424 : : static void
425 : 5601 : audit_md_vss_version(struct ftl_md *md, uint64_t blocks)
426 : : {
427 : : #if defined(DEBUG)
428 : 5601 : union ftl_md_vss *vss = md->io.md;
429 : : /* Need to load the superblock regardless of its version */
430 [ + + ]: 5601 : if (md->region->type == FTL_LAYOUT_REGION_TYPE_SB) {
431 : 82 : return;
432 : : }
433 [ + + ]: 5442319 : while (blocks) {
434 : 5436800 : blocks--;
435 [ - + ]: 5436800 : assert(vss[blocks].version.md_version == md->region->current.version);
436 : : }
437 : : #endif
438 : : }
439 : :
440 : : static void
441 : 5705 : read_write_blocks_cb(struct spdk_bdev_io *bdev_io, bool success, void *arg)
442 : : {
443 : 5705 : struct ftl_md *md = arg;
444 : :
445 : 5705 : ftl_stats_bdev_io_completed(md->dev, get_bdev_io_ftl_stats_type(md->dev, bdev_io), bdev_io);
446 : :
447 [ - + ]: 5705 : if (spdk_unlikely(!success)) {
448 [ # # # # ]: 0 : if (md->io.op == FTL_MD_OP_RESTORE && has_mirror(md)) {
449 : 0 : md->io.status = -EAGAIN;
450 : : } else {
451 : 0 : md->io.status = -EIO;
452 : : }
453 : : } else {
454 : 5705 : uint64_t blocks = bdev_io->u.bdev.num_blocks;
455 : 5705 : uint64_t size = blocks * FTL_BLOCK_SIZE;
456 : :
457 [ + + ]: 5705 : if (md->io.op == FTL_MD_OP_RESTORE) {
458 [ - + - + ]: 151 : memcpy(md->data + md->io.data_offset, md->io.data, size);
459 : :
460 [ + + ]: 151 : if (md->vss_data) {
461 : 135 : uint64_t vss_offset = md->io.data_offset / FTL_BLOCK_SIZE;
462 : 135 : vss_offset *= FTL_MD_VSS_SZ;
463 : 135 : audit_md_vss_version(md, blocks);
464 [ - + - + ]: 135 : memcpy(md->vss_data + vss_offset, md->io.md, blocks * FTL_MD_VSS_SZ);
465 : : }
466 : : }
467 : :
468 : 5705 : md->io.address += blocks;
469 : 5705 : md->io.remaining -= blocks;
470 : 5705 : md->io.data_offset += size;
471 : : }
472 : :
473 : 5705 : spdk_bdev_free_io(bdev_io);
474 : :
475 : 5705 : io_submit(md);
476 : 5705 : }
477 : :
478 : : static inline int
479 : 151 : read_blocks(struct spdk_ftl_dev *dev, struct spdk_bdev_desc *desc,
480 : : struct spdk_io_channel *ch,
481 : : void *buf, void *md_buf,
482 : : uint64_t offset_blocks, uint64_t num_blocks,
483 : : spdk_bdev_io_completion_cb cb, void *cb_arg)
484 : : {
485 [ + + ]: 151 : if (desc == dev->nv_cache.bdev_desc) {
486 : 135 : return ftl_nv_cache_bdev_read_blocks_with_md(dev, desc, ch, buf, md_buf,
487 : : offset_blocks, num_blocks,
488 : : cb, cb_arg);
489 [ - + ]: 16 : } else if (md_buf) {
490 : 0 : return spdk_bdev_read_blocks_with_md(desc, ch, buf, md_buf,
491 : : offset_blocks, num_blocks,
492 : : cb, cb_arg);
493 : : } else {
494 : 16 : return spdk_bdev_read_blocks(desc, ch, buf,
495 : : offset_blocks, num_blocks,
496 : : cb, cb_arg);
497 : : }
498 : : }
499 : :
500 : : static inline int
501 : 11807 : write_blocks(struct spdk_ftl_dev *dev, struct spdk_bdev_desc *desc,
502 : : struct spdk_io_channel *ch,
503 : : void *buf, void *md_buf,
504 : : uint64_t offset_blocks, uint64_t num_blocks,
505 : : spdk_bdev_io_completion_cb cb, void *cb_arg)
506 : : {
507 [ + + ]: 11807 : if (desc == dev->nv_cache.bdev_desc) {
508 : 11719 : return ftl_nv_cache_bdev_write_blocks_with_md(dev, desc, ch, buf, md_buf,
509 : : offset_blocks, num_blocks,
510 : : cb, cb_arg);
511 [ - + ]: 88 : } else if (md_buf) {
512 : 0 : return spdk_bdev_write_blocks_with_md(desc, ch, buf, md_buf, offset_blocks,
513 : : num_blocks, cb, cb_arg);
514 : : } else {
515 : 88 : return spdk_bdev_write_blocks(desc, ch, buf, offset_blocks, num_blocks, cb, cb_arg);
516 : : }
517 : : }
518 : :
519 : : static void
520 : 5705 : read_write_blocks(void *_md)
521 : : {
522 : 5705 : struct ftl_md *md = _md;
523 : 5705 : const struct ftl_layout_region *region = md->region;
524 : : uint64_t blocks;
525 : 5705 : int rc = 0;
526 : :
527 [ + + ]: 5705 : blocks = spdk_min(md->io.remaining, ftl_md_xfer_blocks(md->dev));
528 : :
529 [ + + - ]: 5705 : switch (md->io.op) {
530 : 151 : case FTL_MD_OP_RESTORE:
531 : 151 : rc = read_blocks(md->dev, region->bdev_desc, region->ioch,
532 : : md->io.data, md->io.md,
533 : : md->io.address, blocks,
534 : : read_write_blocks_cb, md);
535 : 151 : break;
536 : 5554 : case FTL_MD_OP_PERSIST:
537 : : case FTL_MD_OP_CLEAR:
538 : 5554 : rc = write_blocks(md->dev, region->bdev_desc, region->ioch,
539 : : md->io.data, md->io.md,
540 : : md->io.address, blocks,
541 : : read_write_blocks_cb, md);
542 : 5554 : break;
543 : 0 : default:
544 : 0 : ftl_abort();
545 : : }
546 : :
547 [ - + ]: 5705 : if (spdk_unlikely(rc)) {
548 [ # # ]: 0 : if (rc == -ENOMEM) {
549 : 0 : struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(region->bdev_desc);
550 : 0 : md->io.bdev_io_wait.bdev = bdev;
551 : 0 : md->io.bdev_io_wait.cb_fn = read_write_blocks;
552 : 0 : md->io.bdev_io_wait.cb_arg = md;
553 : 0 : spdk_bdev_queue_io_wait(bdev, region->ioch, &md->io.bdev_io_wait);
554 : : } else {
555 : 0 : ftl_abort();
556 : : }
557 : : }
558 : 5705 : }
559 : :
560 : : static void
561 : 6213 : io_submit(struct ftl_md *md)
562 : : {
563 [ + + - + ]: 6213 : if (!md->io.remaining || md->io.status) {
564 : 508 : io_done(md);
565 : 508 : return;
566 : : }
567 : :
568 [ + + ]: 5705 : if (md->io.op == FTL_MD_OP_PERSIST) {
569 [ + + ]: 337 : uint64_t blocks = spdk_min(md->io.remaining, ftl_md_xfer_blocks(md->dev));
570 : :
571 [ - + - + ]: 337 : memcpy(md->io.data, md->data + md->io.data_offset, FTL_BLOCK_SIZE * blocks);
572 : :
573 [ + + ]: 337 : if (md->vss_data) {
574 : 249 : uint64_t vss_offset = md->io.data_offset / FTL_BLOCK_SIZE;
575 : 249 : vss_offset *= FTL_MD_VSS_SZ;
576 [ - + ]: 249 : assert(md->io.md);
577 [ - + - + ]: 249 : memcpy(md->io.md, md->vss_data + vss_offset, FTL_MD_VSS_SZ * blocks);
578 : 249 : audit_md_vss_version(md, blocks);
579 : : }
580 : : }
581 : : #if defined(DEBUG)
582 [ + + + + ]: 5705 : if (md->io.md && md->io.op == FTL_MD_OP_CLEAR) {
583 [ + + ]: 5217 : uint64_t blocks = spdk_min(md->io.remaining, ftl_md_xfer_blocks(md->dev));
584 : 5217 : audit_md_vss_version(md, blocks);
585 : : }
586 : : #endif
587 : :
588 : 5705 : read_write_blocks(md);
589 : : }
590 : :
591 : : static int
592 : 508 : io_can_start(struct ftl_md *md)
593 : : {
594 [ - + ]: 508 : assert(NULL == md->io.data);
595 [ - + ]: 508 : if (NULL != md->io.data) {
596 : : /* Outgoing IO on metadata */
597 : 0 : return -EINVAL;
598 : : }
599 : :
600 [ - + ]: 508 : if (!md->region) {
601 : : /* No device region to process data */
602 : 0 : return -EINVAL;
603 : : }
604 : :
605 [ - + ]: 508 : if (md->region->current.blocks > md->data_blocks) {
606 : : /* No device region to process data */
607 [ # # ]: 0 : FTL_ERRLOG(md->dev, "Blocks number mismatch between metadata object and"
608 : : "device region\n");
609 : 0 : return -EINVAL;
610 : : }
611 : :
612 : 508 : return 0;
613 : : }
614 : :
615 : : static int
616 : 508 : io_prepare(struct ftl_md *md, enum ftl_md_ops op)
617 : : {
618 : 508 : const struct ftl_layout_region *region = md->region;
619 : 508 : uint64_t data_size, meta_size = 0;
620 : :
621 : : /* Allocates buffer for IO */
622 : 508 : data_size = xfer_size(md);
623 : 508 : md->io.data = spdk_zmalloc(data_size, FTL_BLOCK_SIZE, NULL,
624 : : SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
625 [ - + ]: 508 : if (!md->io.data) {
626 : 0 : return -ENOMEM;
627 : : }
628 : :
629 [ + + + + ]: 508 : if (md->vss_data || md->region->vss_blksz) {
630 : 404 : meta_size = ftl_md_xfer_blocks(md->dev) * FTL_MD_VSS_SZ;
631 : 404 : md->io.md = spdk_zmalloc(meta_size, FTL_BLOCK_SIZE, NULL,
632 : : SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
633 [ - + ]: 404 : if (!md->io.md) {
634 : 0 : spdk_dma_free(md->io.data);
635 : 0 : md->io.data = NULL;
636 : 0 : return -ENOMEM;
637 : : }
638 : : }
639 : :
640 : 508 : md->io.address = region->current.offset;
641 : 508 : md->io.remaining = region->current.blocks;
642 : 508 : md->io.data_offset = 0;
643 : 508 : md->io.status = 0;
644 : 508 : md->io.op = op;
645 : :
646 : 508 : return 0;
647 : : }
648 : :
649 : : static int
650 : 508 : io_init(struct ftl_md *md, enum ftl_md_ops op)
651 : : {
652 [ - + ]: 508 : if (io_can_start(md)) {
653 : 0 : return -EINVAL;
654 : : }
655 : :
656 [ - + ]: 508 : if (io_prepare(md, op)) {
657 : 0 : return -ENOMEM;
658 : : }
659 : :
660 : 508 : return 0;
661 : : }
662 : :
663 : : static uint64_t
664 : 6253 : persist_entry_lba(struct ftl_md *md, uint64_t start_entry)
665 : : {
666 : 6253 : return md->region->current.offset + start_entry * md->region->entry_size;
667 : : }
668 : :
669 : : static void
670 : 6253 : persist_entry_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
671 : : {
672 : 6253 : struct ftl_md_io_entry_ctx *ctx = cb_arg;
673 : 6253 : struct ftl_md *md = ctx->md;
674 : :
675 : 6253 : ftl_stats_bdev_io_completed(md->dev, get_bdev_io_ftl_stats_type(md->dev, bdev_io), bdev_io);
676 : :
677 : 6253 : spdk_bdev_free_io(bdev_io);
678 : :
679 [ - + ]: 6253 : assert(ctx->remaining > 0);
680 : 6253 : ctx->remaining--;
681 : :
682 [ - + ]: 6253 : if (!success) {
683 : 0 : ctx->status = -EIO;
684 : : }
685 : :
686 [ + + ]: 6253 : if (!ctx->remaining) {
687 : 6172 : ctx->cb(ctx->status, ctx->cb_arg);
688 : : }
689 : 6253 : }
690 : :
691 : : static int
692 : 6253 : ftl_md_persist_entry_write_blocks(struct ftl_md_io_entry_ctx *ctx, struct ftl_md *md,
693 : : spdk_bdev_io_wait_cb retry_fn)
694 : : {
695 : : int rc;
696 : :
697 : 6253 : rc = write_blocks(md->dev, md->region->bdev_desc, md->region->ioch,
698 : : ctx->buffer, ctx->vss_buffer,
699 : 6253 : persist_entry_lba(md, ctx->start_entry), md->region->entry_size,
700 : : persist_entry_cb, ctx);
701 [ - + ]: 6253 : if (spdk_unlikely(rc)) {
702 [ # # ]: 0 : if (rc == -ENOMEM) {
703 : 0 : struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(md->region->bdev_desc);
704 : 0 : ctx->bdev_io_wait.bdev = bdev;
705 : 0 : ctx->bdev_io_wait.cb_fn = retry_fn;
706 : 0 : ctx->bdev_io_wait.cb_arg = ctx;
707 : 0 : spdk_bdev_queue_io_wait(bdev, md->region->ioch, &ctx->bdev_io_wait);
708 : : } else {
709 : 0 : ftl_abort();
710 : : }
711 : : }
712 : :
713 : 6253 : return rc;
714 : : }
715 : :
716 : : static void
717 : 81 : ftl_md_persist_entry_mirror(void *_ctx)
718 : : {
719 : 81 : struct ftl_md_io_entry_ctx *ctx = _ctx;
720 : 81 : struct ftl_md *md_mirror = ftl_md_get_mirror(ctx->md);
721 : :
722 : 81 : ftl_md_persist_entry_write_blocks(ctx, md_mirror, ftl_md_persist_entry_mirror);
723 : 81 : }
724 : :
725 : : static void
726 : 6172 : ftl_md_persist_entry_primary(void *_ctx)
727 : : {
728 : 6172 : struct ftl_md_io_entry_ctx *ctx = _ctx;
729 : 6172 : struct ftl_md *md = ctx->md;
730 : : int rc;
731 : :
732 : 6172 : rc = ftl_md_persist_entry_write_blocks(ctx, md, ftl_md_persist_entry_primary);
733 : :
734 [ + - + + ]: 6172 : if (!rc && has_mirror(md)) {
735 [ - + ]: 81 : assert(md->region->entry_size == (ftl_md_get_mirror(md))->region->entry_size);
736 : :
737 : : /* The MD object has mirror so execute persist on it too */
738 : 81 : ftl_md_persist_entry_mirror(ctx);
739 : 81 : ctx->remaining++;
740 : : }
741 : 6172 : }
742 : :
743 : : static void
744 : 6172 : _ftl_md_persist_entry(struct ftl_md_io_entry_ctx *ctx)
745 : : {
746 : 6172 : ctx->status = 0;
747 : 6172 : ctx->remaining = 1;
748 : :
749 : : /* First execute an IO to the primary region */
750 : 6172 : ftl_md_persist_entry_primary(ctx);
751 : 6172 : }
752 : :
753 : : void
754 : 6172 : ftl_md_persist_entry(struct ftl_md *md, uint64_t start_entry, void *buffer, void *vss_buffer,
755 : : ftl_md_io_entry_cb cb, void *cb_arg,
756 : : struct ftl_md_io_entry_ctx *ctx)
757 : : {
758 [ - + ]: 6172 : if (spdk_unlikely(0 == md->region->entry_size)) {
759 : : /* This MD has not been configured to support persist entry call */
760 : 0 : ftl_abort();
761 : : }
762 : :
763 : : /* Initialize persist entry context */
764 : 6172 : ctx->cb = cb;
765 : 6172 : ctx->cb_arg = cb_arg;
766 : 6172 : ctx->md = md;
767 : 6172 : ctx->start_entry = start_entry;
768 : 6172 : ctx->buffer = buffer;
769 [ + + ]: 6172 : ctx->vss_buffer = vss_buffer ? : md->entry_vss_dma_buf;
770 : :
771 : 6172 : _ftl_md_persist_entry(ctx);
772 : 6172 : }
773 : :
774 : : static void
775 : 0 : read_entry_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
776 : : {
777 : 0 : struct ftl_md_io_entry_ctx *ctx = cb_arg;
778 : 0 : struct ftl_md *md = ctx->md;
779 : :
780 : 0 : ftl_stats_bdev_io_completed(md->dev, get_bdev_io_ftl_stats_type(md->dev, bdev_io), bdev_io);
781 : :
782 : 0 : spdk_bdev_free_io(bdev_io);
783 : :
784 [ # # ]: 0 : if (!success) {
785 [ # # ]: 0 : if (has_mirror(md)) {
786 : 0 : md->mirror_enabled = true;
787 : :
788 : : /* First read from the mirror */
789 : 0 : ftl_md_read_entry(ftl_md_get_mirror(md), ctx->start_entry, ctx->buffer,
790 : : ctx->vss_buffer,
791 : : ctx->cb, ctx->cb_arg,
792 : : ctx);
793 : 0 : return;
794 : : } else {
795 : 0 : ctx->status = -EIO;
796 : 0 : goto finish_io;
797 : : }
798 : : }
799 : :
800 : 0 : finish_io:
801 : 0 : ctx->cb(ctx->status, ctx->cb_arg);
802 : : }
803 : :
804 : : static void
805 : 0 : ftl_md_read_entry_read_blocks(struct ftl_md_io_entry_ctx *ctx, struct ftl_md *md,
806 : : spdk_bdev_io_wait_cb retry_fn)
807 : : {
808 : : int rc;
809 : :
810 : 0 : rc = read_blocks(md->dev, md->region->bdev_desc, md->region->ioch,
811 : : ctx->buffer, ctx->vss_buffer,
812 : 0 : persist_entry_lba(md, ctx->start_entry), md->region->entry_size,
813 : : read_entry_cb, ctx);
814 : :
815 [ # # ]: 0 : if (spdk_unlikely(rc)) {
816 [ # # ]: 0 : if (rc == -ENOMEM) {
817 : 0 : struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(md->region->bdev_desc);
818 : 0 : ctx->bdev_io_wait.bdev = bdev;
819 : 0 : ctx->bdev_io_wait.cb_fn = retry_fn;
820 : 0 : ctx->bdev_io_wait.cb_arg = ctx;
821 : 0 : spdk_bdev_queue_io_wait(bdev, md->region->ioch, &ctx->bdev_io_wait);
822 : : } else {
823 : 0 : ftl_abort();
824 : : }
825 : : }
826 : 0 : }
827 : :
828 : : static void
829 : 0 : _ftl_md_read_entry(void *_ctx)
830 : : {
831 : 0 : struct ftl_md_io_entry_ctx *ctx = _ctx;
832 : :
833 : 0 : ftl_md_read_entry_read_blocks(ctx, ctx->md, _ftl_md_read_entry);
834 : 0 : }
835 : :
836 : : void
837 : 0 : ftl_md_read_entry(struct ftl_md *md, uint64_t start_entry, void *buffer, void *vss_buffer,
838 : : ftl_md_io_entry_cb cb, void *cb_arg,
839 : : struct ftl_md_io_entry_ctx *ctx)
840 : : {
841 [ # # ]: 0 : if (spdk_unlikely(0 == md->region->entry_size)) {
842 : : /* This MD has not been configured to support read entry call */
843 : 0 : ftl_abort();
844 : : }
845 : :
846 : 0 : ctx->cb = cb;
847 : 0 : ctx->cb_arg = cb_arg;
848 : 0 : ctx->md = md;
849 : 0 : ctx->start_entry = start_entry;
850 : 0 : ctx->buffer = buffer;
851 : 0 : ctx->vss_buffer = vss_buffer;
852 : :
853 : 0 : _ftl_md_read_entry(ctx);
854 : 0 : }
855 : :
856 : : void
857 : 0 : ftl_md_persist_entry_retry(struct ftl_md_io_entry_ctx *ctx)
858 : : {
859 : 0 : _ftl_md_persist_entry(ctx);
860 : 0 : }
861 : :
862 : : static void
863 : 146 : persist_mirror_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status)
864 : : {
865 : 146 : struct ftl_md *primary = md->owner.private;
866 : :
867 [ - + ]: 146 : if (status) {
868 : : /* We got an error, stop persist procedure immediately */
869 : 0 : primary->io.status = status;
870 : 0 : io_done(primary);
871 : : } else {
872 : : /* Now continue the persist procedure on the primary MD object */
873 [ + - ]: 146 : if (0 == io_init(primary, FTL_MD_OP_PERSIST)) {
874 : 146 : io_submit(primary);
875 : : } else {
876 : 0 : spdk_thread_send_msg(spdk_get_thread(), exception, primary);
877 : : }
878 : : }
879 : 146 : }
880 : :
881 : : void
882 : 337 : ftl_md_persist(struct ftl_md *md)
883 : : {
884 [ + + ]: 337 : if (has_mirror(md)) {
885 : 146 : struct ftl_md *md_mirror = ftl_md_get_mirror(md);
886 : :
887 : 146 : md->mirror_enabled = true;
888 : :
889 : : /* Set callback and context in mirror */
890 : 146 : md_mirror->cb = persist_mirror_cb;
891 : 146 : md_mirror->owner.private = md;
892 : :
893 : : /* First persist the mirror */
894 : 146 : ftl_md_persist(md_mirror);
895 : 146 : return;
896 : : }
897 : :
898 [ + - ]: 191 : if (0 == io_init(md, FTL_MD_OP_PERSIST)) {
899 : 191 : io_submit(md);
900 : : } else {
901 : 0 : spdk_thread_send_msg(spdk_get_thread(), exception, md);
902 : : }
903 : : }
904 : :
905 : : static void
906 : 0 : restore_mirror_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status)
907 : : {
908 : 0 : struct ftl_md *primary = md->owner.private;
909 : :
910 [ # # ]: 0 : if (status) {
911 : : /* Cannot restore the object from the mirror too, mark error and fail */
912 : 0 : primary->io.status = -EIO;
913 : 0 : io_done(primary);
914 : : } else {
915 : : /*
916 : : * Restoring from the mirror successful. Synchronize mirror to the primary.
917 : : * Because we read MD content from the mirror, we can disable it, only the primary
918 : : * requires persisting.
919 : : */
920 : 0 : primary->io.status = 0;
921 : 0 : primary->mirror_enabled = false;
922 : 0 : io_cleanup(primary);
923 : 0 : ftl_md_persist(primary);
924 : 0 : primary->mirror_enabled = true;
925 : : }
926 : 0 : }
927 : :
928 : : static void
929 : 3 : restore_sync_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status)
930 : : {
931 : 3 : struct ftl_md *primary = md->owner.private;
932 : :
933 [ - + ]: 3 : if (status) {
934 : : /* Cannot sync the object from the primary to the mirror, mark error and fail */
935 : 0 : primary->io.status = -EIO;
936 : 0 : io_done(primary);
937 : : } else {
938 : 3 : primary->cb(dev, primary, primary->io.status);
939 : 3 : io_cleanup(primary);
940 : : }
941 : 3 : }
942 : :
943 : : static int
944 : 151 : restore_done(struct ftl_md *md)
945 : : {
946 [ - + ]: 151 : if (-EAGAIN == md->io.status) {
947 : : /* Failed to read MD from primary region, try it from mirror.
948 : : * At the moment read the mirror entirely, (TODO) in the
949 : : * feature we can restore from primary and mirror region
950 : : * with finer granularity.
951 : : */
952 : :
953 [ # # ]: 0 : if (has_mirror(md)) {
954 : 0 : struct ftl_md *md_mirror = ftl_md_get_mirror(md);
955 : :
956 : 0 : md->mirror_enabled = true;
957 : :
958 : : /* Set callback and context in mirror */
959 : 0 : md_mirror->cb = restore_mirror_cb;
960 : 0 : md_mirror->owner.private = md;
961 : :
962 : : /* First persist the mirror */
963 : 0 : ftl_md_restore(md_mirror);
964 : 0 : return -EAGAIN;
965 : : } else {
966 : 0 : return -EIO;
967 : : }
968 [ + - + + ]: 151 : } else if (0 == md->io.status && false == md->dev->sb->clean) {
969 [ + + ]: 7 : if (has_mirror(md)) {
970 : 3 : struct ftl_md *md_mirror = ftl_md_get_mirror(md);
971 : : /* There was a dirty shutdown, synchronize primary to mirror */
972 : :
973 : : /* Set callback and context in the mirror */
974 : 3 : md_mirror->cb = restore_sync_cb;
975 : 3 : md_mirror->owner.private = md;
976 : :
977 : : /* First persist the mirror */
978 : 3 : ftl_md_persist(md_mirror);
979 : 3 : return -EAGAIN;
980 : : }
981 : : }
982 : :
983 : 148 : return md->io.status;
984 : : }
985 : :
986 : : static void
987 : 508 : io_done(struct ftl_md *md)
988 : : {
989 : : int status;
990 : :
991 [ + + ]: 508 : if (md->io.op == FTL_MD_OP_RESTORE) {
992 : 151 : status = restore_done(md);
993 : : } else {
994 : 357 : status = md->io.status;
995 : : }
996 : :
997 [ + + ]: 508 : if (status != -EAGAIN) {
998 : : /* The MD instance may be destroyed in ctx of md->cb(), e.g. upon region upgrade. */
999 : : /* Need to cleanup DMA bufs first. */
1000 : 505 : io_cleanup(md);
1001 : 505 : md->cb(md->dev, md, status);
1002 : : }
1003 : 508 : }
1004 : :
1005 : : void
1006 : 151 : ftl_md_restore(struct ftl_md *md)
1007 : : {
1008 [ + - ]: 151 : if (0 == io_init(md, FTL_MD_OP_RESTORE)) {
1009 : 151 : io_submit(md);
1010 : : } else {
1011 : 0 : spdk_thread_send_msg(spdk_get_thread(), exception, md);
1012 : : }
1013 : 151 : }
1014 : :
1015 : : static int
1016 : 20 : pattern_prepare(struct ftl_md *md,
1017 : : int data_pattern, union ftl_md_vss *vss_pattern)
1018 : : {
1019 : 20 : void *data = md->io.data;
1020 : 20 : uint64_t data_size = xfer_size(md);
1021 : :
1022 [ - + ]: 20 : memset(data, data_pattern, data_size);
1023 : :
1024 [ + - ]: 20 : if (md->io.md) {
1025 [ + + ]: 20 : if (vss_pattern) {
1026 : : /* store the VSS pattern... */
1027 : 5 : ftl_md_vss_buf_init(md->io.md, ftl_md_xfer_blocks(md->dev), vss_pattern);
1028 : : } else {
1029 : : /* ...or default init VSS to 0 */
1030 : 15 : union ftl_md_vss vss = {0};
1031 : :
1032 : 15 : vss.version.md_version = md->region->current.version;
1033 : 15 : ftl_md_vss_buf_init(md->io.md, ftl_md_xfer_blocks(md->dev), &vss);
1034 : : }
1035 : : }
1036 : :
1037 : 20 : return 0;
1038 : : }
1039 : :
1040 : : static void
1041 : 5 : clear_mirror_cb(struct spdk_ftl_dev *dev, struct ftl_md *secondary, int status)
1042 : : {
1043 : 5 : struct ftl_md *primary = secondary->owner.private;
1044 : :
1045 [ - + ]: 5 : if (status) {
1046 : : /* We got an error, stop persist procedure immediately */
1047 : 0 : primary->io.status = status;
1048 : 0 : io_done(primary);
1049 : : } else {
1050 : : /* Now continue the persist procedure on the primary MD object */
1051 : 5 : io_submit(primary);
1052 : : }
1053 : 5 : }
1054 : :
1055 : : void
1056 : 20 : ftl_md_clear(struct ftl_md *md, int data_pattern, union ftl_md_vss *vss_pattern)
1057 : : {
1058 [ + + ]: 20 : if (has_mirror(md)) {
1059 : 5 : struct ftl_md *md_mirror = ftl_md_get_mirror(md);
1060 : :
1061 : 5 : md->mirror_enabled = true;
1062 : :
1063 : : /* Set callback and context in mirror */
1064 : 5 : md_mirror->cb = clear_mirror_cb;
1065 : 5 : md_mirror->owner.private = md;
1066 : :
1067 : : /* The pattern bufs will not be available outside of this fn context */
1068 : : /* Configure the IO for the primary region now */
1069 [ + - + - ]: 5 : if (0 == io_init(md, FTL_MD_OP_CLEAR) && 0 == pattern_prepare(md, data_pattern, vss_pattern)) {
1070 : : /* First persist the mirror */
1071 : 5 : ftl_md_clear(md_mirror, data_pattern, vss_pattern);
1072 : : } else {
1073 : 0 : spdk_thread_send_msg(spdk_get_thread(), exception, md);
1074 : : }
1075 : 5 : return;
1076 : : }
1077 : :
1078 [ + - + - ]: 15 : if (0 == io_init(md, FTL_MD_OP_CLEAR) && 0 == pattern_prepare(md, data_pattern, vss_pattern)) {
1079 : 15 : io_submit(md);
1080 : : } else {
1081 : 0 : spdk_thread_send_msg(spdk_get_thread(), exception, md);
1082 : : }
1083 : : }
1084 : :
1085 : : const struct ftl_layout_region *
1086 : 81 : ftl_md_get_region(struct ftl_md *md)
1087 : : {
1088 : 81 : return md->region;
1089 : : }
1090 : :
1091 : : void
1092 : 352 : ftl_md_set_region(struct ftl_md *md,
1093 : : const struct ftl_layout_region *region)
1094 : : {
1095 [ - + ]: 352 : assert(region->current.blocks <= md->data_blocks);
1096 : 352 : md->region = region;
1097 : :
1098 [ + + ]: 352 : if (md->vss_data) {
1099 : 176 : union ftl_md_vss vss = {0};
1100 : 176 : vss.version.md_version = region->current.version;
1101 : 176 : ftl_md_vss_buf_init(md->vss_data, md->data_blocks, &vss);
1102 [ + + ]: 176 : if (region->entry_size) {
1103 [ - + ]: 154 : assert(md->entry_vss_dma_buf);
1104 : 154 : ftl_md_vss_buf_init(md->entry_vss_dma_buf, region->entry_size, &vss);
1105 : : }
1106 : : }
1107 : :
1108 [ + + ]: 352 : if (has_mirror(md)) {
1109 : 88 : md->mirror_enabled = true;
1110 : : }
1111 : 352 : }
1112 : :
1113 : : int
1114 : 198 : ftl_md_create_region_flags(struct spdk_ftl_dev *dev, int region_type)
1115 : : {
1116 : 198 : int flags = FTL_MD_CREATE_SHM;
1117 : :
1118 [ + + + + ]: 198 : switch (region_type) {
1119 : 22 : case FTL_LAYOUT_REGION_TYPE_SB:
1120 [ + + ]: 22 : if (dev->conf.mode & SPDK_FTL_MODE_CREATE) {
1121 : 5 : flags |= FTL_MD_CREATE_SHM_NEW;
1122 : : }
1123 : 22 : break;
1124 : :
1125 : 44 : case FTL_LAYOUT_REGION_TYPE_BAND_MD:
1126 : : case FTL_LAYOUT_REGION_TYPE_NVC_MD:
1127 [ + - ]: 44 : if (!ftl_fast_startup(dev)) {
1128 : 44 : flags |= FTL_MD_CREATE_SHM_NEW;
1129 : : }
1130 : 44 : break;
1131 : 44 : case FTL_LAYOUT_REGION_TYPE_VALID_MAP:
1132 : : case FTL_LAYOUT_REGION_TYPE_TRIM_MD:
1133 [ + - + + ]: 44 : if (!ftl_fast_startup(dev) && !ftl_fast_recovery(dev)) {
1134 : 42 : flags |= FTL_MD_CREATE_SHM_NEW;
1135 : : }
1136 : 44 : break;
1137 : 88 : default:
1138 : 88 : return FTL_MD_CREATE_HEAP;
1139 : : }
1140 : :
1141 : 110 : return flags;
1142 : : }
1143 : :
1144 : : int
1145 : 440 : ftl_md_destroy_region_flags(struct spdk_ftl_dev *dev, int region_type)
1146 : : {
1147 [ + + ]: 440 : switch (region_type) {
1148 : 110 : case FTL_LAYOUT_REGION_TYPE_SB:
1149 : : case FTL_LAYOUT_REGION_TYPE_BAND_MD:
1150 : : case FTL_LAYOUT_REGION_TYPE_VALID_MAP:
1151 : : case FTL_LAYOUT_REGION_TYPE_NVC_MD:
1152 : : case FTL_LAYOUT_REGION_TYPE_TRIM_MD:
1153 [ - + - + ]: 110 : if (dev->conf.fast_shutdown) {
1154 : 0 : return FTL_MD_DESTROY_SHM_KEEP;
1155 : : }
1156 : 110 : break;
1157 : :
1158 : 330 : default:
1159 : 330 : break;
1160 : : }
1161 : 440 : return 0;
1162 : : }
1163 : :
1164 : : int
1165 : 110 : ftl_md_create_shm_flags(struct spdk_ftl_dev *dev)
1166 : : {
1167 : 110 : int flags = FTL_MD_CREATE_SHM;
1168 : :
1169 [ + - + + ]: 110 : if (!ftl_fast_startup(dev) && !ftl_fast_recovery(dev)) {
1170 : 105 : flags |= FTL_MD_CREATE_SHM_NEW;
1171 : : }
1172 : 110 : return flags;
1173 : : }
1174 : :
1175 : : int
1176 : 132 : ftl_md_destroy_shm_flags(struct spdk_ftl_dev *dev)
1177 : : {
1178 [ - + ]: 132 : return (dev->conf.fast_shutdown) ? FTL_MD_DESTROY_SHM_KEEP : 0;
1179 : : }
|