Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright 2023 Solidigm All Rights Reserved
3 : : */
4 : :
5 : : #include "ftl_core.h"
6 : : #include "ftl_io.h"
7 : : #include "ftl_layout.h"
8 : : #include "utils/ftl_defs.h"
9 : :
10 : : struct ftl_pl2_log_item {
11 : : uint64_t lba;
12 : : uint64_t num_blocks;
13 : : uint64_t seq_id;
14 : : ftl_addr addr;
15 : : };
16 : : #define FTL_P2L_LOG_ITEMS_IN_PAGE ((FTL_BLOCK_SIZE - sizeof(union ftl_md_vss)) / sizeof(struct ftl_pl2_log_item))
17 : : #define FTL_P2L_LOG_PAGE_COUNT_DEFAULT 128
18 : :
19 : : struct ftl_p2l_log_page {
20 : : union ftl_md_vss hdr;
21 : : struct ftl_pl2_log_item items[FTL_P2L_LOG_ITEMS_IN_PAGE];
22 : : };
23 : : SPDK_STATIC_ASSERT(sizeof(struct ftl_p2l_log_page) == FTL_BLOCK_SIZE, "Invalid size of P2L page");
24 : :
25 : : struct ftl_p2l_log_page_ctrl {
26 : : struct ftl_p2l_log_page page;
27 : : struct ftl_p2l_log *p2l;
28 : : uint64_t entry_idx;
29 : : TAILQ_HEAD(, ftl_io) ios;
30 : : struct ftl_md_io_entry_ctx md_ctx;
31 : : };
32 : :
33 : : struct ftl_p2l_log {
34 : : struct spdk_ftl_dev *dev;
35 : : TAILQ_ENTRY(ftl_p2l_log) link;
36 : : TAILQ_HEAD(, ftl_io) ios;
37 : : struct ftl_md *md;
38 : : uint64_t seq_id;
39 : : struct ftl_mempool *page_pool;
40 : : uint64_t entry_idx;
41 : : uint64_t entry_max;
42 : : ftl_p2l_log_cb cb_fn;
43 : : uint32_t ref_cnt;
44 : : bool in_use;
45 : :
46 : : struct {
47 : : spdk_ftl_fn cb_fn;
48 : : void *cb_arg;
49 : : ftl_p2l_log_rd_cb cb_rd;
50 : : uint64_t qd;
51 : : uint64_t idx;
52 : : uint64_t seq_id;
53 : : int result;
54 : : } read_ctx;
55 : : };
56 : :
57 : : static void p2l_log_page_io(struct ftl_p2l_log *p2l, struct ftl_p2l_log_page_ctrl *ctrl);
58 : : static void ftl_p2l_log_read_process(struct ftl_p2l_log *p2l);
59 : :
60 : : static struct ftl_p2l_log *
61 : 0 : p2l_log_create(struct spdk_ftl_dev *dev, uint32_t region_type)
62 : : {
63 : : struct ftl_p2l_log *p2l;
64 : :
65 : 0 : p2l = calloc(1, sizeof(struct ftl_p2l_log));
66 [ # # ]: 0 : if (!p2l) {
67 : 0 : return NULL;
68 : : }
69 : :
70 [ # # # # : 0 : TAILQ_INIT(&p2l->ios);
# # # # #
# # # # #
# # ]
71 [ # # # # ]: 0 : p2l->dev = dev;
72 [ # # # # : 0 : p2l->md = dev->layout.md[region_type];
# # # # #
# # # ]
73 [ # # # # : 0 : p2l->entry_max = ftl_md_get_buffer_size(p2l->md) / FTL_BLOCK_SIZE;
# # # # #
# ]
74 [ # # # # ]: 0 : p2l->page_pool = ftl_mempool_create(FTL_P2L_LOG_PAGE_COUNT_DEFAULT,
75 : : sizeof(struct ftl_p2l_log_page_ctrl),
76 : : FTL_BLOCK_SIZE, SPDK_ENV_SOCKET_ID_ANY);
77 [ # # # # : 0 : if (!p2l->page_pool) {
# # ]
78 : 0 : goto ERROR;
79 : : }
80 : :
81 : 0 : return p2l;
82 : 0 : ERROR:
83 : 0 : free(p2l);
84 : 0 : return NULL;
85 : 0 : }
86 : :
87 : : static void
88 : 0 : p2l_log_destroy(struct ftl_p2l_log *p2l)
89 : : {
90 [ # # ]: 0 : if (!p2l) {
91 : 0 : return;
92 : : }
93 : :
94 [ # # # # ]: 0 : ftl_mempool_destroy(p2l->page_pool);
95 : 0 : free(p2l);
96 : 0 : }
97 : :
98 : : static struct ftl_p2l_log_page_ctrl *
99 : 0 : p2l_log_get_page(struct ftl_p2l_log *p2l)
100 : : {
101 : : struct ftl_p2l_log_page_ctrl *ctrl;
102 : :
103 [ # # # # ]: 0 : ctrl = ftl_mempool_get(p2l->page_pool);
104 [ # # ]: 0 : if (!ctrl) {
105 : 0 : return NULL;
106 : : }
107 : :
108 : : /* Initialize P2L header */
109 [ # # # # : 0 : ctrl->page.hdr.p2l_ckpt.seq_id = p2l->seq_id;
# # # # #
# # # #
# ]
110 [ # # # # : 0 : ctrl->page.hdr.p2l_ckpt.count = 0;
# # # # #
# ]
111 [ # # # # : 0 : ctrl->page.hdr.p2l_ckpt.p2l_checksum = 0;
# # # # #
# ]
112 [ # # # # : 0 : ctrl->page.hdr.p2l_ckpt.idx = ctrl->entry_idx = p2l->entry_idx;
# # # # #
# # # # #
# # # # ]
113 : :
114 : : /* Initialize the page control structure */
115 [ # # # # ]: 0 : ctrl->p2l = p2l;
116 [ # # # # : 0 : TAILQ_INIT(&ctrl->ios);
# # # # #
# # # # #
# # ]
117 : :
118 : : /* Increase P2L page index */
119 [ # # ]: 0 : p2l->entry_idx++;
120 : :
121 : : /* Check if the index exceeding the buffer size */
122 [ # # # # : 0 : ftl_bug(p2l->entry_idx > p2l->entry_max);
# # # # #
# # # ]
123 : :
124 : 0 : return ctrl;
125 : 0 : }
126 : :
127 : : static bool
128 : 0 : l2p_log_page_is_full(struct ftl_p2l_log_page_ctrl *ctrl)
129 : : {
130 [ # # # # : 0 : return ctrl->page.hdr.p2l_ckpt.count == FTL_P2L_LOG_ITEMS_IN_PAGE;
# # # # #
# ]
131 : : }
132 : :
133 : : static void
134 : 0 : p2l_log_page_free(struct ftl_p2l_log *p2l, struct ftl_p2l_log_page_ctrl *ctrl)
135 : : {
136 [ # # # # ]: 0 : ftl_mempool_put(p2l->page_pool, ctrl);
137 : 0 : }
138 : :
139 : : static void
140 : 0 : p2l_log_handle_io_error(struct ftl_p2l_log *p2l, struct ftl_p2l_log_page_ctrl *ctrl)
141 : : {
142 : : #ifdef SPDK_FTL_RETRY_ON_ERROR
143 : : p2l_log_page_io(p2l, ctrl);
144 : : #else
145 [ # # ]: 0 : ftl_abort();
146 : : #endif
147 : 0 : }
148 : :
149 : : static uint32_t
150 : 0 : p2l_log_page_crc(struct ftl_p2l_log_page *page)
151 : : {
152 : 0 : uint32_t crc = 0;
153 : 0 : void *buffer = page;
154 : 0 : size_t size = sizeof(*page);
155 : 0 : size_t offset = offsetof(struct ftl_p2l_log_page, hdr.p2l_ckpt.p2l_checksum);
156 : :
157 : 0 : crc = spdk_crc32c_update(buffer, offset, crc);
158 : 0 : buffer += offset + sizeof(page->hdr.p2l_ckpt.p2l_checksum);
159 : 0 : size -= offset + sizeof(page->hdr.p2l_ckpt.p2l_checksum);
160 : :
161 : 0 : return spdk_crc32c_update(buffer, size, crc);
162 : : }
163 : :
164 : : static void
165 : 0 : p2l_log_page_io_cb(int status, void *arg)
166 : : {
167 : 0 : struct ftl_p2l_log_page_ctrl *ctrl = arg;
168 [ # # # # ]: 0 : struct ftl_p2l_log *p2l = ctrl->p2l;
169 : : struct ftl_io *io;
170 : :
171 [ # # ]: 0 : if (status) {
172 : 0 : p2l_log_handle_io_error(p2l, ctrl);
173 : 0 : return;
174 : : }
175 : :
176 [ # # # # : 0 : while ((io = TAILQ_FIRST(&ctrl->ios))) {
# # # # ]
177 [ # # # # : 0 : TAILQ_REMOVE(&ctrl->ios, io, queue_entry);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
178 [ # # # # : 0 : p2l->cb_fn(io);
# # # # ]
179 : : }
180 : :
181 : 0 : p2l_log_page_free(p2l, ctrl);
182 : 0 : }
183 : :
184 : : static void
185 : 0 : p2l_log_page_io(struct ftl_p2l_log *p2l, struct ftl_p2l_log_page_ctrl *ctrl)
186 : : {
187 [ # # # # : 0 : ctrl->page.hdr.p2l_ckpt.p2l_checksum = p2l_log_page_crc(&ctrl->page);
# # # # #
# # # ]
188 : :
189 [ # # # # : 0 : ftl_md_persist_entries(p2l->md, ctrl->page.hdr.p2l_ckpt.idx, 1, &ctrl->page, NULL,
# # # # #
# # # # #
# # ]
190 : : p2l_log_page_io_cb,
191 [ # # ]: 0 : ctrl, &ctrl->md_ctx);
192 : 0 : }
193 : :
194 : : static void
195 : 0 : p2l_log_add_io(struct ftl_p2l_log *p2l, struct ftl_p2l_log_page_ctrl *ctrl, struct ftl_io *io)
196 : : {
197 [ # # # # : 0 : uint64_t i = ctrl->page.hdr.p2l_ckpt.count++;
# # # # ]
198 : :
199 [ # # # # ]: 0 : assert(i < FTL_P2L_LOG_ITEMS_IN_PAGE);
200 [ # # # # : 0 : ctrl->page.items[i].lba = io->lba;
# # # # #
# # # #
# ]
201 [ # # # # : 0 : ctrl->page.items[i].num_blocks = io->num_blocks;
# # # # #
# # # #
# ]
202 [ # # # # : 0 : ctrl->page.items[i].seq_id = io->nv_cache_chunk->md->seq_id;
# # # # #
# # # # #
# # # # #
# # # ]
203 [ # # # # : 0 : ctrl->page.items[i].addr = io->addr;
# # # # #
# # # #
# ]
204 : :
205 : : /* TODO Make sure P2L map is updated respectively */
206 : :
207 [ # # # # : 0 : TAILQ_REMOVE(&p2l->ios, io, queue_entry);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
208 [ # # # # : 0 : TAILQ_INSERT_TAIL(&ctrl->ios, io, queue_entry);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
209 : 0 : }
210 : :
211 : : void
212 : 0 : ftl_p2l_log_io(struct ftl_p2l_log *p2l, struct ftl_io *io)
213 : : {
214 [ # # # # : 0 : TAILQ_INSERT_TAIL(&p2l->ios, io, queue_entry);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
215 : 0 : }
216 : :
217 : : static void
218 : 0 : p2l_log_flush(struct ftl_p2l_log *p2l)
219 : : {
220 : 0 : struct ftl_p2l_log_page_ctrl *ctrl = NULL;
221 : : struct ftl_io *io;
222 : :
223 [ # # # # : 0 : while ((io = TAILQ_FIRST(&p2l->ios))) {
# # # # ]
224 [ # # ]: 0 : if (!ctrl) {
225 : 0 : ctrl = p2l_log_get_page(p2l);
226 [ # # ]: 0 : if (!ctrl) {
227 : : /* No page at the moment, try next time */
228 : 0 : break;
229 : : }
230 : 0 : }
231 : :
232 : 0 : p2l_log_add_io(p2l, ctrl, io);
233 : :
234 [ # # ]: 0 : if (l2p_log_page_is_full(ctrl)) {
235 : 0 : p2l_log_page_io(p2l, ctrl);
236 : 0 : ctrl = NULL;
237 : 0 : }
238 : : }
239 : :
240 [ # # ]: 0 : if (ctrl) {
241 : 0 : p2l_log_page_io(p2l, ctrl);
242 : 0 : }
243 : 0 : }
244 : :
245 : : void
246 : 0 : ftl_p2l_log_flush(struct spdk_ftl_dev *dev)
247 : : {
248 : : struct ftl_p2l_log *p2l;
249 : :
250 [ # # # # : 0 : TAILQ_FOREACH(p2l, &dev->p2l_ckpt.log.inuse, link) {
# # # # #
# # # # #
# # # # ]
251 : 0 : p2l_log_flush(p2l);
252 : 0 : }
253 : 0 : }
254 : :
255 : : uint64_t
256 : 0 : ftl_p2l_log_get_md_blocks_required(struct spdk_ftl_dev *dev, uint64_t write_unit_blocks,
257 : : uint64_t max_user_data_blocks)
258 : : {
259 : 0 : return spdk_divide_round_up(max_user_data_blocks, write_unit_blocks);
260 : : }
261 : :
262 : : int
263 : 0 : ftl_p2l_log_init(struct spdk_ftl_dev *dev)
264 : : {
265 : : struct ftl_p2l_log *p2l;
266 : : uint32_t region_type;
267 : :
268 [ # # # # : 0 : TAILQ_INIT(&dev->p2l_ckpt.log.free);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
269 [ # # # # : 0 : TAILQ_INIT(&dev->p2l_ckpt.log.inuse);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
270 : :
271 [ # # ]: 0 : for (region_type = FTL_LAYOUT_REGION_TYPE_P2L_LOG_IO_MIN;
272 [ # # ]: 0 : region_type <= FTL_LAYOUT_REGION_TYPE_P2L_LOG_IO_MAX;
273 : 0 : region_type++) {
274 : 0 : p2l = p2l_log_create(dev, region_type);
275 [ # # ]: 0 : if (!p2l) {
276 : 0 : return -ENOMEM;
277 : : }
278 : :
279 [ # # # # : 0 : TAILQ_INSERT_TAIL(&dev->p2l_ckpt.log.free, p2l, link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
280 : 0 : }
281 : :
282 : 0 : return 0;
283 : 0 : }
284 : :
285 : : void
286 : 0 : ftl_p2l_log_deinit(struct spdk_ftl_dev *dev)
287 : : {
288 : : struct ftl_p2l_log *p2l, *p2l_next;
289 : :
290 [ # # # # : 0 : TAILQ_FOREACH_SAFE(p2l, &dev->p2l_ckpt.log.free, link, p2l_next) {
# # # # #
# # # # #
# # # # #
# ]
291 [ # # # # : 0 : TAILQ_REMOVE(&dev->p2l_ckpt.log.free, p2l, link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
292 : 0 : p2l_log_destroy(p2l);
293 : 0 : }
294 : :
295 [ # # # # : 0 : TAILQ_FOREACH_SAFE(p2l, &dev->p2l_ckpt.log.inuse, link, p2l_next) {
# # # # #
# # # # #
# # # # #
# ]
296 [ # # # # : 0 : TAILQ_REMOVE(&dev->p2l_ckpt.log.inuse, p2l, link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
297 : 0 : p2l_log_destroy(p2l);
298 : 0 : }
299 : 0 : }
300 : :
301 : : enum ftl_layout_region_type
302 : 0 : ftl_p2l_log_type(struct ftl_p2l_log *p2l) {
303 [ # # # # : 0 : return p2l->md->region->type;
# # # # #
# # # ]
304 : : }
305 : :
306 : : struct ftl_p2l_log *
307 : 0 : ftl_p2l_log_acquire(struct spdk_ftl_dev *dev, uint64_t seq_id, ftl_p2l_log_cb cb)
308 : : {
309 : : struct ftl_p2l_log *p2l;
310 : :
311 [ # # # # : 0 : p2l = TAILQ_FIRST(&dev->p2l_ckpt.log.free);
# # # # #
# ]
312 [ # # # # ]: 0 : assert(p2l);
313 [ # # # # : 0 : TAILQ_REMOVE(&dev->p2l_ckpt.log.free, p2l, link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
314 [ # # # # : 0 : TAILQ_INSERT_TAIL(&dev->p2l_ckpt.log.inuse, p2l, link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
315 : :
316 [ # # # # ]: 0 : p2l->entry_idx = 0;
317 [ # # # # ]: 0 : p2l->seq_id = seq_id;
318 [ # # # # ]: 0 : p2l->cb_fn = cb;
319 : :
320 : 0 : return p2l;
321 : : }
322 : :
323 : : void
324 : 0 : ftl_p2l_log_release(struct spdk_ftl_dev *dev, struct ftl_p2l_log *p2l)
325 : : {
326 [ # # # # ]: 0 : assert(p2l);
327 : :
328 : : /* TODO: Add assert if no ongoing IOs on the P2L log */
329 : : /* TODO: Add assert if the P2L log already open */
330 : :
331 [ # # # # : 0 : TAILQ_REMOVE(&dev->p2l_ckpt.log.inuse, p2l, link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
332 [ # # # # : 0 : TAILQ_INSERT_TAIL(&dev->p2l_ckpt.log.free, p2l, link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
333 : 0 : }
334 : :
335 : : static struct ftl_p2l_log *
336 : 0 : p2l_log_get(struct spdk_ftl_dev *dev, enum ftl_layout_region_type type)
337 : : {
338 : : struct ftl_p2l_log *p2l_Log;
339 : :
340 [ # # # # : 0 : TAILQ_FOREACH(p2l_Log, &dev->p2l_ckpt.log.free, link) {
# # # # #
# # # # #
# # # # ]
341 [ # # # # : 0 : if (type == p2l_Log->md->region->type) {
# # # # #
# # # #
# ]
342 : 0 : return p2l_Log;
343 : : }
344 : 0 : }
345 : :
346 [ # # # # : 0 : TAILQ_FOREACH(p2l_Log, &dev->p2l_ckpt.log.inuse, link) {
# # # # #
# # # # #
# # # # ]
347 [ # # # # : 0 : if (type == p2l_Log->md->region->type) {
# # # # #
# # # #
# ]
348 : 0 : return p2l_Log;
349 : : }
350 : 0 : }
351 : :
352 : 0 : return NULL;
353 : 0 : }
354 : :
355 : : static bool
356 : 0 : p2l_log_read_in_progress(struct ftl_p2l_log *p2l)
357 : : {
358 [ # # # # : 0 : return p2l->read_ctx.cb_fn ? true : false;
# # ]
359 : : }
360 : :
361 : : static bool
362 : 0 : ftl_p2l_log_read_is_next(struct ftl_p2l_log *p2l)
363 : : {
364 [ # # # # : 0 : if (p2l->read_ctx.result) {
# # # # ]
365 : 0 : return false;
366 : : }
367 : :
368 [ # # # # : 0 : return p2l->read_ctx.idx < p2l->entry_max;
# # # # #
# ]
369 : 0 : }
370 : :
371 : : static bool
372 : 0 : ftl_p2l_log_read_is_qd(struct ftl_p2l_log *p2l)
373 : : {
374 [ # # # # : 0 : return p2l->read_ctx.qd > 0;
# # ]
375 : : }
376 : :
377 : : static bool
378 : 0 : ftl_p2l_log_read_is_finished(struct ftl_p2l_log *p2l)
379 : : {
380 [ # # # # ]: 0 : if (ftl_p2l_log_read_is_next(p2l) || ftl_p2l_log_read_is_qd(p2l)) {
381 : 0 : return false;
382 : : }
383 : :
384 : 0 : return true;
385 : 0 : }
386 : :
387 : : static void
388 : 0 : ftl_p2l_log_read_finish(struct ftl_p2l_log *p2l)
389 : : {
390 [ # # # # : 0 : spdk_ftl_fn cb_fn = p2l->read_ctx.cb_fn;
# # ]
391 [ # # # # : 0 : void *cb_arg = p2l->read_ctx.cb_arg;
# # ]
392 [ # # # # : 0 : int result = p2l->read_ctx.result;
# # ]
393 : :
394 [ # # # # ]: 0 : memset(&p2l->read_ctx, 0, sizeof(p2l->read_ctx));
395 [ # # # # ]: 0 : cb_fn(cb_arg, result);
396 : 0 : }
397 : :
398 : : static void
399 : 0 : ftl_p2l_log_read_visit(struct ftl_p2l_log *p2l, struct ftl_p2l_log_page_ctrl *ctrl)
400 : : {
401 [ # # ]: 0 : struct ftl_p2l_log_page *page = &ctrl->page;
402 [ # # # # ]: 0 : struct spdk_ftl_dev *dev = p2l->dev;
403 [ # # # # : 0 : ftl_p2l_log_rd_cb cb_rd = p2l->read_ctx.cb_rd;
# # ]
404 [ # # # # : 0 : void *cb_arg = p2l->read_ctx.cb_arg;
# # ]
405 [ # # ]: 0 : uint64_t crc = p2l_log_page_crc(&ctrl->page);
406 : : uint64_t i, j;
407 : 0 : int rc = 0;
408 : :
409 [ # # # # : 0 : ftl_bug(ctrl->entry_idx > p2l->entry_max);
# # # # #
# # # ]
410 : :
411 [ # # # # : 0 : if (p2l->read_ctx.seq_id != page->hdr.p2l_ckpt.seq_id) {
# # # # #
# # # # #
# # ]
412 : : /* This page contains entires older than the owner's sequence ID */
413 : 0 : return;
414 : : }
415 : :
416 [ # # # # : 0 : if (ctrl->entry_idx != page->hdr.p2l_ckpt.idx) {
# # # # #
# # # #
# ]
417 [ # # # # : 0 : FTL_ERRLOG(p2l->dev, "Read P2L IO Logs ERROR, invalid index, type %d\n",
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
418 : : p2l->md->region->type);
419 [ # # # # : 0 : p2l->read_ctx.result = -EINVAL;
# # ]
420 : 0 : return;
421 : : }
422 : :
423 [ # # # # : 0 : if (crc != page->hdr.p2l_ckpt.p2l_checksum) {
# # # # #
# ]
424 [ # # # # : 0 : FTL_ERRLOG(p2l->dev, "Read P2L IO Log ERROR, CRC problem, type %d\n",
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
425 : : p2l->md->region->type);
426 [ # # # # : 0 : p2l->read_ctx.result = -EINVAL;
# # ]
427 : 0 : return;
428 : : }
429 : :
430 [ # # # # : 0 : if (page->hdr.p2l_ckpt.count > SPDK_COUNTOF(page->items)) {
# # # # #
# ]
431 [ # # # # : 0 : FTL_ERRLOG(p2l->dev, "Read P2L IO Log ERROR, inconsistent format, type %d\n",
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
432 : : p2l->md->region->type);
433 [ # # # # : 0 : p2l->read_ctx.result = -EINVAL;
# # ]
434 : 0 : return;
435 : : }
436 : :
437 [ # # # # : 0 : for (i = 0; i < page->hdr.p2l_ckpt.count; i++) {
# # # # #
# ]
438 [ # # # # ]: 0 : struct ftl_pl2_log_item *item = &page->items[i];
439 : :
440 [ # # # # : 0 : for (j = 0; j < item->num_blocks; j++) {
# # ]
441 [ # # # # : 0 : rc = cb_rd(dev, cb_arg, item->lba + j, item->addr + j, item->seq_id);
# # # # #
# # # # #
# # ]
442 [ # # ]: 0 : if (rc) {
443 [ # # # # : 0 : p2l->read_ctx.result = rc;
# # ]
444 : 0 : break;
445 : : }
446 : 0 : }
447 : :
448 [ # # ]: 0 : if (rc) {
449 : 0 : break;
450 : : }
451 : 0 : }
452 : 0 : }
453 : :
454 : : static void
455 : 0 : ftl_p2l_log_read_cb(int status, void *arg)
456 : : {
457 : 0 : struct ftl_p2l_log_page_ctrl *ctrl = arg;
458 [ # # # # ]: 0 : struct ftl_p2l_log *p2l = ctrl->p2l;
459 : :
460 [ # # # # : 0 : assert(p2l->read_ctx.qd > 0);
# # # # #
# ]
461 [ # # # # ]: 0 : p2l->read_ctx.qd--;
462 : :
463 [ # # ]: 0 : if (status) {
464 [ # # # # : 0 : p2l->read_ctx.result = status;
# # ]
465 : 0 : } else {
466 : 0 : ftl_p2l_log_read_visit(p2l, ctrl);
467 : : }
468 : :
469 : : /* Release page control */
470 [ # # # # ]: 0 : ftl_mempool_put(p2l->page_pool, ctrl);
471 : 0 : ftl_p2l_log_read_process(p2l);
472 : 0 : }
473 : :
474 : : static void
475 : 0 : ftl_p2l_log_read_process(struct ftl_p2l_log *p2l)
476 : : {
477 : : struct ftl_p2l_log_page_ctrl *ctrl;
478 : :
479 [ # # ]: 0 : while (ftl_p2l_log_read_is_next(p2l)) {
480 [ # # # # ]: 0 : ctrl = ftl_mempool_get(p2l->page_pool);
481 [ # # ]: 0 : if (!ctrl) {
482 : 0 : break;
483 : : }
484 : :
485 [ # # # # ]: 0 : ctrl->p2l = p2l;
486 [ # # # # : 0 : ctrl->entry_idx = p2l->read_ctx.idx++;
# # # # ]
487 : :
488 : : /* Check if the index exceeding the buffer size */
489 [ # # # # : 0 : ftl_bug(p2l->read_ctx.idx > p2l->entry_max);
# # # # #
# # # #
# ]
490 : :
491 [ # # # # ]: 0 : p2l->read_ctx.qd++;
492 [ # # # # : 0 : ftl_md_read_entry(p2l->md, ctrl->entry_idx, &ctrl->page, NULL,
# # # # #
# ]
493 [ # # ]: 0 : ftl_p2l_log_read_cb, ctrl, &ctrl->md_ctx);
494 : : }
495 : :
496 [ # # ]: 0 : if (ftl_p2l_log_read_is_finished(p2l)) {
497 : 0 : ftl_p2l_log_read_finish(p2l);
498 : 0 : }
499 : 0 : }
500 : :
501 : : int
502 : 0 : ftl_p2l_log_read(struct spdk_ftl_dev *dev, enum ftl_layout_region_type type, uint64_t seq_id,
503 : : spdk_ftl_fn cb_fn, void *cb_arg, ftl_p2l_log_rd_cb cb_rd)
504 : : {
505 : 0 : struct ftl_p2l_log *p2l_log = p2l_log_get(dev, type);
506 : :
507 [ # # ]: 0 : if (!p2l_log) {
508 [ # # # # : 0 : FTL_ERRLOG(dev, "Read P2L IO Log ERROR, no such log, type %d\n", type);
# # # # ]
509 : 0 : return -ENODEV;
510 : : }
511 [ # # ]: 0 : if (p2l_log_read_in_progress(p2l_log)) {
512 [ # # # # : 0 : FTL_ERRLOG(dev, "Read P2L IO Log ERROR, read busy, type %d\n", type);
# # # # ]
513 : 0 : return -EBUSY;
514 : : }
515 : :
516 [ # # # # ]: 0 : memset(&p2l_log->read_ctx, 0, sizeof(p2l_log->read_ctx));
517 [ # # # # : 0 : p2l_log->read_ctx.cb_fn = cb_fn;
# # ]
518 [ # # # # : 0 : p2l_log->read_ctx.cb_arg = cb_arg;
# # ]
519 [ # # # # : 0 : p2l_log->read_ctx.cb_rd = cb_rd;
# # ]
520 [ # # # # : 0 : p2l_log->read_ctx.seq_id = seq_id;
# # ]
521 : :
522 : 0 : ftl_p2l_log_read_process(p2l_log);
523 [ # # ]: 0 : if (ftl_p2l_log_read_is_qd(p2l_log)) {
524 : : /* Read in progress */
525 : 0 : return 0;
526 : : } else {
527 [ # # # # : 0 : FTL_ERRLOG(dev, "Read P2L IO Log ERROR, operation not started, type %d\n", type);
# # # # ]
528 : 0 : return -EINVAL;
529 : : }
530 : 0 : }
|