Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2022 Intel Corporation.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include "spdk/bdev_module.h"
7 : : #include "spdk/crc32.h"
8 : :
9 : : #include "ftl_internal.h"
10 : : #include "ftl_band.h"
11 : : #include "ftl_core.h"
12 : : #include "ftl_layout.h"
13 : : #include "ftl_nv_cache_io.h"
14 : : #include "ftl_writer.h"
15 : : #include "mngt/ftl_mngt.h"
16 : :
17 : : struct ftl_p2l_ckpt {
18 : : TAILQ_ENTRY(ftl_p2l_ckpt) link;
19 : : union ftl_md_vss *vss_md_page;
20 : : struct ftl_md *md;
21 : : struct ftl_layout_region *layout_region;
22 : : uint64_t num_pages;
23 : :
24 : : #if defined(DEBUG)
25 : : uint64_t dbg_bmp_sz;
26 : : void *dbg_bmp;
27 : : struct ftl_bitmap *bmp;
28 : : #endif
29 : : };
30 : :
31 : : static struct ftl_p2l_ckpt *
32 : 88 : ftl_p2l_ckpt_new(struct spdk_ftl_dev *dev, int region_type)
33 : : {
34 : : struct ftl_p2l_ckpt *ckpt;
35 : 88 : struct ftl_layout_region *region = ftl_layout_region_get(dev, region_type);
36 : :
37 : 88 : ckpt = calloc(1, sizeof(struct ftl_p2l_ckpt));
38 [ - + ]: 88 : if (!ckpt) {
39 : 0 : return NULL;
40 : : }
41 : :
42 : 88 : ckpt->vss_md_page = ftl_md_vss_buf_alloc(region, region->num_entries);
43 : 88 : ckpt->layout_region = region;
44 : 88 : ckpt->md = dev->layout.md[region_type];
45 : 88 : ckpt->num_pages = spdk_divide_round_up(ftl_get_num_blocks_in_band(dev), FTL_NUM_LBA_IN_BLOCK);
46 : :
47 [ - + ]: 88 : if (!ckpt->vss_md_page) {
48 : 0 : free(ckpt);
49 : 0 : return NULL;
50 : : }
51 : :
52 : : #if defined(DEBUG)
53 : : /* The bitmap size must be a multiple of word size (8b) - round up */
54 : 88 : ckpt->dbg_bmp_sz = spdk_divide_round_up(ckpt->num_pages, 8);
55 : :
56 : 88 : ckpt->dbg_bmp = calloc(1, ckpt->dbg_bmp_sz);
57 [ - + ]: 88 : assert(ckpt->dbg_bmp);
58 : 88 : ckpt->bmp = ftl_bitmap_create(ckpt->dbg_bmp, ckpt->dbg_bmp_sz);
59 [ - + ]: 88 : assert(ckpt->bmp);
60 : : #endif
61 : :
62 : 88 : return ckpt;
63 : : }
64 : :
65 : : static void
66 : 88 : ftl_p2l_ckpt_destroy(struct ftl_p2l_ckpt *ckpt)
67 : : {
68 : : #if defined(DEBUG)
69 : 88 : ftl_bitmap_destroy(ckpt->bmp);
70 : 88 : free(ckpt->dbg_bmp);
71 : : #endif
72 : 88 : spdk_dma_free(ckpt->vss_md_page);
73 : 88 : free(ckpt);
74 : 88 : }
75 : :
76 : : int
77 : 22 : ftl_p2l_ckpt_init(struct spdk_ftl_dev *dev)
78 : : {
79 : : int region_type;
80 : : struct ftl_p2l_ckpt *ckpt;
81 : :
82 : 22 : TAILQ_INIT(&dev->p2l_ckpt.free);
83 : 22 : TAILQ_INIT(&dev->p2l_ckpt.inuse);
84 [ # # ]: 22 : for (region_type = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MIN;
85 [ + + ]: 110 : region_type <= FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MAX;
86 : 88 : region_type++) {
87 : 88 : ckpt = ftl_p2l_ckpt_new(dev, region_type);
88 [ - + ]: 88 : if (!ckpt) {
89 : 0 : return -1;
90 : : }
91 : 88 : TAILQ_INSERT_TAIL(&dev->p2l_ckpt.free, ckpt, link);
92 : : }
93 : 22 : return 0;
94 : : }
95 : :
96 : : void
97 : 22 : ftl_p2l_ckpt_deinit(struct spdk_ftl_dev *dev)
98 : : {
99 : : struct ftl_p2l_ckpt *ckpt, *ckpt_next;
100 : :
101 [ + + ]: 105 : TAILQ_FOREACH_SAFE(ckpt, &dev->p2l_ckpt.free, link, ckpt_next) {
102 [ + + ]: 83 : TAILQ_REMOVE(&dev->p2l_ckpt.free, ckpt, link);
103 : 83 : ftl_p2l_ckpt_destroy(ckpt);
104 : : }
105 : :
106 [ + + ]: 27 : TAILQ_FOREACH_SAFE(ckpt, &dev->p2l_ckpt.inuse, link, ckpt_next) {
107 [ - + ]: 5 : TAILQ_REMOVE(&dev->p2l_ckpt.inuse, ckpt, link);
108 : 5 : ftl_p2l_ckpt_destroy(ckpt);
109 : : }
110 : 22 : }
111 : :
112 : : struct ftl_p2l_ckpt *
113 : 6 : ftl_p2l_ckpt_acquire(struct spdk_ftl_dev *dev)
114 : : {
115 : : struct ftl_p2l_ckpt *ckpt;
116 : :
117 : 6 : ckpt = TAILQ_FIRST(&dev->p2l_ckpt.free);
118 [ - + ]: 6 : assert(ckpt);
119 [ + - ]: 6 : TAILQ_REMOVE(&dev->p2l_ckpt.free, ckpt, link);
120 : 6 : TAILQ_INSERT_TAIL(&dev->p2l_ckpt.inuse, ckpt, link);
121 : 6 : return ckpt;
122 : : }
123 : :
124 : : void
125 : 4 : ftl_p2l_ckpt_release(struct spdk_ftl_dev *dev, struct ftl_p2l_ckpt *ckpt)
126 : : {
127 [ - + ]: 4 : assert(ckpt);
128 : : #if defined(DEBUG)
129 [ - + ]: 4 : memset(ckpt->dbg_bmp, 0, ckpt->dbg_bmp_sz);
130 : : #endif
131 [ + + ]: 4 : TAILQ_REMOVE(&dev->p2l_ckpt.inuse, ckpt, link);
132 : 4 : TAILQ_INSERT_TAIL(&dev->p2l_ckpt.free, ckpt, link);
133 : 4 : }
134 : :
135 : : static void
136 : 4615 : ftl_p2l_ckpt_issue_end(int status, void *arg)
137 : : {
138 : 4615 : struct ftl_rq *rq = arg;
139 [ - + ]: 4615 : assert(rq);
140 : :
141 [ - + ]: 4615 : if (status) {
142 : : #ifdef SPDK_FTL_RETRY_ON_ERROR
143 : : /* retry */
144 : : ftl_md_persist_entry_retry(&rq->md_persist_entry_ctx);
145 : : return;
146 : : #else
147 : 0 : ftl_abort();
148 : : #endif
149 : : }
150 : :
151 [ - + ]: 4615 : assert(rq->io.band->queue_depth > 0);
152 : 4615 : rq->io.band->queue_depth--;
153 : :
154 : 4615 : rq->owner.cb(rq);
155 : 4615 : }
156 : :
157 : : void
158 : 4615 : ftl_p2l_ckpt_issue(struct ftl_rq *rq)
159 : : {
160 : 4615 : struct ftl_rq_entry *iter = rq->entries;
161 : 4615 : ftl_addr addr = rq->io.addr;
162 : 4615 : struct ftl_p2l_ckpt *ckpt = NULL;
163 : : struct ftl_p2l_ckpt_page *map_page;
164 : : union ftl_md_vss *md_page;
165 : : struct ftl_band *band;
166 : : uint64_t band_offs, p2l_map_page_no, i;
167 : :
168 [ - + ]: 4615 : assert(rq);
169 : 4615 : band = rq->io.band;
170 : 4615 : ckpt = band->p2l_map.p2l_ckpt;
171 [ - + ]: 4615 : assert(ckpt);
172 : :
173 : : /* Derive the P2L map page no */
174 : 4615 : band_offs = ftl_band_block_offset_from_addr(band, rq->io.addr);
175 : 4615 : p2l_map_page_no = band_offs / FTL_NUM_LBA_IN_BLOCK;
176 [ - + ]: 4615 : assert((band_offs + rq->num_blocks - 1) / FTL_NUM_LBA_IN_BLOCK == p2l_map_page_no);
177 [ - + ]: 4615 : assert(p2l_map_page_no < ckpt->num_pages);
178 : :
179 : : /* Get the corresponding P2L map page - the underlying stored data is the same as in the end metadata of band P2L (ftl_p2l_map_entry),
180 : : * however we're interested in a whole page (4KiB) worth of content
181 : : */
182 : 4615 : map_page = ((struct ftl_p2l_ckpt_page *)band->p2l_map.band_map) + p2l_map_page_no;
183 [ - + ]: 4615 : assert(map_page);
184 : :
185 : : /* Set up the md */
186 : 4615 : md_page = &ckpt->vss_md_page[p2l_map_page_no];
187 : 4615 : md_page->p2l_ckpt.seq_id = band->md->seq;
188 [ - + ]: 4615 : assert(rq->num_blocks == FTL_NUM_LBA_IN_BLOCK);
189 : :
190 : : /* Update the band P2L map */
191 [ + + ]: 1186055 : for (i = 0; i < rq->num_blocks; i++, iter++) {
192 [ + + ]: 1181440 : if (iter->lba != FTL_LBA_INVALID) {
193 : : /* This is compaction or reloc */
194 [ - + ]: 922368 : assert(!ftl_addr_in_nvc(rq->dev, addr));
195 : 922368 : ftl_band_set_p2l(band, iter->lba, addr, iter->seq_id);
196 : : }
197 : 1181440 : addr = ftl_band_next_addr(band, addr, 1);
198 : : }
199 : :
200 : : #if defined(DEBUG)
201 : 4615 : ftl_bitmap_set(ckpt->bmp, p2l_map_page_no);
202 : : #endif
203 : :
204 : 4615 : md_page->p2l_ckpt.p2l_checksum = spdk_crc32c_update(map_page,
205 : 4615 : rq->num_blocks * sizeof(struct ftl_p2l_map_entry), 0);
206 : : /* Save the P2L map entry */
207 : 4615 : ftl_md_persist_entry(ckpt->md, p2l_map_page_no, map_page, md_page, ftl_p2l_ckpt_issue_end,
208 : : rq, &rq->md_persist_entry_ctx);
209 : 4615 : }
210 : :
211 : : #if defined(DEBUG)
212 : : static void
213 : 8 : ftl_p2l_validate_pages(struct ftl_band *band, struct ftl_p2l_ckpt *ckpt,
214 : : uint64_t page_begin, uint64_t page_end, bool val)
215 : : {
216 : : uint64_t page_no;
217 : :
218 [ + + ]: 4104 : for (page_no = page_begin; page_no < page_end; page_no++) {
219 [ - + ]: 4096 : assert(ftl_bitmap_get(ckpt->bmp, page_no) == val);
220 : : }
221 : 8 : }
222 : :
223 : : void
224 : 4 : ftl_p2l_validate_ckpt(struct ftl_band *band)
225 : : {
226 : 4 : struct ftl_p2l_ckpt *ckpt = band->p2l_map.p2l_ckpt;
227 : 4 : uint64_t num_blks_tail_md = ftl_tail_md_num_blocks(band->dev);
228 : 4 : uint64_t num_pages_tail_md = num_blks_tail_md / FTL_NUM_LBA_IN_BLOCK;
229 : :
230 [ - + ]: 4 : if (!ckpt) {
231 : 0 : return;
232 : : }
233 : :
234 [ - + ]: 4 : assert(num_blks_tail_md % FTL_NUM_LBA_IN_BLOCK == 0);
235 : :
236 : : /* all data pages written */
237 : 4 : ftl_p2l_validate_pages(band, ckpt,
238 : 4 : 0, ckpt->num_pages - num_pages_tail_md, true);
239 : :
240 : : /* tail md pages not written */
241 : 4 : ftl_p2l_validate_pages(band, ckpt, ckpt->num_pages - num_pages_tail_md,
242 : : ckpt->num_pages, false);
243 : : }
244 : : #endif
245 : :
246 : : static struct ftl_band *
247 : 88 : ftl_get_band_from_region(struct spdk_ftl_dev *dev, enum ftl_layout_region_type type)
248 : : {
249 : 88 : struct ftl_band *band = NULL;
250 : : uint64_t i;
251 : :
252 [ - + ]: 88 : assert(type >= FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MIN);
253 [ - + ]: 88 : assert(type <= FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MAX);
254 : :
255 [ + + ]: 7734 : for (i = 0; i < ftl_get_num_bands(dev); i++) {
256 : 7651 : band = &dev->bands[i];
257 [ + + ]: 7651 : if ((band->md->state == FTL_BAND_STATE_OPEN ||
258 [ - + ]: 7631 : band->md->state == FTL_BAND_STATE_FULL) &&
259 [ + + ]: 20 : band->md->p2l_md_region == type) {
260 : 5 : return band;
261 : : }
262 : : }
263 : :
264 : 83 : return NULL;
265 : : }
266 : :
267 : : static void ftl_mngt_persist_band_p2l(struct ftl_mngt_process *mngt, struct ftl_p2l_sync_ctx *ctx);
268 : :
269 : : static void
270 : 1518 : ftl_p2l_ckpt_persist_end(int status, void *arg)
271 : : {
272 : 1518 : struct ftl_mngt_process *mngt = arg;
273 : : struct ftl_p2l_sync_ctx *ctx;
274 : :
275 [ - + ]: 1518 : assert(mngt);
276 : :
277 [ - + ]: 1518 : if (status) {
278 : 0 : ftl_mngt_fail_step(mngt);
279 : 0 : return;
280 : : }
281 : :
282 : 1518 : ctx = ftl_mngt_get_step_ctx(mngt);
283 : 1518 : ctx->page_start++;
284 : :
285 [ + + ]: 1518 : if (ctx->page_start == ctx->page_end) {
286 : 5 : ctx->md_region++;
287 : 5 : ftl_mngt_continue_step(mngt);
288 : : } else {
289 : 1513 : ftl_mngt_persist_band_p2l(mngt, ctx);
290 : : }
291 : : }
292 : :
293 : : static void
294 : 1518 : ftl_mngt_persist_band_p2l(struct ftl_mngt_process *mngt, struct ftl_p2l_sync_ctx *ctx)
295 : : {
296 : 1518 : struct ftl_band *band = ctx->band;
297 : : union ftl_md_vss *md_page;
298 : : struct ftl_p2l_ckpt_page *map_page;
299 : : struct ftl_p2l_ckpt *ckpt;
300 : :
301 : 1518 : ckpt = band->p2l_map.p2l_ckpt;
302 : :
303 : 1518 : map_page = ((struct ftl_p2l_ckpt_page *)band->p2l_map.band_map) + ctx->page_start;
304 : :
305 : 1518 : md_page = &ckpt->vss_md_page[ctx->page_start];
306 : 1518 : md_page->p2l_ckpt.seq_id = band->md->seq;
307 : 1518 : md_page->p2l_ckpt.p2l_checksum = spdk_crc32c_update(map_page,
308 : : FTL_NUM_LBA_IN_BLOCK * sizeof(struct ftl_p2l_map_entry), 0);
309 : :
310 : : /* Save the P2L map entry */
311 : 1518 : ftl_md_persist_entry(ckpt->md, ctx->page_start, map_page, md_page,
312 : : ftl_p2l_ckpt_persist_end, mngt, &band->md_persist_entry_ctx);
313 : 1518 : }
314 : :
315 : : void
316 : 110 : ftl_mngt_persist_bands_p2l(struct ftl_mngt_process *mngt)
317 : : {
318 : 110 : struct ftl_p2l_sync_ctx *ctx = ftl_mngt_get_step_ctx(mngt);
319 : : struct ftl_band *band;
320 : : uint64_t band_offs, p2l_map_page_no;
321 : :
322 [ + + ]: 110 : if (ctx->md_region > FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MAX) {
323 : 22 : ftl_mngt_next_step(mngt);
324 : 22 : return;
325 : : }
326 : :
327 : 88 : band = ftl_get_band_from_region(ftl_mngt_get_dev(mngt), ctx->md_region);
328 : :
329 : : /* No band has the md region assigned (shutdown happened before next_band was assigned) */
330 [ + + ]: 88 : if (!band) {
331 : 83 : ctx->page_start = 0;
332 : 83 : ctx->page_end = 0;
333 : 83 : ctx->md_region++;
334 : 83 : ftl_mngt_continue_step(mngt);
335 : 83 : return;
336 : : }
337 : :
338 : 5 : band_offs = ftl_band_block_offset_from_addr(band, band->md->iter.addr);
339 : 5 : p2l_map_page_no = band_offs / FTL_NUM_LBA_IN_BLOCK;
340 : :
341 : 5 : ctx->page_start = 0;
342 : 5 : ctx->page_end = p2l_map_page_no;
343 : 5 : ctx->band = band;
344 : :
345 : : /* Band wasn't written to - no need to sync its P2L */
346 [ - + ]: 5 : if (ctx->page_end == 0) {
347 : 0 : ctx->md_region++;
348 : 0 : ftl_mngt_continue_step(mngt);
349 : 0 : return;
350 : : }
351 : :
352 : 5 : ftl_mngt_persist_band_p2l(mngt, ctx);
353 : : }
354 : :
355 : : uint64_t
356 : 4 : ftl_mngt_p2l_ckpt_get_seq_id(struct spdk_ftl_dev *dev, int md_region)
357 : : {
358 : 4 : struct ftl_layout *layout = &dev->layout;
359 : 4 : struct ftl_md *md = layout->md[md_region];
360 : 4 : union ftl_md_vss *page_md_buf = ftl_md_get_vss_buffer(md);
361 : 4 : uint64_t page_no, seq_id = 0;
362 : :
363 [ + + ]: 4100 : for (page_no = 0; page_no < layout->p2l.ckpt_pages; page_no++, page_md_buf++) {
364 [ + + ]: 4096 : if (seq_id < page_md_buf->p2l_ckpt.seq_id) {
365 : 3 : seq_id = page_md_buf->p2l_ckpt.seq_id;
366 : : }
367 : : }
368 : 4 : return seq_id;
369 : : }
370 : :
371 : : int
372 : 0 : ftl_mngt_p2l_ckpt_restore(struct ftl_band *band, uint32_t md_region, uint64_t seq_id)
373 : : {
374 : 0 : struct ftl_layout *layout = &band->dev->layout;
375 : 0 : struct ftl_md *md = layout->md[md_region];
376 : 0 : union ftl_md_vss *page_md_buf = ftl_md_get_vss_buffer(md);
377 : 0 : struct ftl_p2l_ckpt_page *page = ftl_md_get_buffer(md);
378 : : struct ftl_p2l_ckpt_page *map_page;
379 : 0 : uint64_t page_no, page_max = 0;
380 : 0 : bool page_found = false;
381 : :
382 [ # # ]: 0 : assert(band->md->p2l_md_region == md_region);
383 [ # # ]: 0 : if (band->md->p2l_md_region != md_region) {
384 : 0 : return -EINVAL;
385 : : }
386 : :
387 [ # # ]: 0 : assert(band->md->seq == seq_id);
388 [ # # ]: 0 : if (band->md->seq != seq_id) {
389 : 0 : return -EINVAL;
390 : : }
391 : :
392 [ # # ]: 0 : for (page_no = 0; page_no < layout->p2l.ckpt_pages; page_no++, page++, page_md_buf++) {
393 [ # # ]: 0 : if (page_md_buf->p2l_ckpt.seq_id != seq_id) {
394 : 0 : continue;
395 : : }
396 : :
397 : 0 : page_max = page_no;
398 : 0 : page_found = true;
399 : :
400 : : /* Get the corresponding P2L map page - the underlying stored data is the same as in the end metadata of band P2L (ftl_p2l_map_entry),
401 : : * however we're interested in a whole page (4KiB) worth of content
402 : : */
403 : 0 : map_page = ((struct ftl_p2l_ckpt_page *)band->p2l_map.band_map) + page_no;
404 : :
405 [ # # # # ]: 0 : if (page_md_buf->p2l_ckpt.p2l_checksum &&
406 : 0 : page_md_buf->p2l_ckpt.p2l_checksum != spdk_crc32c_update(page,
407 : : FTL_NUM_LBA_IN_BLOCK * sizeof(struct ftl_p2l_map_entry), 0)) {
408 : 0 : ftl_stats_crc_error(band->dev, FTL_STATS_TYPE_MD_NV_CACHE);
409 : 0 : return -EINVAL;
410 : : }
411 : :
412 : : /* Restore the page from P2L checkpoint */
413 : 0 : *map_page = *page;
414 : : }
415 : :
416 [ # # ]: 0 : assert(page_found);
417 [ # # ]: 0 : if (!page_found) {
418 : 0 : return -EINVAL;
419 : : }
420 : :
421 : : /* Restore check point in band P2L map */
422 : 0 : band->p2l_map.p2l_ckpt = ftl_p2l_ckpt_acquire_region_type(
423 : : band->dev, md_region);
424 : :
425 : : #ifdef DEBUG
426 : : /* Set check point valid map for validation */
427 : 0 : struct ftl_p2l_ckpt *ckpt = band->p2l_map.p2l_ckpt ;
428 [ # # ]: 0 : for (uint64_t i = 0; i <= page_max; i++) {
429 : 0 : ftl_bitmap_set(ckpt->bmp, i);
430 : : }
431 : : #endif
432 : :
433 : 0 : ftl_band_iter_init(band);
434 : 0 : ftl_band_iter_set(band, (page_max + 1) * FTL_NUM_LBA_IN_BLOCK);
435 : :
436 : 0 : return 0;
437 : : }
438 : :
439 : : enum ftl_layout_region_type
440 : 6 : ftl_p2l_ckpt_region_type(const struct ftl_p2l_ckpt *ckpt) {
441 : 6 : return ckpt->layout_region->type;
442 : : }
443 : :
444 : : struct ftl_p2l_ckpt *
445 : 3 : ftl_p2l_ckpt_acquire_region_type(struct spdk_ftl_dev *dev, uint32_t region_type)
446 : : {
447 : 3 : struct ftl_p2l_ckpt *ckpt = NULL;
448 : :
449 [ + - ]: 4 : TAILQ_FOREACH(ckpt, &dev->p2l_ckpt.free, link) {
450 [ + + ]: 4 : if (ckpt->layout_region->type == region_type) {
451 : 3 : break;
452 : : }
453 : : }
454 : :
455 [ - + ]: 3 : assert(ckpt);
456 : :
457 [ + - ]: 3 : TAILQ_REMOVE(&dev->p2l_ckpt.free, ckpt, link);
458 : 3 : TAILQ_INSERT_TAIL(&dev->p2l_ckpt.inuse, ckpt, link);
459 : :
460 : 3 : return ckpt;
461 : : }
462 : :
463 : : int
464 : 3 : ftl_mngt_p2l_ckpt_restore_clean(struct ftl_band *band)
465 : : {
466 : 3 : struct spdk_ftl_dev *dev = band->dev;
467 : 3 : struct ftl_layout *layout = &dev->layout;
468 : : struct ftl_p2l_ckpt_page *page, *map_page;
469 : 3 : enum ftl_layout_region_type md_region = band->md->p2l_md_region;
470 : : uint64_t page_no;
471 : : uint64_t num_written_pages;
472 : : union ftl_md_vss *page_md_buf;
473 : :
474 [ + - - + ]: 3 : if (md_region < FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MIN ||
475 : : md_region > FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MAX) {
476 : 0 : return -EINVAL;
477 : : }
478 : :
479 [ - + ]: 3 : assert(band->md->iter.offset % FTL_NUM_LBA_IN_BLOCK == 0);
480 : 3 : num_written_pages = band->md->iter.offset / FTL_NUM_LBA_IN_BLOCK;
481 : :
482 : : /* Associate band with md region before shutdown */
483 [ + - ]: 3 : if (!band->p2l_map.p2l_ckpt) {
484 : 3 : band->p2l_map.p2l_ckpt = ftl_p2l_ckpt_acquire_region_type(dev, md_region);
485 : : }
486 : :
487 : : /* Band was opened but no data was written */
488 [ - + ]: 3 : if (band->md->iter.offset == 0) {
489 : 0 : return 0;
490 : : }
491 : :
492 : 3 : page_no = 0;
493 : :
494 : : /* Restore P2L map up to last written page */
495 : 3 : page_md_buf = ftl_md_get_vss_buffer(layout->md[md_region]);
496 : 3 : page = ftl_md_get_buffer(layout->md[md_region]);
497 : :
498 [ + + ]: 986 : for (; page_no < num_written_pages; page_no++, page++, page_md_buf++) {
499 [ - + ]: 983 : if (page_md_buf->p2l_ckpt.seq_id != band->md->seq) {
500 [ # # ]: 0 : assert(page_md_buf->p2l_ckpt.seq_id == band->md->seq);
501 : : }
502 : :
503 : : /* Get the corresponding P2L map page */
504 : 983 : map_page = ((struct ftl_p2l_ckpt_page *)band->p2l_map.band_map) + page_no;
505 : :
506 : : /* Restore the page from P2L checkpoint */
507 : 983 : *map_page = *page;
508 : :
509 : : #if defined(DEBUG)
510 [ - + ]: 983 : assert(ftl_bitmap_get(band->p2l_map.p2l_ckpt->bmp, page_no) == false);
511 : 983 : ftl_bitmap_set(band->p2l_map.p2l_ckpt->bmp, page_no);
512 : : #endif
513 : : }
514 : :
515 [ - + ]: 3 : assert(page_md_buf->p2l_ckpt.seq_id < band->md->seq);
516 : :
517 : 3 : return 0;
518 : : }
519 : :
520 : : void
521 : 0 : ftl_mngt_p2l_ckpt_restore_shm_clean(struct ftl_band *band)
522 : : {
523 : 0 : struct spdk_ftl_dev *dev = band->dev;
524 : 0 : enum ftl_layout_region_type md_region = band->md->p2l_md_region;
525 : :
526 : : /* Associate band with md region before shutdown */
527 [ # # ]: 0 : if (!band->p2l_map.p2l_ckpt) {
528 : 0 : band->p2l_map.p2l_ckpt = ftl_p2l_ckpt_acquire_region_type(dev, md_region);
529 : : }
530 : :
531 : : #if defined(DEBUG)
532 : : uint64_t page_no;
533 : : uint64_t num_written_pages;
534 : :
535 [ # # ]: 0 : assert(band->md->iter.offset % FTL_NUM_LBA_IN_BLOCK == 0);
536 : 0 : num_written_pages = band->md->iter.offset / FTL_NUM_LBA_IN_BLOCK;
537 : :
538 : : /* Band was opened but no data was written */
539 [ # # ]: 0 : if (band->md->iter.offset == 0) {
540 : 0 : return;
541 : : }
542 : :
543 : : /* Set page number to first data page - skip head md */
544 : 0 : page_no = 0;
545 : :
546 [ # # ]: 0 : for (; page_no < num_written_pages; page_no++) {
547 [ # # ]: 0 : assert(ftl_bitmap_get(band->p2l_map.p2l_ckpt->bmp, page_no) == false);
548 : 0 : ftl_bitmap_set(band->p2l_map.p2l_ckpt->bmp, page_no);
549 : : }
550 : : #endif
551 : : }
|