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/stdinc.h"
7 : : #include "spdk/cpuset.h"
8 : : #include "spdk/queue.h"
9 : : #include "spdk/thread.h"
10 : : #include "spdk/event.h"
11 : : #include "spdk/ftl.h"
12 : : #include "spdk/conf.h"
13 : : #include "spdk/env.h"
14 : : #include "spdk/util.h"
15 : :
16 : : #include "ftl_core.h"
17 : : #include "ftl_l2p_cache.h"
18 : : #include "ftl_layout.h"
19 : : #include "ftl_nv_cache_io.h"
20 : : #include "mngt/ftl_mngt_steps.h"
21 : : #include "utils/ftl_defs.h"
22 : : #include "utils/ftl_addr_utils.h"
23 : :
24 : : struct ftl_l2p_cache_page_io_ctx {
25 : : struct ftl_l2p_cache *cache;
26 : : uint64_t updates;
27 : : spdk_bdev_io_completion_cb cb;
28 : : struct spdk_bdev_io_wait_entry bdev_io_wait;
29 : : };
30 : :
31 : : enum ftl_l2p_page_state {
32 : : L2P_CACHE_PAGE_INIT, /* Page in memory not initialized from disk page */
33 : : L2P_CACHE_PAGE_READY, /* Page initialized from disk */
34 : : L2P_CACHE_PAGE_FLUSHING, /* Page is being flushed to disk and removed from memory */
35 : : L2P_CACHE_PAGE_PERSISTING, /* Page is being flushed to disk and not removed from memory */
36 : : L2P_CACHE_PAGE_CLEARING, /* Page is being initialized with INVALID addresses */
37 : : L2P_CACHE_PAGE_CORRUPTED /* Page corrupted */
38 : : };
39 : :
40 : : struct ftl_l2p_page {
41 : : uint64_t updates; /* Number of times an L2P entry was updated in the page since it was last persisted */
42 : : TAILQ_HEAD(, ftl_l2p_page_wait_ctx) ppe_list; /* for deferred pins */
43 : : TAILQ_ENTRY(ftl_l2p_page) list_entry;
44 : : uint64_t page_no;
45 : : enum ftl_l2p_page_state state;
46 : : uint64_t pin_ref_cnt;
47 : : struct ftl_l2p_cache_page_io_ctx ctx;
48 : : bool on_lru_list;
49 : : void *page_buffer;
50 : : uint64_t ckpt_seq_id;
51 : : ftl_df_obj_id obj_id;
52 : : };
53 : :
54 : : struct ftl_l2p_page_set;
55 : :
56 : : struct ftl_l2p_page_wait_ctx {
57 : : uint16_t pg_pin_issued;
58 : : uint16_t pg_pin_completed;
59 : : struct ftl_l2p_page_set *parent;
60 : : uint64_t pg_no;
61 : : TAILQ_ENTRY(ftl_l2p_page_wait_ctx) list_entry;
62 : : };
63 : :
64 : : /* A L2P page contains 1024 4B entries (or 512 8B ones for big drives).
65 : : * Currently internal IO will only pin 1 LBA at a time, so only one entry should be needed.
66 : : * User IO is split on internal xfer_size boundaries, which is currently set to 1MiB (256 blocks),
67 : : * so one entry should also be enough.
68 : : * TODO: We should probably revisit this though, when/if the xfer_size is based on io requirements of the
69 : : * bottom device (e.g. RAID5F), since then big IOs (especially unaligned ones) could potentially break this.
70 : : */
71 : : #define L2P_MAX_PAGES_TO_PIN 4
72 : : struct ftl_l2p_page_set {
73 : : uint16_t to_pin_cnt;
74 : : uint16_t pinned_cnt;
75 : : uint16_t pin_fault_cnt;
76 : : uint8_t locked;
77 : : uint8_t deferred;
78 : : struct ftl_l2p_pin_ctx *pin_ctx;
79 : : TAILQ_ENTRY(ftl_l2p_page_set) list_entry;
80 : : struct ftl_l2p_page_wait_ctx entry[L2P_MAX_PAGES_TO_PIN];
81 : : };
82 : :
83 : : struct ftl_l2p_l1_map_entry {
84 : : ftl_df_obj_id page_obj_id;
85 : : };
86 : :
87 : : enum ftl_l2p_cache_state {
88 : : L2P_CACHE_INIT,
89 : : L2P_CACHE_RUNNING,
90 : : L2P_CACHE_IN_SHUTDOWN,
91 : : L2P_CACHE_SHUTDOWN_DONE,
92 : : };
93 : :
94 : : struct ftl_l2p_cache_process_ctx {
95 : : int status;
96 : : ftl_l2p_cb cb;
97 : : void *cb_ctx;
98 : : uint64_t idx;
99 : : uint64_t qd;
100 : : };
101 : :
102 : : struct ftl_l2p_cache {
103 : : struct spdk_ftl_dev *dev;
104 : : struct ftl_l2p_l1_map_entry *l2_mapping;
105 : : struct ftl_md *l2_md;
106 : : struct ftl_md *l2_ctx_md;
107 : : struct ftl_mempool *l2_ctx_pool;
108 : : struct ftl_md *l1_md;
109 : :
110 : : TAILQ_HEAD(l2p_lru_list, ftl_l2p_page) lru_list;
111 : : /* TODO: A lot of / and % operations are done on this value, consider adding a shift based field and calculactions instead */
112 : : uint64_t lbas_in_page;
113 : : uint64_t num_pages; /* num pages to hold the entire L2P */
114 : :
115 : : uint64_t ios_in_flight; /* Currently in flight IOs, to determine l2p shutdown readiness */
116 : : enum ftl_l2p_cache_state state;
117 : : uint32_t l2_pgs_avail;
118 : : uint32_t l2_pgs_evicting;
119 : : uint32_t l2_pgs_resident_max;
120 : : uint32_t evict_keep;
121 : : struct ftl_mempool *page_sets_pool;
122 : : TAILQ_HEAD(, ftl_l2p_page_set) deferred_page_set_list; /* for deferred page sets */
123 : :
124 : : /* Process trim in background */
125 : : struct {
126 : : #define FTL_L2P_MAX_LAZY_TRIM_QD 1
127 : : /* Trim queue depth */
128 : : uint32_t qd;
129 : : /* Currently processed page */
130 : : uint64_t page_no;
131 : : /* Context for page pinning */
132 : : struct ftl_l2p_pin_ctx pin_ctx;
133 : : } lazy_trim;
134 : :
135 : : /* This is a context for a management process */
136 : : struct ftl_l2p_cache_process_ctx mctx;
137 : :
138 : : /* MD layout cache: Offset on a device in FTL_BLOCK_SIZE unit */
139 : : uint64_t cache_layout_offset;
140 : :
141 : : /* MD layout cache: Device of region */
142 : : struct spdk_bdev_desc *cache_layout_bdev_desc;
143 : :
144 : : /* MD layout cache: IO channel of region */
145 : : struct spdk_io_channel *cache_layout_ioch;
146 : : };
147 : :
148 : : typedef void (*ftl_l2p_cache_clear_cb)(struct ftl_l2p_cache *cache, int status, void *ctx_page);
149 : : typedef void (*ftl_l2p_cache_persist_cb)(struct ftl_l2p_cache *cache, int status, void *ctx_page);
150 : : typedef void (*ftl_l2p_cache_sync_cb)(struct spdk_ftl_dev *dev, int status, void *page,
151 : : void *user_ctx);
152 : :
153 : : static bool page_set_is_done(struct ftl_l2p_page_set *page_set);
154 : : static void page_set_end(struct spdk_ftl_dev *dev, struct ftl_l2p_cache *cache,
155 : : struct ftl_l2p_page_set *page_set);
156 : : static void page_out_io_retry(void *arg);
157 : : static void page_in_io_retry(void *arg);
158 : :
159 : : static inline void
160 : 672707 : ftl_l2p_page_queue_wait_ctx(struct ftl_l2p_page *page,
161 : : struct ftl_l2p_page_wait_ctx *ppe)
162 : : {
163 [ # # # # : 672707 : TAILQ_INSERT_TAIL(&page->ppe_list, ppe, list_entry);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
164 : 672707 : }
165 : :
166 : : static inline uint64_t
167 : 81 : ftl_l2p_cache_get_l1_page_size(void)
168 : : {
169 [ # # ]: 81 : return 1UL << 12;
170 : : }
171 : :
172 : : static inline uint64_t
173 : 4 : ftl_l2p_cache_get_lbas_in_page(struct ftl_l2p_cache *cache)
174 : : {
175 [ # # # # ]: 4 : return cache->lbas_in_page;
176 : : }
177 : :
178 : : static inline size_t
179 : 54 : ftl_l2p_cache_get_page_all_size(void)
180 : : {
181 : 54 : return sizeof(struct ftl_l2p_page) + ftl_l2p_cache_get_l1_page_size();
182 : : }
183 : :
184 : : static void
185 : 1669886 : ftl_l2p_cache_lru_remove_page(struct ftl_l2p_cache *cache, struct ftl_l2p_page *page)
186 : : {
187 [ - + # # ]: 1669886 : assert(page);
188 [ - + - + : 1669886 : assert(page->on_lru_list);
# # # # #
# ]
189 : :
190 [ + + # # : 1669886 : TAILQ_REMOVE(&cache->lru_list, page, list_entry);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
191 [ # # # # ]: 1669886 : page->on_lru_list = false;
192 : 1669886 : }
193 : :
194 : : static void
195 : 1671166 : ftl_l2p_cache_lru_add_page(struct ftl_l2p_cache *cache, struct ftl_l2p_page *page)
196 : : {
197 [ - + # # ]: 1671166 : assert(page);
198 [ - + - + : 1671166 : assert(!page->on_lru_list);
# # # # #
# ]
199 : :
200 [ + + # # : 1671166 : TAILQ_INSERT_HEAD(&cache->lru_list, page, list_entry);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
201 : :
202 [ # # # # ]: 1671166 : page->on_lru_list = true;
203 : 1671166 : }
204 : :
205 : : static void
206 : 17047974 : ftl_l2p_cache_lru_promote_page(struct ftl_l2p_cache *cache, struct ftl_l2p_page *page)
207 : : {
208 [ - + + - : 17047974 : if (!page->on_lru_list) {
# # # # ]
209 : 17047974 : return;
210 : : }
211 : :
212 : 0 : ftl_l2p_cache_lru_remove_page(cache, page);
213 : 0 : ftl_l2p_cache_lru_add_page(cache, page);
214 : 0 : }
215 : :
216 : : static inline void
217 : 118535 : ftl_l2p_cache_page_insert(struct ftl_l2p_cache *cache, struct ftl_l2p_page *page)
218 : : {
219 [ # # # # ]: 118535 : struct ftl_l2p_l1_map_entry *me = cache->l2_mapping;
220 [ - + # # ]: 118535 : assert(me);
221 : :
222 [ - + # # : 118535 : assert(me[page->page_no].page_obj_id == FTL_DF_OBJ_ID_INVALID);
# # # # #
# # # #
# ]
223 [ # # # # : 118535 : me[page->page_no].page_obj_id = page->obj_id;
# # # # #
# # # #
# ]
224 : 118535 : }
225 : :
226 : : static void
227 : 118458 : ftl_l2p_cache_page_remove(struct ftl_l2p_cache *cache, struct ftl_l2p_page *page)
228 : : {
229 [ # # # # ]: 118458 : struct ftl_l2p_l1_map_entry *me = cache->l2_mapping;
230 [ - + # # ]: 118458 : assert(me);
231 [ - + # # : 118458 : assert(me[page->page_no].page_obj_id != FTL_DF_OBJ_ID_INVALID);
# # # # #
# # # #
# ]
232 [ - + # # : 118458 : assert(TAILQ_EMPTY(&page->ppe_list));
# # # # #
# ]
233 : :
234 [ # # # # : 118458 : me[page->page_no].page_obj_id = FTL_DF_OBJ_ID_INVALID;
# # # # #
# ]
235 [ # # ]: 118458 : cache->l2_pgs_avail++;
236 [ # # # # ]: 118458 : ftl_mempool_put(cache->l2_ctx_pool, page);
237 : 118458 : }
238 : :
239 : : static inline struct ftl_l2p_page *
240 : 84122 : ftl_l2p_cache_get_coldest_page(struct ftl_l2p_cache *cache)
241 : : {
242 [ # # # # : 84122 : return TAILQ_LAST(&cache->lru_list, l2p_lru_list);
# # # # #
# # # ]
243 : : }
244 : :
245 : : static inline struct ftl_l2p_page *
246 : 0 : ftl_l2p_cache_get_hotter_page(struct ftl_l2p_page *page)
247 : : {
248 [ # # # # : 0 : return TAILQ_PREV(page, l2p_lru_list, list_entry);
# # # # #
# # # ]
249 : : }
250 : :
251 : : static inline uint64_t
252 : 221799 : ftl_l2p_cache_page_get_bdev_offset(struct ftl_l2p_cache *cache,
253 : : struct ftl_l2p_page *page)
254 : : {
255 [ # # # # : 221799 : return cache->cache_layout_offset + page->page_no;
# # # # ]
256 : : }
257 : :
258 : : static inline struct spdk_bdev_desc *
259 : 221799 : ftl_l2p_cache_get_bdev_desc(struct ftl_l2p_cache *cache)
260 : : {
261 [ # # # # ]: 221799 : return cache->cache_layout_bdev_desc;
262 : : }
263 : :
264 : : static inline struct spdk_io_channel *
265 : 221799 : ftl_l2p_cache_get_bdev_iochannel(struct ftl_l2p_cache *cache)
266 : : {
267 [ # # # # ]: 221799 : return cache->cache_layout_ioch;
268 : : }
269 : :
270 : : static struct ftl_l2p_page *
271 : 118535 : ftl_l2p_cache_page_alloc(struct ftl_l2p_cache *cache, size_t page_no)
272 : : {
273 [ # # # # ]: 118535 : struct ftl_l2p_page *page = ftl_mempool_get(cache->l2_ctx_pool);
274 [ - + # # ]: 118535 : ftl_bug(!page);
275 : :
276 [ # # ]: 118535 : cache->l2_pgs_avail--;
277 : :
278 [ - + ]: 118535 : memset(page, 0, sizeof(*page));
279 : :
280 [ # # # # : 118535 : page->obj_id = ftl_mempool_get_df_obj_id(cache->l2_ctx_pool, page);
# # # # ]
281 : :
282 [ # # # # : 237070 : page->page_buffer = (char *)ftl_md_get_buffer(cache->l1_md) + ftl_mempool_get_df_obj_index(
# # # # #
# # # ]
283 [ # # # # ]: 118535 : cache->l2_ctx_pool, page) * FTL_BLOCK_SIZE;
284 : :
285 [ # # # # : 118535 : TAILQ_INIT(&page->ppe_list);
# # # # #
# # # # #
# # ]
286 : :
287 [ # # # # ]: 118535 : page->page_no = page_no;
288 [ # # # # ]: 118535 : page->state = L2P_CACHE_PAGE_INIT;
289 : :
290 : 118535 : return page;
291 : : }
292 : :
293 : : static inline bool
294 : 81448 : ftl_l2p_cache_page_can_remove(struct ftl_l2p_page *page)
295 : : {
296 [ # # # # : 81448 : return (!page->updates &&
# # ]
297 [ + - + - : 162896 : page->state != L2P_CACHE_PAGE_INIT &&
# # ]
298 [ + + # # ]: 81448 : !page->pin_ref_cnt);
299 : : }
300 : :
301 : : static inline ftl_addr
302 : 13652352 : ftl_l2p_cache_get_addr(struct spdk_ftl_dev *dev,
303 : : struct ftl_l2p_cache *cache, struct ftl_l2p_page *page, uint64_t lba)
304 : : {
305 [ - + # # : 13652352 : return ftl_addr_load(dev, page->page_buffer, lba % cache->lbas_in_page);
# # # # #
# ]
306 : : }
307 : :
308 : : static inline void
309 : 3397670 : ftl_l2p_cache_set_addr(struct spdk_ftl_dev *dev, struct ftl_l2p_cache *cache,
310 : : struct ftl_l2p_page *page, uint64_t lba, ftl_addr addr)
311 : : {
312 [ - + # # : 3397670 : ftl_addr_store(dev, page->page_buffer, lba % cache->lbas_in_page, addr);
# # # # #
# ]
313 : 3397670 : }
314 : :
315 : : static void
316 : 4 : ftl_l2p_page_set_invalid(struct spdk_ftl_dev *dev, struct ftl_l2p_page *page)
317 : : {
318 : : ftl_addr addr;
319 [ # # # # ]: 4 : struct ftl_l2p_cache *cache = (struct ftl_l2p_cache *)dev->l2p;
320 : : uint64_t naddr;
321 : :
322 [ # # ]: 4 : page->updates++;
323 : :
324 : 4 : naddr = ftl_l2p_cache_get_lbas_in_page(cache);
325 [ + + ]: 4100 : for (uint64_t i = 0; i < naddr; i++) {
326 [ # # # # ]: 4096 : addr = ftl_addr_load(dev, page->page_buffer, i);
327 [ + + ]: 4096 : if (addr == FTL_ADDR_INVALID) {
328 : 2048 : continue;
329 : : }
330 : :
331 : 2048 : ftl_invalidate_addr(dev, addr);
332 : 2048 : ftl_l2p_cache_set_addr(dev, cache, page, i, FTL_ADDR_INVALID);
333 : 0 : }
334 : 4 : }
335 : :
336 : : static inline void
337 : 5450431 : ftl_l2p_cache_page_pin(struct ftl_l2p_cache *cache, struct ftl_l2p_page *page)
338 : : {
339 [ # # ]: 5450431 : page->pin_ref_cnt++;
340 : : /* Pinned pages can't be evicted (since L2P sets/gets will be executed on it), so remove them from LRU */
341 [ - + + + : 5450431 : if (page->on_lru_list) {
# # # # ]
342 : 1551415 : ftl_l2p_cache_lru_remove_page(cache, page);
343 : 0 : }
344 : 5450431 : }
345 : :
346 : : static inline void
347 : 5450431 : ftl_l2p_cache_page_unpin(struct ftl_l2p_cache *cache, struct ftl_l2p_page *page)
348 : : {
349 [ # # ]: 5450431 : page->pin_ref_cnt--;
350 [ + + - + : 5450431 : if (!page->pin_ref_cnt && !page->on_lru_list && page->state != L2P_CACHE_PAGE_FLUSHING) {
+ - + - #
# # # # #
# # # # #
# ]
351 : : /* L2P_CACHE_PAGE_FLUSHING: the page is currently being evicted.
352 : : * In such a case, the page can't be returned to the rank list, because
353 : : * the ongoing eviction will remove it if no pg updates had happened.
354 : : * Moreover, the page could make it to the top of the rank list and be
355 : : * selected for another eviction, while the ongoing one did not finish yet.
356 : : *
357 : : * Depending on the page updates tracker, the page will be evicted
358 : : * or returned to the rank list in context of the eviction completion
359 : : * cb - see page_out_io_complete().
360 : : */
361 : 1669963 : ftl_l2p_cache_lru_add_page(cache, page);
362 : 0 : }
363 : 5450431 : }
364 : :
365 : : static inline bool
366 : 84122 : ftl_l2p_cache_page_can_evict(struct ftl_l2p_page *page)
367 : : {
368 [ # # # # : 84122 : return (page->state == L2P_CACHE_PAGE_FLUSHING ||
# # ]
369 [ + - # # : 84122 : page->state == L2P_CACHE_PAGE_PERSISTING ||
# # ]
370 [ + - # # : 84122 : page->state == L2P_CACHE_PAGE_INIT ||
# # ]
371 [ + - + - ]: 168244 : page->pin_ref_cnt) ? false : true;
372 : : }
373 : :
374 : : static bool
375 : 23239879 : ftl_l2p_cache_evict_continue(struct ftl_l2p_cache *cache)
376 : : {
377 [ # # # # : 23239879 : return cache->l2_pgs_avail + cache->l2_pgs_evicting < cache->evict_keep;
# # # # #
# # # ]
378 : : }
379 : :
380 : : static void *
381 : 27 : _ftl_l2p_cache_init(struct spdk_ftl_dev *dev, size_t addr_size, uint64_t l2p_size)
382 : : {
383 : : struct ftl_l2p_cache *cache;
384 : 27 : uint64_t l2_pages = spdk_divide_round_up(l2p_size, ftl_l2p_cache_get_l1_page_size());
385 : 27 : size_t l2_size = l2_pages * sizeof(struct ftl_l2p_l1_map_entry);
386 : :
387 : 27 : cache = calloc(1, sizeof(struct ftl_l2p_cache));
388 [ - + ]: 27 : if (cache == NULL) {
389 : 0 : return NULL;
390 : : }
391 [ # # # # ]: 27 : cache->dev = dev;
392 : :
393 [ # # # # : 27 : cache->l2_md = ftl_md_create(dev,
# # ]
394 : 0 : spdk_divide_round_up(l2_size, FTL_BLOCK_SIZE), 0,
395 : : FTL_L2P_CACHE_MD_NAME_L2,
396 : 0 : ftl_md_create_shm_flags(dev), NULL);
397 : :
398 [ - + # # : 27 : if (cache->l2_md == NULL) {
# # ]
399 : 0 : goto fail_l2_md;
400 : : }
401 [ # # # # : 27 : cache->l2_mapping = ftl_md_get_buffer(cache->l2_md);
# # # # ]
402 : :
403 [ # # # # : 27 : cache->lbas_in_page = dev->layout.l2p.lbas_in_page;
# # # # #
# # # ]
404 [ # # # # ]: 27 : cache->num_pages = l2_pages;
405 : :
406 : 27 : return cache;
407 : 0 : fail_l2_md:
408 : 0 : free(cache);
409 : 0 : return NULL;
410 : 0 : }
411 : :
412 : : static struct ftl_l2p_page *
413 : 28829990 : get_l2p_page_by_df_id(struct ftl_l2p_cache *cache, size_t page_no)
414 : : {
415 [ # # # # ]: 28829990 : struct ftl_l2p_l1_map_entry *me = cache->l2_mapping;
416 [ # # # # : 28829990 : ftl_df_obj_id obj_id = me[page_no].page_obj_id;
# # ]
417 : :
418 [ + + ]: 28829990 : if (obj_id != FTL_DF_OBJ_ID_INVALID) {
419 [ # # # # ]: 27864650 : return ftl_mempool_get_df_ptr(cache->l2_ctx_pool, obj_id);
420 : : }
421 : :
422 : 965340 : return NULL;
423 : 0 : }
424 : :
425 : : int
426 : 27 : ftl_l2p_cache_init(struct spdk_ftl_dev *dev)
427 : : {
428 [ # # # # : 27 : uint64_t l2p_size = dev->num_lbas * dev->layout.l2p.addr_size;
# # # # #
# # # ]
429 : : struct ftl_l2p_cache *cache;
430 : : const struct ftl_layout_region *reg;
431 [ # # # # : 27 : void *l2p = _ftl_l2p_cache_init(dev, dev->layout.l2p.addr_size, l2p_size);
# # # # ]
432 [ # # # # ]: 27 : size_t page_sets_pool_size = 1 << 15;
433 : : size_t max_resident_size, max_resident_pgs;
434 : :
435 [ - + ]: 27 : if (!l2p) {
436 : 0 : return -1;
437 : : }
438 [ # # # # ]: 27 : dev->l2p = l2p;
439 : :
440 [ # # # # ]: 27 : cache = (struct ftl_l2p_cache *)dev->l2p;
441 [ # # # # ]: 27 : cache->page_sets_pool = ftl_mempool_create(page_sets_pool_size,
442 : : sizeof(struct ftl_l2p_page_set),
443 : : 64, SPDK_ENV_NUMA_ID_ANY);
444 [ - + # # : 27 : if (!cache->page_sets_pool) {
# # ]
445 : 0 : return -1;
446 : : }
447 : :
448 [ # # # # : 27 : max_resident_size = dev->conf.l2p_dram_limit << 20;
# # # # ]
449 [ - + ]: 27 : max_resident_pgs = max_resident_size / ftl_l2p_cache_get_page_all_size();
450 : :
451 [ - + # # : 27 : if (max_resident_pgs > cache->num_pages) {
# # ]
452 : 0 : SPDK_NOTICELOG("l2p memory limit higher than entire L2P size\n");
453 [ # # # # ]: 0 : max_resident_pgs = cache->num_pages;
454 : 0 : }
455 : :
456 : : /* Round down max res pgs to the nearest # of l2/l1 pgs */
457 : 27 : max_resident_size = max_resident_pgs * ftl_l2p_cache_get_page_all_size();
458 [ # # # # : 27 : SPDK_NOTICELOG("l2p maximum resident size is: %"PRIu64" (of %"PRIu64") MiB\n",
# # # # ]
459 : : max_resident_size >> 20, dev->conf.l2p_dram_limit);
460 : :
461 [ # # # # : 27 : TAILQ_INIT(&cache->deferred_page_set_list);
# # # # #
# # # # #
# # ]
462 [ # # # # : 27 : TAILQ_INIT(&cache->lru_list);
# # # # #
# # # # #
# # ]
463 : :
464 [ # # # # : 27 : cache->l2_ctx_md = ftl_md_create(dev,
# # ]
465 : 0 : spdk_divide_round_up(max_resident_pgs * SPDK_ALIGN_CEIL(sizeof(struct ftl_l2p_page), 64),
466 : 0 : FTL_BLOCK_SIZE), 0, FTL_L2P_CACHE_MD_NAME_L2_CTX, ftl_md_create_shm_flags(dev), NULL);
467 : :
468 [ - + # # : 27 : if (cache->l2_ctx_md == NULL) {
# # ]
469 : 0 : return -1;
470 : : }
471 : :
472 [ # # # # ]: 27 : cache->l2_pgs_resident_max = max_resident_pgs;
473 [ # # # # ]: 27 : cache->l2_pgs_avail = max_resident_pgs;
474 [ # # # # ]: 27 : cache->l2_pgs_evicting = 0;
475 [ # # # # : 27 : cache->l2_ctx_pool = ftl_mempool_create_ext(ftl_md_get_buffer(cache->l2_ctx_md),
# # # # #
# ]
476 : 0 : max_resident_pgs, sizeof(struct ftl_l2p_page), 64);
477 : :
478 [ - + # # : 27 : if (cache->l2_ctx_pool == NULL) {
# # ]
479 : 0 : return -1;
480 : : }
481 : :
482 : : #define FTL_L2P_CACHE_PAGE_AVAIL_MAX 16UL << 10
483 : : #define FTL_L2P_CACHE_PAGE_AVAIL_RATIO 5UL
484 [ # # # # : 27 : cache->evict_keep = spdk_divide_round_up(cache->num_pages * FTL_L2P_CACHE_PAGE_AVAIL_RATIO, 100);
# # # # ]
485 [ # # # # : 27 : cache->evict_keep = spdk_min(FTL_L2P_CACHE_PAGE_AVAIL_MAX, cache->evict_keep);
# # # # #
# # # # #
# # # # ]
486 : :
487 [ + + + + ]: 27 : if (!ftl_fast_startup(dev) && !ftl_fast_recovery(dev)) {
488 [ - + # # : 23 : memset(cache->l2_mapping, (int)FTL_DF_OBJ_ID_INVALID, ftl_md_get_buffer_size(cache->l2_md));
# # # # #
# ]
489 [ # # # # ]: 23 : ftl_mempool_initialize_ext(cache->l2_ctx_pool);
490 : 0 : }
491 : :
492 [ # # # # : 27 : cache->l1_md = ftl_md_create(dev,
# # ]
493 : 0 : max_resident_pgs, 0,
494 : : FTL_L2P_CACHE_MD_NAME_L1,
495 : 0 : ftl_md_create_shm_flags(dev), NULL);
496 : :
497 [ - + # # : 27 : if (cache->l1_md == NULL) {
# # ]
498 : 0 : return -1;
499 : : }
500 : :
501 : : /* Cache MD layout */
502 [ # # # # : 27 : reg = &dev->layout.region[FTL_LAYOUT_REGION_TYPE_L2P];
# # # # ]
503 [ # # # # : 27 : cache->cache_layout_offset = reg->current.offset;
# # # # #
# ]
504 [ # # # # : 27 : cache->cache_layout_bdev_desc = reg->bdev_desc;
# # # # ]
505 [ # # # # : 27 : cache->cache_layout_ioch = reg->ioch;
# # # # ]
506 : :
507 : 27 : return 0;
508 : 0 : }
509 : :
510 : : static void
511 : 27 : ftl_l2p_cache_deinit_l2(struct spdk_ftl_dev *dev, struct ftl_l2p_cache *cache)
512 : : {
513 [ # # # # ]: 27 : ftl_md_destroy(cache->l2_ctx_md, ftl_md_destroy_shm_flags(dev));
514 [ # # # # ]: 27 : cache->l2_ctx_md = NULL;
515 : :
516 [ # # # # ]: 27 : ftl_mempool_destroy_ext(cache->l2_ctx_pool);
517 [ # # # # ]: 27 : cache->l2_ctx_pool = NULL;
518 : :
519 [ # # # # ]: 27 : ftl_md_destroy(cache->l1_md, ftl_md_destroy_shm_flags(dev));
520 [ # # # # ]: 27 : cache->l1_md = NULL;
521 : :
522 [ # # # # ]: 27 : ftl_mempool_destroy(cache->page_sets_pool);
523 [ # # # # ]: 27 : cache->page_sets_pool = NULL;
524 : 27 : }
525 : :
526 : : static void
527 : 27 : _ftl_l2p_cache_deinit(struct spdk_ftl_dev *dev)
528 : : {
529 [ # # # # ]: 27 : struct ftl_l2p_cache *cache = (struct ftl_l2p_cache *)dev->l2p;
530 : :
531 : 27 : ftl_l2p_cache_deinit_l2(dev, cache);
532 [ # # # # ]: 27 : ftl_md_destroy(cache->l2_md, ftl_md_destroy_shm_flags(dev));
533 : 27 : free(cache);
534 : 27 : }
535 : :
536 : : void
537 : 27 : ftl_l2p_cache_deinit(struct spdk_ftl_dev *dev)
538 : : {
539 [ # # # # ]: 27 : struct ftl_l2p_cache *cache = (struct ftl_l2p_cache *)dev->l2p;
540 : :
541 [ - + ]: 27 : if (!cache) {
542 : 0 : return;
543 : : }
544 [ - + - - : 27 : assert(cache->state == L2P_CACHE_SHUTDOWN_DONE || cache->state == L2P_CACHE_INIT);
# # # # #
# # # #
# ]
545 : :
546 : 27 : _ftl_l2p_cache_deinit(dev);
547 [ # # # # ]: 27 : dev->l2p = 0;
548 : 0 : }
549 : :
550 : : static void
551 : 46 : process_init_ctx(struct spdk_ftl_dev *dev, struct ftl_l2p_cache *cache,
552 : : ftl_l2p_cb cb, void *cb_ctx)
553 : : {
554 [ # # ]: 46 : struct ftl_l2p_cache_process_ctx *ctx = &cache->mctx;
555 : :
556 [ - + # # : 46 : assert(NULL == ctx->cb_ctx);
# # # # ]
557 [ - + # # : 46 : assert(0 == cache->l2_pgs_evicting);
# # # # ]
558 : :
559 [ - + ]: 46 : memset(ctx, 0, sizeof(*ctx));
560 : :
561 [ # # # # ]: 46 : ctx->cb = cb;
562 [ # # # # ]: 46 : ctx->cb_ctx = cb_ctx;
563 : 46 : }
564 : :
565 : : static void
566 : 46 : process_finish(struct ftl_l2p_cache *cache)
567 : : {
568 [ # # ]: 46 : struct ftl_l2p_cache_process_ctx ctx = cache->mctx;
569 : :
570 [ - + # # : 46 : assert(cache->l2_pgs_avail == cache->l2_pgs_resident_max);
# # # # #
# # # ]
571 [ - + # # : 46 : assert(0 == ctx.qd);
# # ]
572 : :
573 [ - + # # ]: 46 : memset(&cache->mctx, 0, sizeof(cache->mctx));
574 [ # # # # : 46 : ctx.cb(cache->dev, ctx.status, ctx.cb_ctx);
# # # # #
# # # ]
575 : 46 : }
576 : :
577 : : static void process_page_out_retry(void *_page);
578 : : static void process_persist(struct ftl_l2p_cache *cache);
579 : :
580 : : static void
581 : 0 : process_page_in(struct ftl_l2p_page *page, spdk_bdev_io_completion_cb cb)
582 : : {
583 [ # # # # : 0 : struct ftl_l2p_cache *cache = (struct ftl_l2p_cache *)page->ctx.cache;
# # ]
584 : : int rc;
585 : :
586 [ # # # # : 0 : assert(page->page_buffer);
# # # # ]
587 : :
588 [ # # # # ]: 0 : rc = ftl_nv_cache_bdev_read_blocks_with_md(cache->dev, ftl_l2p_cache_get_bdev_desc(cache),
589 : 0 : ftl_l2p_cache_get_bdev_iochannel(cache),
590 [ # # # # ]: 0 : page->page_buffer, NULL, ftl_l2p_cache_page_get_bdev_offset(cache, page),
591 : 0 : 1, cb, page);
592 : :
593 [ # # ]: 0 : if (rc) {
594 [ # # # # ]: 0 : cb(NULL, false, page);
595 : 0 : }
596 : 0 : }
597 : :
598 : : static void
599 : 21816 : process_persist_page_out_cb(struct spdk_bdev_io *bdev_io, bool success, void *arg)
600 : : {
601 : 21816 : struct ftl_l2p_page *page = arg;
602 [ # # # # : 21816 : struct ftl_l2p_cache *cache = page->ctx.cache;
# # ]
603 [ # # # # ]: 21816 : struct spdk_ftl_dev *dev = cache->dev;
604 [ # # ]: 21816 : struct ftl_l2p_cache_process_ctx *ctx = &cache->mctx;
605 : :
606 [ - + # # ]: 21816 : assert(bdev_io);
607 : 21816 : ftl_stats_bdev_io_completed(dev, FTL_STATS_TYPE_L2P, bdev_io);
608 : 21816 : spdk_bdev_free_io(bdev_io);
609 : :
610 [ - + # # ]: 21816 : if (!success) {
611 [ # # # # ]: 0 : ctx->status = -EIO;
612 : 0 : }
613 : :
614 [ - + # # : 21816 : if (ftl_bitmap_get(dev->trim_map, ctx->idx)) {
# # # # #
# ]
615 : : /*
616 : : * Page had been trimmed, in persist path before IO, it was invalidated entirely
617 : : * now clear trim flag
618 : : */
619 [ # # # # : 0 : ftl_bitmap_clear(dev->trim_map, page->page_no);
# # # # ]
620 : 0 : }
621 : 21816 : ftl_l2p_cache_page_remove(cache, page);
622 : :
623 [ # # ]: 21816 : ctx->qd--;
624 : 21816 : process_persist(cache);
625 : 21816 : }
626 : :
627 : : static void
628 : 21816 : process_page_out(struct ftl_l2p_page *page, spdk_bdev_io_completion_cb cb)
629 : : {
630 : : struct spdk_bdev *bdev;
631 : : struct spdk_bdev_io_wait_entry *bdev_io_wait;
632 [ # # # # : 21816 : struct ftl_l2p_cache *cache = page->ctx.cache;
# # ]
633 [ # # # # ]: 21816 : struct spdk_ftl_dev *dev = cache->dev;
634 : : int rc;
635 : :
636 [ - + # # : 21816 : assert(page->page_buffer);
# # # # ]
637 : :
638 : 21816 : rc = ftl_nv_cache_bdev_write_blocks_with_md(dev, ftl_l2p_cache_get_bdev_desc(cache),
639 : 0 : ftl_l2p_cache_get_bdev_iochannel(cache),
640 [ # # # # ]: 0 : page->page_buffer, NULL, ftl_l2p_cache_page_get_bdev_offset(cache, page),
641 : 0 : 1, cb, page);
642 : :
643 [ + - ]: 21816 : if (spdk_likely(0 == rc)) {
644 : 21816 : return;
645 : : }
646 : :
647 [ # # ]: 0 : if (rc == -ENOMEM) {
648 : 0 : bdev = spdk_bdev_desc_get_bdev(ftl_l2p_cache_get_bdev_desc(cache));
649 [ # # # # ]: 0 : bdev_io_wait = &page->ctx.bdev_io_wait;
650 [ # # # # ]: 0 : bdev_io_wait->bdev = bdev;
651 [ # # # # ]: 0 : bdev_io_wait->cb_fn = process_page_out_retry;
652 [ # # # # ]: 0 : bdev_io_wait->cb_arg = page;
653 [ # # # # : 0 : page->ctx.cb = cb;
# # ]
654 : :
655 : 0 : rc = spdk_bdev_queue_io_wait(bdev, ftl_l2p_cache_get_bdev_iochannel(cache), bdev_io_wait);
656 [ # # # # ]: 0 : ftl_bug(rc);
657 : 0 : } else {
658 [ # # ]: 0 : ftl_abort();
659 : : }
660 : 0 : }
661 : :
662 : : static void
663 : 0 : process_page_out_retry(void *_page)
664 : : {
665 : 0 : struct ftl_l2p_page *page = _page;
666 : :
667 [ # # # # : 0 : process_page_out(page, page->ctx.cb);
# # ]
668 : 0 : }
669 : :
670 : : static void process_trim(struct ftl_l2p_cache *cache);
671 : :
672 : : static void
673 : 0 : process_trim_page_out_cb(struct spdk_bdev_io *bdev_io, bool success, void *ctx_page)
674 : : {
675 : 0 : struct ftl_l2p_page *page = (struct ftl_l2p_page *)ctx_page;
676 [ # # # # : 0 : struct ftl_l2p_cache *cache = (struct ftl_l2p_cache *)page->ctx.cache;
# # ]
677 [ # # # # ]: 0 : struct spdk_ftl_dev *dev = cache->dev;
678 [ # # ]: 0 : struct ftl_l2p_cache_process_ctx *ctx = &cache->mctx;
679 : :
680 [ # # # # ]: 0 : assert(bdev_io);
681 : 0 : ftl_stats_bdev_io_completed(dev, FTL_STATS_TYPE_L2P, bdev_io);
682 : 0 : spdk_bdev_free_io(bdev_io);
683 : :
684 [ # # # # ]: 0 : if (!success) {
685 [ # # # # ]: 0 : ctx->status = -EIO;
686 : 0 : }
687 : :
688 [ # # # # : 0 : assert(!page->on_lru_list);
# # # # #
# ]
689 [ # # # # : 0 : assert(ftl_bitmap_get(dev->trim_map, page->page_no));
# # # # #
# # # ]
690 [ # # # # : 0 : ftl_bitmap_clear(dev->trim_map, page->page_no);
# # # # ]
691 : 0 : ftl_l2p_cache_page_remove(cache, page);
692 : :
693 [ # # ]: 0 : ctx->qd--;
694 : 0 : process_trim(cache);
695 : 0 : }
696 : :
697 : : static void
698 : 0 : process_trim_page_in_cb(struct spdk_bdev_io *bdev_io, bool success, void *ctx_page)
699 : : {
700 : 0 : struct ftl_l2p_page *page = (struct ftl_l2p_page *)ctx_page;
701 [ # # # # : 0 : struct ftl_l2p_cache *cache = (struct ftl_l2p_cache *)page->ctx.cache;
# # ]
702 [ # # # # ]: 0 : struct spdk_ftl_dev *dev = cache->dev;
703 [ # # ]: 0 : struct ftl_l2p_cache_process_ctx *ctx = &cache->mctx;
704 : :
705 [ # # ]: 0 : if (bdev_io) {
706 : 0 : ftl_stats_bdev_io_completed(dev, FTL_STATS_TYPE_L2P, bdev_io);
707 : 0 : spdk_bdev_free_io(bdev_io);
708 : 0 : }
709 [ # # # # ]: 0 : if (success) {
710 [ # # # # : 0 : assert(ftl_bitmap_get(dev->trim_map, page->page_no));
# # # # #
# # # ]
711 : 0 : ftl_l2p_page_set_invalid(dev, page);
712 : 0 : process_page_out(page, process_trim_page_out_cb);
713 : 0 : } else {
714 [ # # # # ]: 0 : ctx->status = -EIO;
715 [ # # ]: 0 : ctx->qd--;
716 : 0 : process_trim(cache);
717 : : }
718 : 0 : }
719 : :
720 : : static void
721 : 23 : process_trim(struct ftl_l2p_cache *cache)
722 : : {
723 [ # # ]: 23 : struct ftl_l2p_cache_process_ctx *ctx = &cache->mctx;
724 : :
725 [ + + + - : 455397 : while (ctx->idx < cache->num_pages && ctx->qd < 64) {
# # # # #
# # # # #
# # ]
726 : : struct ftl_l2p_page *page;
727 : :
728 [ + - # # : 455374 : if (!ftl_bitmap_get(cache->dev->trim_map, ctx->idx)) {
# # # # #
# # # #
# ]
729 : : /* Page had not been trimmed, continue */
730 [ # # ]: 455374 : ctx->idx++;
731 : 455374 : continue;
732 : : }
733 : :
734 : : /* All pages were removed in persist phase */
735 [ # # # # : 0 : assert(get_l2p_page_by_df_id(cache, ctx->idx) == NULL);
# # # # ]
736 : :
737 : : /* Allocate page to invalidate it */
738 [ # # # # ]: 0 : page = ftl_l2p_cache_page_alloc(cache, ctx->idx);
739 [ # # ]: 0 : if (!page) {
740 : : /* All pages utilized so far, continue when they will be back available */
741 [ # # # # : 0 : assert(ctx->qd);
# # # # ]
742 : 0 : break;
743 : : }
744 : :
745 [ # # # # ]: 0 : page->state = L2P_CACHE_PAGE_CLEARING;
746 [ # # # # : 0 : page->ctx.cache = cache;
# # ]
747 : :
748 : 0 : ftl_l2p_cache_page_insert(cache, page);
749 : 0 : process_page_in(page, process_trim_page_in_cb);
750 : :
751 [ # # ]: 0 : ctx->qd++;
752 [ # # ]: 0 : ctx->idx++;
753 : : }
754 : :
755 [ + - # # : 23 : if (0 == ctx->qd) {
# # ]
756 : 23 : process_finish(cache);
757 : 0 : }
758 : 23 : }
759 : :
760 : : void
761 : 23 : ftl_l2p_cache_trim(struct spdk_ftl_dev *dev, ftl_l2p_cb cb, void *cb_ctx)
762 : : {
763 [ # # # # ]: 23 : struct ftl_l2p_cache *cache = (struct ftl_l2p_cache *)dev->l2p;
764 : :
765 : 23 : process_init_ctx(dev, cache, cb, cb_ctx);
766 : 23 : process_trim(cache);
767 : 23 : }
768 : :
769 : : static void
770 : 6 : clear_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status)
771 : : {
772 [ # # # # : 6 : ftl_l2p_cb cb = md->owner.private;
# # ]
773 [ # # # # : 6 : void *cb_cntx = md->owner.cb_ctx;
# # ]
774 : :
775 [ # # # # ]: 6 : cb(dev, status, cb_cntx);
776 : 6 : }
777 : :
778 : : void
779 : 6 : ftl_l2p_cache_clear(struct spdk_ftl_dev *dev, ftl_l2p_cb cb, void *cb_ctx)
780 : : {
781 [ # # # # : 6 : struct ftl_md *md = dev->layout.md[FTL_LAYOUT_REGION_TYPE_L2P];
# # # # ]
782 : 6 : ftl_addr invalid_addr = FTL_ADDR_INVALID;
783 : :
784 [ # # # # ]: 6 : md->cb = clear_cb;
785 [ # # # # : 6 : md->owner.cb_ctx = cb_ctx;
# # ]
786 [ # # # # : 6 : md->owner.private = cb;
# # ]
787 : :
788 : 6 : ftl_md_clear(md, invalid_addr, NULL);
789 : 6 : }
790 : :
791 : : static void
792 : 3 : l2p_shm_restore_clean(struct spdk_ftl_dev *dev)
793 : : {
794 [ # # # # ]: 3 : struct ftl_l2p_cache *cache = (struct ftl_l2p_cache *)dev->l2p;
795 [ # # # # ]: 3 : struct ftl_l2p_l1_map_entry *me = cache->l2_mapping;
796 : : struct ftl_l2p_page *page;
797 : : ftl_df_obj_id obj_id;
798 : : uint64_t page_no;
799 : :
800 [ + + # # : 61443 : for (page_no = 0; page_no < cache->num_pages; ++page_no) {
# # ]
801 [ # # # # : 61440 : obj_id = me[page_no].page_obj_id;
# # ]
802 [ + + ]: 61440 : if (obj_id == FTL_DF_OBJ_ID_INVALID) {
803 : 60544 : continue;
804 : : }
805 : :
806 [ # # # # ]: 896 : page = ftl_mempool_claim_df(cache->l2_ctx_pool, obj_id);
807 [ - + # # ]: 896 : assert(page);
808 [ - + # # : 896 : assert(page->obj_id == ftl_mempool_get_df_obj_id(cache->l2_ctx_pool, page));
# # # # #
# # # ]
809 [ - + # # : 896 : assert(page->page_no == page_no);
# # # # ]
810 [ - + # # : 896 : assert(page->state != L2P_CACHE_PAGE_INIT);
# # # # ]
811 [ - + # # : 896 : assert(page->state != L2P_CACHE_PAGE_CLEARING);
# # # # ]
812 [ - + # # : 896 : assert(cache->l2_pgs_avail > 0);
# # # # ]
813 [ # # ]: 896 : cache->l2_pgs_avail--;
814 : :
815 [ # # # # : 1792 : page->page_buffer = (char *)ftl_md_get_buffer(cache->l1_md) + ftl_mempool_get_df_obj_index(
# # # # #
# # # ]
816 [ # # # # ]: 896 : cache->l2_ctx_pool, page) * FTL_BLOCK_SIZE;
817 : :
818 [ # # # # : 896 : TAILQ_INIT(&page->ppe_list);
# # # # #
# # # # #
# # ]
819 : :
820 [ # # # # ]: 896 : page->pin_ref_cnt = 0;
821 [ # # # # ]: 896 : page->on_lru_list = 0;
822 [ - + # # ]: 896 : memset(&page->ctx, 0, sizeof(page->ctx));
823 : :
824 : 896 : ftl_l2p_cache_lru_add_page(cache, page);
825 : 0 : }
826 : :
827 [ # # # # ]: 3 : ftl_mempool_initialize_ext(cache->l2_ctx_pool);
828 : 3 : }
829 : :
830 : : static void
831 : 1 : l2p_shm_restore_dirty(struct spdk_ftl_dev *dev)
832 : : {
833 [ # # # # ]: 1 : struct ftl_l2p_cache *cache = (struct ftl_l2p_cache *)dev->l2p;
834 [ # # # # ]: 1 : struct ftl_l2p_l1_map_entry *me = cache->l2_mapping;
835 : : struct ftl_l2p_page *page;
836 : : ftl_df_obj_id obj_id;
837 : : uint64_t page_no;
838 : :
839 [ + + # # : 3688 : for (page_no = 0; page_no < cache->num_pages; ++page_no) {
# # ]
840 [ # # # # : 3687 : obj_id = me[page_no].page_obj_id;
# # ]
841 [ + + ]: 3687 : if (obj_id == FTL_DF_OBJ_ID_INVALID) {
842 : 3380 : continue;
843 : : }
844 : :
845 [ # # # # ]: 307 : page = ftl_mempool_claim_df(cache->l2_ctx_pool, obj_id);
846 [ - + # # ]: 307 : assert(page);
847 [ - + # # : 307 : assert(page->obj_id == ftl_mempool_get_df_obj_id(cache->l2_ctx_pool, page));
# # # # #
# # # ]
848 [ - + # # : 307 : assert(page->page_no == page_no);
# # # # ]
849 [ - + # # : 307 : assert(page->state != L2P_CACHE_PAGE_CLEARING);
# # # # ]
850 [ - + # # : 307 : assert(cache->l2_pgs_avail > 0);
# # # # ]
851 [ # # ]: 307 : cache->l2_pgs_avail--;
852 : :
853 [ - + # # : 307 : if (page->state == L2P_CACHE_PAGE_INIT) {
# # ]
854 [ # # # # : 0 : me[page_no].page_obj_id = FTL_DF_OBJ_ID_INVALID;
# # ]
855 [ # # ]: 0 : cache->l2_pgs_avail++;
856 [ # # # # ]: 0 : ftl_mempool_release_df(cache->l2_ctx_pool, obj_id);
857 : 0 : continue;
858 : : }
859 : :
860 [ # # # # ]: 307 : page->state = L2P_CACHE_PAGE_READY;
861 : : /* Assume page is dirty after crash */
862 [ # # # # ]: 307 : page->updates = 1;
863 [ # # # # : 614 : page->page_buffer = (char *)ftl_md_get_buffer(cache->l1_md) + ftl_mempool_get_df_obj_index(
# # # # #
# # # ]
864 [ # # # # ]: 307 : cache->l2_ctx_pool, page) * FTL_BLOCK_SIZE;
865 : :
866 [ # # # # : 307 : TAILQ_INIT(&page->ppe_list);
# # # # #
# # # # #
# # ]
867 : :
868 [ # # # # ]: 307 : page->pin_ref_cnt = 0;
869 [ # # # # ]: 307 : page->on_lru_list = 0;
870 [ - + # # ]: 307 : memset(&page->ctx, 0, sizeof(page->ctx));
871 : :
872 : 307 : ftl_l2p_cache_lru_add_page(cache, page);
873 : 0 : }
874 : :
875 [ # # # # ]: 1 : ftl_mempool_initialize_ext(cache->l2_ctx_pool);
876 : 1 : }
877 : :
878 : : void
879 : 21 : ftl_l2p_cache_restore(struct spdk_ftl_dev *dev, ftl_l2p_cb cb, void *cb_ctx)
880 : : {
881 [ + + ]: 21 : if (ftl_fast_startup(dev)) {
882 : 3 : l2p_shm_restore_clean(dev);
883 : 0 : }
884 : :
885 [ + + ]: 21 : if (ftl_fast_recovery(dev)) {
886 : 1 : l2p_shm_restore_dirty(dev);
887 : 0 : }
888 : :
889 [ # # # # ]: 21 : cb(dev, 0, cb_ctx);
890 : 21 : }
891 : :
892 : : static void
893 : 21839 : process_persist(struct ftl_l2p_cache *cache)
894 : : {
895 [ # # ]: 21839 : struct ftl_l2p_cache_process_ctx *ctx = &cache->mctx;
896 [ # # # # ]: 21839 : struct spdk_ftl_dev *dev = cache->dev;
897 : :
898 [ + + + + : 477213 : while (ctx->idx < cache->num_pages && ctx->qd < 64) {
# # # # #
# # # # #
# # ]
899 [ # # # # ]: 455374 : struct ftl_l2p_page *page = get_l2p_page_by_df_id(cache, ctx->idx);
900 [ # # ]: 455374 : ctx->idx++;
901 : :
902 [ + + ]: 455374 : if (!page) {
903 : 421025 : continue;
904 : : }
905 : :
906 : : /* Finish trim if the page was marked */
907 [ - + # # : 34349 : if (ftl_bitmap_get(dev->trim_map, ctx->idx)) {
# # # # #
# ]
908 : 0 : ftl_l2p_page_set_invalid(dev, page);
909 : 0 : }
910 : :
911 [ - + + - : 34349 : if (page->on_lru_list) {
# # # # ]
912 : 34349 : ftl_l2p_cache_lru_remove_page(cache, page);
913 : 0 : }
914 : :
915 [ + + # # : 34349 : if (page->updates) {
# # ]
916 : : /* Need to persist the page */
917 [ # # # # ]: 21816 : page->state = L2P_CACHE_PAGE_PERSISTING;
918 [ # # # # : 21816 : page->ctx.cache = cache;
# # ]
919 [ # # ]: 21816 : ctx->qd++;
920 : 21816 : process_page_out(page, process_persist_page_out_cb);
921 : 0 : } else {
922 : 12533 : ftl_l2p_cache_page_remove(cache, page);
923 : : }
924 : : }
925 : :
926 [ + + # # : 21839 : if (0 == ctx->qd) {
# # ]
927 : 23 : process_finish(cache);
928 : 0 : }
929 : 21839 : }
930 : :
931 : : void
932 : 23 : ftl_l2p_cache_persist(struct spdk_ftl_dev *dev, ftl_l2p_cb cb, void *cb_ctx)
933 : : {
934 [ # # # # ]: 23 : struct ftl_l2p_cache *cache = (struct ftl_l2p_cache *)dev->l2p;
935 : :
936 : 23 : process_init_ctx(dev, cache, cb, cb_ctx);
937 : 23 : process_persist(cache);
938 : 23 : }
939 : :
940 : : bool
941 : 54 : ftl_l2p_cache_is_halted(struct spdk_ftl_dev *dev)
942 : : {
943 [ # # # # ]: 54 : struct ftl_l2p_cache *cache = (struct ftl_l2p_cache *)dev->l2p;
944 : :
945 [ # # # # ]: 54 : return cache->state == L2P_CACHE_SHUTDOWN_DONE;
946 : : }
947 : :
948 : : void
949 : 27 : ftl_l2p_cache_halt(struct spdk_ftl_dev *dev)
950 : : {
951 [ # # # # ]: 27 : struct ftl_l2p_cache *cache = (struct ftl_l2p_cache *)dev->l2p;
952 : :
953 [ + - # # : 27 : if (cache->state != L2P_CACHE_SHUTDOWN_DONE) {
# # ]
954 [ # # # # ]: 27 : cache->state = L2P_CACHE_IN_SHUTDOWN;
955 [ + - + - : 27 : if (!cache->ios_in_flight && !cache->l2_pgs_evicting) {
# # # # #
# # # ]
956 [ # # # # ]: 27 : cache->state = L2P_CACHE_SHUTDOWN_DONE;
957 : 0 : }
958 : 0 : }
959 : 27 : }
960 : :
961 : : void
962 : 27 : ftl_l2p_cache_resume(struct spdk_ftl_dev *dev)
963 : : {
964 [ # # # # ]: 27 : struct ftl_l2p_cache *cache = (struct ftl_l2p_cache *)dev->l2p;
965 : :
966 [ - + # # : 27 : assert(cache->state == L2P_CACHE_INIT);
# # # # ]
967 [ # # # # ]: 27 : cache->state = L2P_CACHE_RUNNING;
968 : 27 : }
969 : :
970 : : static inline struct ftl_l2p_page *
971 : 17047974 : get_page(struct ftl_l2p_cache *cache, uint64_t lba)
972 : : {
973 [ - + # # : 17047974 : return get_l2p_page_by_df_id(cache, lba / cache->lbas_in_page);
# # ]
974 : : }
975 : :
976 : : static inline void
977 : 5450431 : ftl_l2p_cache_init_page_set(struct ftl_l2p_page_set *page_set, struct ftl_l2p_pin_ctx *pin_ctx)
978 : : {
979 [ # # # # ]: 5450431 : page_set->to_pin_cnt = 0;
980 [ # # # # ]: 5450431 : page_set->pinned_cnt = 0;
981 [ # # # # ]: 5450431 : page_set->pin_fault_cnt = 0;
982 [ # # # # ]: 5450431 : page_set->locked = 0;
983 [ # # # # ]: 5450431 : page_set->deferred = 0;
984 [ # # # # ]: 5450431 : page_set->pin_ctx = pin_ctx;
985 : 5450431 : }
986 : :
987 : : static inline bool
988 : 22498409 : ftl_l2p_cache_running(struct ftl_l2p_cache *cache)
989 : : {
990 [ # # # # ]: 22498409 : return cache->state == L2P_CACHE_RUNNING;
991 : : }
992 : :
993 : : static inline bool
994 : 5450431 : ftl_l2p_cache_page_is_pinnable(struct ftl_l2p_page *page)
995 : : {
996 [ # # # # ]: 5450431 : return page->state != L2P_CACHE_PAGE_INIT;
997 : : }
998 : :
999 : : void
1000 : 5450431 : ftl_l2p_cache_pin(struct spdk_ftl_dev *dev, struct ftl_l2p_pin_ctx *pin_ctx)
1001 : : {
1002 [ - + # # : 5450431 : assert(dev->num_lbas >= pin_ctx->lba + pin_ctx->count);
# # # # #
# # # # #
# # ]
1003 [ # # # # ]: 5450431 : struct ftl_l2p_cache *cache = (struct ftl_l2p_cache *)dev->l2p;
1004 : : struct ftl_l2p_page_set *page_set;
1005 : 5450431 : bool defer_pin = false;
1006 : :
1007 : : /* Calculate first and last page to pin, count of them */
1008 [ - + # # : 5450431 : uint64_t start = pin_ctx->lba / cache->lbas_in_page;
# # # # #
# ]
1009 [ - + # # : 5450431 : uint64_t end = (pin_ctx->lba + pin_ctx->count - 1) / cache->lbas_in_page;
# # # # #
# # # #
# ]
1010 : 5450431 : uint64_t count = end - start + 1;
1011 : : uint64_t i;
1012 : :
1013 [ - + ]: 5450431 : if (spdk_unlikely(count > L2P_MAX_PAGES_TO_PIN)) {
1014 : 0 : ftl_l2p_pin_complete(dev, -E2BIG, pin_ctx);
1015 : 0 : return;
1016 : : }
1017 : :
1018 : : /* Get and initialize page sets */
1019 [ - + # # ]: 5450431 : assert(ftl_l2p_cache_running(cache));
1020 [ # # # # ]: 5450431 : page_set = ftl_mempool_get(cache->page_sets_pool);
1021 [ - + ]: 5450431 : if (!page_set) {
1022 : 0 : ftl_l2p_pin_complete(dev, -EAGAIN, pin_ctx);
1023 : 0 : return;
1024 : : }
1025 : 5450431 : ftl_l2p_cache_init_page_set(page_set, pin_ctx);
1026 : :
1027 [ # # ]: 5450431 : struct ftl_l2p_page_wait_ctx *entry = page_set->entry;
1028 [ + + # # ]: 10900862 : for (i = start; i <= end; i++, entry++) {
1029 : : struct ftl_l2p_page *page;
1030 [ # # # # ]: 5450431 : entry->parent = page_set;
1031 [ # # # # ]: 5450431 : entry->pg_no = i;
1032 [ # # # # ]: 5450431 : entry->pg_pin_completed = false;
1033 [ # # # # ]: 5450431 : entry->pg_pin_issued = false;
1034 : :
1035 [ # # ]: 5450431 : page_set->to_pin_cnt++;
1036 : :
1037 : : /* Try get page and pin */
1038 : 5450431 : page = get_l2p_page_by_df_id(cache, i);
1039 [ + + ]: 5450431 : if (page) {
1040 [ + + ]: 5024651 : if (ftl_l2p_cache_page_is_pinnable(page)) {
1041 : : /* Page available and we can pin it */
1042 [ # # ]: 4777254 : page_set->pinned_cnt++;
1043 [ # # # # ]: 4777254 : entry->pg_pin_issued = true;
1044 [ # # # # ]: 4777254 : entry->pg_pin_completed = true;
1045 : 4777254 : ftl_l2p_cache_page_pin(cache, page);
1046 : 0 : } else {
1047 : : /* The page is being loaded */
1048 : : /* Queue the page pin entry to be executed on page in */
1049 : 247397 : ftl_l2p_page_queue_wait_ctx(page, entry);
1050 [ # # # # ]: 247397 : entry->pg_pin_issued = true;
1051 : : }
1052 : 0 : } else {
1053 : : /* The page is not in the cache, queue the page_set to page in */
1054 : 425780 : defer_pin = true;
1055 : : }
1056 : 0 : }
1057 : :
1058 : : /* Check if page set is done */
1059 [ + + ]: 5450431 : if (page_set_is_done(page_set)) {
1060 : 4777254 : page_set_end(dev, cache, page_set);
1061 [ + + # # ]: 673177 : } else if (defer_pin) {
1062 [ # # # # : 425780 : TAILQ_INSERT_TAIL(&cache->deferred_page_set_list, page_set, list_entry);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
1063 [ # # # # ]: 425780 : page_set->deferred = 1;
1064 : 0 : }
1065 : 0 : }
1066 : :
1067 : : void
1068 : 5450431 : ftl_l2p_cache_unpin(struct spdk_ftl_dev *dev, uint64_t lba, uint64_t count)
1069 : : {
1070 [ - + # # : 5450431 : assert(dev->num_lbas >= lba + count);
# # # # ]
1071 [ # # # # ]: 5450431 : struct ftl_l2p_cache *cache = (struct ftl_l2p_cache *)dev->l2p;
1072 : : struct ftl_l2p_page *page;
1073 [ - + # # : 5450431 : uint64_t start = lba / cache->lbas_in_page;
# # ]
1074 [ - + # # : 5450431 : uint64_t end = (lba + count - 1) / cache->lbas_in_page;
# # ]
1075 : : uint64_t i;
1076 : :
1077 [ - + # # ]: 5450431 : assert(count);
1078 [ - + # # : 5450431 : assert(start < cache->num_pages);
# # # # ]
1079 [ - + # # : 5450431 : assert(end < cache->num_pages);
# # # # ]
1080 : :
1081 [ + + ]: 10900862 : for (i = start; i <= end; i++) {
1082 : 5450431 : page = get_l2p_page_by_df_id(cache, i);
1083 [ - + # # ]: 5450431 : ftl_bug(!page);
1084 : 5450431 : ftl_l2p_cache_page_unpin(cache, page);
1085 : 0 : }
1086 : 5450431 : }
1087 : :
1088 : : ftl_addr
1089 : 13652352 : ftl_l2p_cache_get(struct spdk_ftl_dev *dev, uint64_t lba)
1090 : : {
1091 [ - + # # : 13652352 : assert(dev->num_lbas > lba);
# # # # ]
1092 [ # # # # ]: 13652352 : struct ftl_l2p_cache *cache = (struct ftl_l2p_cache *)dev->l2p;
1093 : 13652352 : struct ftl_l2p_page *page = get_page(cache, lba);
1094 : : ftl_addr addr;
1095 : :
1096 [ - + # # ]: 13652352 : ftl_bug(!page);
1097 [ - + # # ]: 13652352 : assert(ftl_l2p_cache_running(cache));
1098 [ - + # # : 13652352 : assert(page->pin_ref_cnt);
# # # # ]
1099 : :
1100 [ + + # # : 13652352 : if (ftl_bitmap_get(dev->trim_map, page->page_no)) {
# # # # #
# ]
1101 : 4 : ftl_l2p_page_set_invalid(dev, page);
1102 [ # # # # : 4 : ftl_bitmap_clear(dev->trim_map, page->page_no);
# # # # ]
1103 : 0 : }
1104 : :
1105 : 13652352 : ftl_l2p_cache_lru_promote_page(cache, page);
1106 : 13652352 : addr = ftl_l2p_cache_get_addr(dev, cache, page, lba);
1107 : :
1108 : 13652352 : return addr;
1109 : : }
1110 : :
1111 : : void
1112 : 3395622 : ftl_l2p_cache_set(struct spdk_ftl_dev *dev, uint64_t lba, ftl_addr addr)
1113 : : {
1114 [ - + # # : 3395622 : assert(dev->num_lbas > lba);
# # # # ]
1115 [ # # # # ]: 3395622 : struct ftl_l2p_cache *cache = (struct ftl_l2p_cache *)dev->l2p;
1116 : 3395622 : struct ftl_l2p_page *page = get_page(cache, lba);
1117 : :
1118 [ - + # # ]: 3395622 : ftl_bug(!page);
1119 [ - + # # ]: 3395622 : assert(ftl_l2p_cache_running(cache));
1120 [ - + # # : 3395622 : assert(page->pin_ref_cnt);
# # # # ]
1121 : :
1122 [ - + # # : 3395622 : if (ftl_bitmap_get(dev->trim_map, page->page_no)) {
# # # # #
# ]
1123 : 0 : ftl_l2p_page_set_invalid(dev, page);
1124 [ # # # # : 0 : ftl_bitmap_clear(dev->trim_map, page->page_no);
# # # # ]
1125 : 0 : }
1126 : :
1127 [ # # ]: 3395622 : page->updates++;
1128 : 3395622 : ftl_l2p_cache_lru_promote_page(cache, page);
1129 : 3395622 : ftl_l2p_cache_set_addr(dev, cache, page, lba, addr);
1130 : 3395622 : }
1131 : :
1132 : : static struct ftl_l2p_page *
1133 : 118535 : page_allocate(struct ftl_l2p_cache *cache, uint64_t page_no)
1134 : : {
1135 : 118535 : struct ftl_l2p_page *page = ftl_l2p_cache_page_alloc(cache, page_no);
1136 : 118535 : ftl_l2p_cache_page_insert(cache, page);
1137 : :
1138 : 118535 : return page;
1139 : : }
1140 : :
1141 : : static bool
1142 : 6548918 : page_set_is_done(struct ftl_l2p_page_set *page_set)
1143 : : {
1144 [ - + # # : 6548918 : if (page_set->locked) {
# # ]
1145 : 0 : return false;
1146 : : }
1147 : :
1148 [ - + # # : 6548918 : assert(page_set->pinned_cnt + page_set->pin_fault_cnt <= page_set->to_pin_cnt);
# # # # #
# # # # #
# # ]
1149 [ # # # # : 6548918 : return (page_set->pinned_cnt + page_set->pin_fault_cnt == page_set->to_pin_cnt);
# # # # #
# # # ]
1150 : 0 : }
1151 : :
1152 : : static void
1153 : 0 : page_set_unpin(struct ftl_l2p_cache *cache, struct ftl_l2p_page_set *page_set)
1154 : : {
1155 : : uint64_t i;
1156 [ # # ]: 0 : struct ftl_l2p_page_wait_ctx *pentry = page_set->entry;
1157 : :
1158 [ # # # # : 0 : for (i = 0; i < page_set->to_pin_cnt; i++, pentry++) {
# # # # ]
1159 : : struct ftl_l2p_page *pinned_page;
1160 : :
1161 [ # # # # : 0 : if (false == pentry->pg_pin_completed) {
# # ]
1162 : 0 : continue;
1163 : : }
1164 : :
1165 [ # # # # ]: 0 : pinned_page = get_l2p_page_by_df_id(cache, pentry->pg_no);
1166 [ # # # # ]: 0 : ftl_bug(!pinned_page);
1167 : :
1168 : 0 : ftl_l2p_cache_page_unpin(cache, pinned_page);
1169 : 0 : }
1170 : 0 : }
1171 : :
1172 : : static void
1173 : 5450431 : page_set_end(struct spdk_ftl_dev *dev, struct ftl_l2p_cache *cache,
1174 : : struct ftl_l2p_page_set *page_set)
1175 : : {
1176 [ + - # # : 5450431 : if (spdk_likely(0 == page_set->pin_fault_cnt)) {
# # ]
1177 [ # # # # ]: 5450431 : ftl_l2p_pin_complete(dev, 0, page_set->pin_ctx);
1178 : 0 : } else {
1179 : 0 : page_set_unpin(cache, page_set);
1180 [ # # # # ]: 0 : ftl_l2p_pin_complete(dev, -EIO, page_set->pin_ctx);
1181 : : }
1182 : :
1183 [ - + # # : 5450431 : if (page_set->deferred) {
# # ]
1184 [ # # # # : 0 : TAILQ_REMOVE(&cache->deferred_page_set_list, page_set, list_entry);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
1185 : 0 : }
1186 : :
1187 [ - + # # : 5450431 : assert(0 == page_set->locked);
# # # # ]
1188 [ # # # # ]: 5450431 : ftl_mempool_put(cache->page_sets_pool, page_set);
1189 : 5450431 : }
1190 : :
1191 : : static void
1192 : 118535 : page_in_io_complete(struct spdk_ftl_dev *dev, struct ftl_l2p_cache *cache,
1193 : : struct ftl_l2p_page *page, bool success)
1194 : : {
1195 : : struct ftl_l2p_page_set *page_set;
1196 : : struct ftl_l2p_page_wait_ctx *pentry;
1197 : :
1198 [ # # ]: 118535 : cache->ios_in_flight--;
1199 : :
1200 [ - + # # : 118535 : assert(0 == page->pin_ref_cnt);
# # # # ]
1201 [ - + # # : 118535 : assert(L2P_CACHE_PAGE_INIT == page->state);
# # # # ]
1202 [ - + - + : 118535 : assert(false == page->on_lru_list);
# # # # #
# ]
1203 : :
1204 [ + - # # ]: 118535 : if (spdk_likely(success)) {
1205 [ # # # # ]: 118535 : page->state = L2P_CACHE_PAGE_READY;
1206 : 0 : }
1207 : :
1208 [ + + # # : 909777 : while ((pentry = TAILQ_FIRST(&page->ppe_list))) {
# # # # ]
1209 [ + + # # : 672707 : TAILQ_REMOVE(&page->ppe_list, pentry, list_entry);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
1210 : :
1211 [ # # # # ]: 672707 : page_set = pentry->parent;
1212 : :
1213 [ - + # # : 672707 : assert(false == pentry->pg_pin_completed);
# # # # ]
1214 : :
1215 [ + - # # ]: 672707 : if (success) {
1216 : 672707 : ftl_l2p_cache_page_pin(cache, page);
1217 [ # # ]: 672707 : page_set->pinned_cnt++;
1218 [ # # # # ]: 672707 : pentry->pg_pin_completed = true;
1219 : 0 : } else {
1220 [ # # ]: 0 : page_set->pin_fault_cnt++;
1221 : : }
1222 : :
1223 : : /* Check if page_set is done */
1224 [ + - ]: 672707 : if (page_set_is_done(page_set)) {
1225 : 672707 : page_set_end(dev, cache, page_set);
1226 : 0 : }
1227 : : }
1228 : :
1229 [ - + # # ]: 118535 : if (spdk_unlikely(!success)) {
1230 [ # # # # : 0 : ftl_bug(page->on_lru_list);
# # # # #
# ]
1231 : 0 : ftl_l2p_cache_page_remove(cache, page);
1232 : 0 : }
1233 : 118535 : }
1234 : :
1235 : : static void
1236 : 118535 : page_in_io_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
1237 : : {
1238 : 118535 : struct ftl_l2p_page *page = cb_arg;
1239 [ # # # # : 118535 : struct ftl_l2p_cache *cache = page->ctx.cache;
# # ]
1240 [ # # # # ]: 118535 : struct spdk_ftl_dev *dev = cache->dev;
1241 : :
1242 : 118535 : ftl_stats_bdev_io_completed(dev, FTL_STATS_TYPE_L2P, bdev_io);
1243 : 118535 : spdk_bdev_free_io(bdev_io);
1244 [ # # ]: 118535 : page_in_io_complete(dev, cache, page, success);
1245 : 118535 : }
1246 : :
1247 : : static void
1248 : 118535 : page_in_io(struct spdk_ftl_dev *dev, struct ftl_l2p_cache *cache, struct ftl_l2p_page *page)
1249 : : {
1250 : : struct spdk_io_channel *ioch;
1251 : : struct spdk_bdev *bdev;
1252 : : struct spdk_bdev_io_wait_entry *bdev_io_wait;
1253 : : int rc;
1254 [ # # # # : 118535 : page->ctx.cache = cache;
# # ]
1255 : :
1256 [ # # # # ]: 118535 : rc = ftl_nv_cache_bdev_read_blocks_with_md(cache->dev, ftl_l2p_cache_get_bdev_desc(cache),
1257 : 0 : ftl_l2p_cache_get_bdev_iochannel(cache),
1258 [ # # # # ]: 0 : page->page_buffer, NULL, ftl_l2p_cache_page_get_bdev_offset(cache, page),
1259 : 0 : 1, page_in_io_cb, page);
1260 [ # # ]: 118535 : cache->ios_in_flight++;
1261 [ + - ]: 118535 : if (spdk_likely(0 == rc)) {
1262 : 118535 : return;
1263 : : }
1264 : :
1265 [ # # ]: 0 : if (rc == -ENOMEM) {
1266 : 0 : ioch = ftl_l2p_cache_get_bdev_iochannel(cache);
1267 : 0 : bdev = spdk_bdev_desc_get_bdev(ftl_l2p_cache_get_bdev_desc(cache));
1268 [ # # # # ]: 0 : bdev_io_wait = &page->ctx.bdev_io_wait;
1269 [ # # # # ]: 0 : bdev_io_wait->bdev = bdev;
1270 [ # # # # ]: 0 : bdev_io_wait->cb_fn = page_in_io_retry;
1271 [ # # # # ]: 0 : bdev_io_wait->cb_arg = page;
1272 : :
1273 : 0 : rc = spdk_bdev_queue_io_wait(bdev, ioch, bdev_io_wait);
1274 [ # # # # ]: 0 : ftl_bug(rc);
1275 : 0 : } else {
1276 [ # # ]: 0 : ftl_abort();
1277 : : }
1278 : 0 : }
1279 : :
1280 : : static void
1281 : 0 : page_in_io_retry(void *arg)
1282 : : {
1283 : 0 : struct ftl_l2p_page *page = arg;
1284 [ # # # # : 0 : struct ftl_l2p_cache *cache = page->ctx.cache;
# # ]
1285 [ # # # # ]: 0 : struct spdk_ftl_dev *dev = cache->dev;
1286 : :
1287 [ # # ]: 0 : cache->ios_in_flight--;
1288 : 0 : page_in_io(dev, cache, page);
1289 : 0 : }
1290 : :
1291 : : static void
1292 : 425780 : page_in(struct spdk_ftl_dev *dev, struct ftl_l2p_cache *cache,
1293 : : struct ftl_l2p_page_set *page_set, struct ftl_l2p_page_wait_ctx *pentry)
1294 : : {
1295 : : struct ftl_l2p_page *page;
1296 : 425780 : bool page_in = false;
1297 : :
1298 : : /* Get page */
1299 [ # # # # ]: 425780 : page = get_l2p_page_by_df_id(cache, pentry->pg_no);
1300 [ + + ]: 425780 : if (!page) {
1301 : : /* Page not allocated yet, do it */
1302 [ # # # # ]: 118535 : page = page_allocate(cache, pentry->pg_no);
1303 : 118535 : page_in = true;
1304 : 0 : }
1305 : :
1306 [ + + ]: 425780 : if (ftl_l2p_cache_page_is_pinnable(page)) {
1307 : 470 : ftl_l2p_cache_page_pin(cache, page);
1308 [ # # ]: 470 : page_set->pinned_cnt++;
1309 [ # # # # ]: 470 : pentry->pg_pin_issued = true;
1310 [ # # # # ]: 470 : pentry->pg_pin_completed = true;
1311 : 0 : } else {
1312 [ # # # # ]: 425310 : pentry->pg_pin_issued = true;
1313 : 425310 : ftl_l2p_page_queue_wait_ctx(page, pentry);
1314 : : }
1315 : :
1316 [ + + # # ]: 425780 : if (page_in) {
1317 : 118535 : page_in_io(dev, cache, page);
1318 : 0 : }
1319 : 425780 : }
1320 : :
1321 : : static int
1322 : 23664763 : ftl_l2p_cache_process_page_sets(struct spdk_ftl_dev *dev, struct ftl_l2p_cache *cache)
1323 : : {
1324 : : struct ftl_l2p_page_set *page_set;
1325 : : struct ftl_l2p_page_wait_ctx *pentry;
1326 : : uint64_t i;
1327 : :
1328 [ # # # # : 23664763 : page_set = TAILQ_FIRST(&cache->deferred_page_set_list);
# # ]
1329 [ + + ]: 23664763 : if (!page_set) {
1330 : : /* No page_set */
1331 : 23203170 : return -ECHILD;
1332 : : }
1333 : :
1334 [ + + # # : 461593 : if (page_set->to_pin_cnt > cache->l2_pgs_avail) {
# # # # #
# ]
1335 : : /* No enough page to pin, wait */
1336 : 35813 : return -EBUSY;
1337 : : }
1338 [ - + # # : 425780 : if (cache->ios_in_flight > 512) {
# # ]
1339 : : /* Too big QD */
1340 : 0 : return -EBUSY;
1341 : : }
1342 : :
1343 : 425780 : ftl_add_io_activity(dev);
1344 : :
1345 [ + + # # : 425780 : TAILQ_REMOVE(&cache->deferred_page_set_list, page_set, list_entry);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
1346 [ # # # # ]: 425780 : page_set->deferred = 0;
1347 [ # # # # ]: 425780 : page_set->locked = 1;
1348 : :
1349 : : /* Now we can start pinning */
1350 [ # # ]: 425780 : pentry = page_set->entry;
1351 [ + + # # : 851560 : for (i = 0; i < page_set->to_pin_cnt; i++, pentry++) {
# # # # ]
1352 [ + - # # : 425780 : if (!pentry->pg_pin_issued) {
# # ]
1353 : 425780 : page_in(dev, cache, page_set, pentry);
1354 : 0 : }
1355 : 0 : }
1356 : :
1357 [ # # # # ]: 425780 : page_set->locked = 0;
1358 : :
1359 : : /* Check if page_set is done */
1360 [ + + ]: 425780 : if (page_set_is_done(page_set)) {
1361 : 470 : page_set_end(dev, cache, page_set);
1362 : 0 : }
1363 : :
1364 : 425780 : return 0;
1365 : 0 : }
1366 : :
1367 : : static struct ftl_l2p_page *
1368 : 84122 : eviction_get_page(struct spdk_ftl_dev *dev, struct ftl_l2p_cache *cache)
1369 : : {
1370 : 84122 : uint64_t i = 0;
1371 : 84122 : struct ftl_l2p_page *page = ftl_l2p_cache_get_coldest_page(cache);
1372 : :
1373 [ + - ]: 84122 : while (page) {
1374 [ - + # # : 84122 : ftl_bug(L2P_CACHE_PAGE_READY != page->state);
# # # # ]
1375 [ - + # # : 84122 : ftl_bug(page->pin_ref_cnt);
# # # # ]
1376 : :
1377 [ + - ]: 84122 : if (ftl_l2p_cache_page_can_evict(page)) {
1378 : 84122 : ftl_l2p_cache_lru_remove_page(cache, page);
1379 : 84122 : return page;
1380 : : }
1381 : :
1382 : : /*
1383 : : * Practically only one iteration is needed to find a page. It is because
1384 : : * the rank of pages contains only ready and unpinned pages
1385 : : */
1386 [ # # # # ]: 0 : ftl_bug(++i > 1024);
1387 : :
1388 : 0 : page = ftl_l2p_cache_get_hotter_page(page);
1389 : : }
1390 : :
1391 : 0 : return NULL;
1392 : 0 : }
1393 : :
1394 : : static void
1395 : 81448 : page_out_io_complete(struct spdk_ftl_dev *dev, struct ftl_l2p_cache *cache,
1396 : : struct ftl_l2p_page *page, bool success)
1397 : : {
1398 [ # # ]: 81448 : cache->l2_pgs_evicting--;
1399 : :
1400 [ - + # # : 81448 : ftl_bug(page->ctx.updates > page->updates);
# # # # #
# # # #
# ]
1401 [ - + # # : 81448 : ftl_bug(!TAILQ_EMPTY(&page->ppe_list));
# # # # #
# ]
1402 [ - + - + : 81448 : ftl_bug(page->on_lru_list);
# # # # #
# ]
1403 : :
1404 [ + - # # ]: 81448 : if (spdk_likely(success)) {
1405 [ # # # # : 81448 : page->updates -= page->ctx.updates;
# # # # #
# ]
1406 : 0 : }
1407 : :
1408 [ + - + + : 81448 : if (success && ftl_l2p_cache_page_can_remove(page)) {
# # ]
1409 : 81435 : ftl_l2p_cache_page_remove(cache, page);
1410 : 0 : } else {
1411 [ - + # # : 13 : if (!page->pin_ref_cnt) {
# # ]
1412 : 0 : ftl_l2p_cache_lru_add_page(cache, page);
1413 : 0 : }
1414 [ # # # # ]: 13 : page->state = L2P_CACHE_PAGE_READY;
1415 : : }
1416 : 81448 : }
1417 : :
1418 : : static void
1419 : 81448 : page_out_io_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
1420 : : {
1421 : 81448 : struct ftl_l2p_page *page = cb_arg;
1422 [ # # # # : 81448 : struct ftl_l2p_cache *cache = page->ctx.cache;
# # ]
1423 [ # # # # ]: 81448 : struct spdk_ftl_dev *dev = cache->dev;
1424 : :
1425 : 81448 : ftl_stats_bdev_io_completed(dev, FTL_STATS_TYPE_L2P, bdev_io);
1426 : 81448 : spdk_bdev_free_io(bdev_io);
1427 [ # # ]: 81448 : page_out_io_complete(dev, cache, page, success);
1428 : 81448 : }
1429 : :
1430 : : static void
1431 : 81448 : page_out_io(struct spdk_ftl_dev *dev, struct ftl_l2p_cache *cache,
1432 : : struct ftl_l2p_page *page)
1433 : : {
1434 : : struct spdk_io_channel *ioch;
1435 : : struct spdk_bdev *bdev;
1436 : : struct spdk_bdev_io_wait_entry *bdev_io_wait;
1437 : : int rc;
1438 : :
1439 [ # # # # : 81448 : page->ctx.cache = cache;
# # ]
1440 : :
1441 : 81448 : rc = ftl_nv_cache_bdev_write_blocks_with_md(dev, ftl_l2p_cache_get_bdev_desc(cache),
1442 : 0 : ftl_l2p_cache_get_bdev_iochannel(cache),
1443 [ # # # # ]: 0 : page->page_buffer, NULL, ftl_l2p_cache_page_get_bdev_offset(cache, page),
1444 : 0 : 1, page_out_io_cb, page);
1445 : :
1446 [ # # ]: 81448 : cache->l2_pgs_evicting++;
1447 [ + - ]: 81448 : if (spdk_likely(0 == rc)) {
1448 : 81448 : return;
1449 : : }
1450 : :
1451 [ # # ]: 0 : if (rc == -ENOMEM) {
1452 : 0 : ioch = ftl_l2p_cache_get_bdev_iochannel(cache);
1453 : 0 : bdev = spdk_bdev_desc_get_bdev(ftl_l2p_cache_get_bdev_desc(cache));
1454 [ # # # # ]: 0 : bdev_io_wait = &page->ctx.bdev_io_wait;
1455 [ # # # # ]: 0 : bdev_io_wait->bdev = bdev;
1456 [ # # # # ]: 0 : bdev_io_wait->cb_fn = page_out_io_retry;
1457 [ # # # # ]: 0 : bdev_io_wait->cb_arg = page;
1458 : :
1459 : 0 : rc = spdk_bdev_queue_io_wait(bdev, ioch, bdev_io_wait);
1460 [ # # # # ]: 0 : ftl_bug(rc);
1461 : 0 : } else {
1462 [ # # ]: 0 : ftl_abort();
1463 : : }
1464 : 0 : }
1465 : :
1466 : : static void
1467 : 0 : page_out_io_retry(void *arg)
1468 : : {
1469 : 0 : struct ftl_l2p_page *page = arg;
1470 [ # # # # : 0 : struct ftl_l2p_cache *cache = page->ctx.cache;
# # ]
1471 [ # # # # ]: 0 : struct spdk_ftl_dev *dev = cache->dev;
1472 : :
1473 [ # # ]: 0 : cache->l2_pgs_evicting--;
1474 : 0 : page_out_io(dev, cache, page);
1475 : 0 : }
1476 : :
1477 : : static void
1478 : 23239879 : ftl_l2p_cache_process_eviction(struct spdk_ftl_dev *dev, struct ftl_l2p_cache *cache)
1479 : : {
1480 : : struct ftl_l2p_page *page;
1481 : :
1482 [ + + ]: 23239879 : if (!ftl_l2p_cache_evict_continue(cache)) {
1483 : 23155757 : return;
1484 : : }
1485 : :
1486 [ - + # # : 84122 : if (cache->l2_pgs_evicting > 512) {
# # ]
1487 : 0 : return;
1488 : : }
1489 : :
1490 : 84122 : ftl_add_io_activity(dev);
1491 : :
1492 : 84122 : page = eviction_get_page(dev, cache);
1493 [ - + ]: 84122 : if (spdk_unlikely(!page)) {
1494 : 0 : return;
1495 : : }
1496 : :
1497 [ + + # # : 84122 : if (page->updates) {
# # ]
1498 [ # # # # ]: 81448 : page->state = L2P_CACHE_PAGE_FLUSHING;
1499 [ # # # # : 81448 : page->ctx.updates = page->updates;
# # # # #
# ]
1500 : 81448 : page_out_io(dev, cache, page);
1501 : 0 : } else {
1502 : : /* Page clean and we can remove it */
1503 : 2674 : ftl_l2p_cache_page_remove(cache, page);
1504 : : }
1505 : 0 : }
1506 : :
1507 : : static void
1508 : 4 : ftl_l2p_lazy_trim_process_cb(struct spdk_ftl_dev *dev, int status, struct ftl_l2p_pin_ctx *pin_ctx)
1509 : : {
1510 [ # # # # ]: 4 : struct ftl_l2p_cache *cache = dev->l2p;
1511 : :
1512 [ # # # # ]: 4 : cache->lazy_trim.qd--;
1513 : :
1514 : : /* We will retry on next ftl_l2p_lazy_trim_process */
1515 [ - + ]: 4 : if (spdk_unlikely(status != 0)) {
1516 : 0 : return;
1517 : : }
1518 : :
1519 [ + - ]: 4 : if (ftl_l2p_cache_running(cache)) {
1520 [ # # # # ]: 4 : ftl_l2p_cache_get(dev, pin_ctx->lba);
1521 : 0 : }
1522 : :
1523 [ # # # # : 4 : ftl_l2p_cache_unpin(dev, pin_ctx->lba, pin_ctx->count);
# # # # ]
1524 : 0 : }
1525 : :
1526 : : static void
1527 : 23239879 : ftl_l2p_lazy_trim_process(struct spdk_ftl_dev *dev)
1528 : : {
1529 [ # # # # ]: 23239879 : struct ftl_l2p_cache *cache = dev->l2p;
1530 : : struct ftl_l2p_pin_ctx *pin_ctx;
1531 : : uint64_t page_no;
1532 : :
1533 [ - + + + : 23239879 : if (spdk_likely(!dev->trim_in_progress)) {
# # # # ]
1534 : 23239838 : return;
1535 : : }
1536 : :
1537 [ + + # # : 41 : if (cache->lazy_trim.qd == FTL_L2P_MAX_LAZY_TRIM_QD) {
# # # # ]
1538 : 33 : return;
1539 : : }
1540 : :
1541 [ # # # # : 8 : page_no = ftl_bitmap_find_first_set(dev->trim_map, cache->lazy_trim.page_no, UINT64_MAX);
# # # # #
# ]
1542 [ + + ]: 8 : if (page_no == UINT64_MAX) {
1543 [ # # # # : 4 : cache->lazy_trim.page_no = 0;
# # ]
1544 : :
1545 : : /* Check trim map from beginning to detect unprocessed trims */
1546 [ # # # # : 4 : page_no = ftl_bitmap_find_first_set(dev->trim_map, cache->lazy_trim.page_no, UINT64_MAX);
# # # # #
# ]
1547 [ + - ]: 4 : if (page_no == UINT64_MAX) {
1548 [ # # # # ]: 4 : dev->trim_in_progress = false;
1549 : 4 : return;
1550 : : }
1551 : 0 : }
1552 : :
1553 [ # # # # : 4 : cache->lazy_trim.page_no = page_no;
# # ]
1554 : :
1555 [ # # # # ]: 4 : pin_ctx = &cache->lazy_trim.pin_ctx;
1556 : :
1557 [ # # # # ]: 4 : cache->lazy_trim.qd++;
1558 [ - + # # : 4 : assert(cache->lazy_trim.qd <= FTL_L2P_MAX_LAZY_TRIM_QD);
# # # # #
# ]
1559 [ - + # # : 4 : assert(page_no < cache->num_pages);
# # # # ]
1560 : :
1561 [ # # # # : 4 : pin_ctx->lba = page_no * cache->lbas_in_page;
# # # # ]
1562 [ # # # # ]: 4 : pin_ctx->count = 1;
1563 [ # # # # ]: 4 : pin_ctx->cb = ftl_l2p_lazy_trim_process_cb;
1564 [ # # # # ]: 4 : pin_ctx->cb_ctx = pin_ctx;
1565 : :
1566 : 4 : ftl_l2p_cache_pin(dev, pin_ctx);
1567 : 0 : }
1568 : :
1569 : : void
1570 : 23241150 : ftl_l2p_cache_process(struct spdk_ftl_dev *dev)
1571 : : {
1572 [ # # # # ]: 23241150 : struct ftl_l2p_cache *cache = dev->l2p;
1573 : : int i;
1574 : :
1575 [ + + # # : 23241150 : if (spdk_unlikely(cache->state != L2P_CACHE_RUNNING)) {
# # ]
1576 : 1271 : return;
1577 : : }
1578 : :
1579 [ + + # # ]: 23665659 : for (i = 0; i < 256; i++) {
1580 [ + + ]: 23664763 : if (ftl_l2p_cache_process_page_sets(dev, cache)) {
1581 : 23238983 : break;
1582 : : }
1583 : 0 : }
1584 : :
1585 : 23239879 : ftl_l2p_cache_process_eviction(dev, cache);
1586 : 23239879 : ftl_l2p_lazy_trim_process(dev);
1587 : 0 : }
|