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