LCOV - code coverage report
Current view: top level - spdk/lib/ftl - ftl_l2p_cache.c (source / functions) Hit Total Coverage
Test: Combined Lines: 561 739 75.9 %
Date: 2024-07-12 17:35:58 Functions: 67 76 88.2 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 217 418 51.9 %

           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                 :     683805 : ftl_l2p_page_queue_wait_ctx(struct ftl_l2p_page *page,
     161                 :            :                             struct ftl_l2p_page_wait_ctx *ppe)
     162                 :            : {
     163                 :     683805 :         TAILQ_INSERT_TAIL(&page->ppe_list, ppe, list_entry);
     164                 :     683805 : }
     165                 :            : 
     166                 :            : static inline uint64_t
     167                 :         66 : ftl_l2p_cache_get_l1_page_size(void)
     168                 :            : {
     169                 :         66 :         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                 :         44 : ftl_l2p_cache_get_page_all_size(void)
     180                 :            : {
     181                 :         44 :         return sizeof(struct ftl_l2p_page) + ftl_l2p_cache_get_l1_page_size();
     182                 :            : }
     183                 :            : 
     184                 :            : static void
     185                 :    1192089 : ftl_l2p_cache_lru_remove_page(struct ftl_l2p_cache *cache, struct ftl_l2p_page *page)
     186                 :            : {
     187         [ -  + ]:    1192089 :         assert(page);
     188   [ -  +  -  + ]:    1192089 :         assert(page->on_lru_list);
     189                 :            : 
     190         [ +  + ]:    1192089 :         TAILQ_REMOVE(&cache->lru_list, page, list_entry);
     191                 :    1192089 :         page->on_lru_list = false;
     192                 :    1192089 : }
     193                 :            : 
     194                 :            : static void
     195                 :    1192089 : ftl_l2p_cache_lru_add_page(struct ftl_l2p_cache *cache, struct ftl_l2p_page *page)
     196                 :            : {
     197         [ -  + ]:    1192089 :         assert(page);
     198   [ -  +  -  + ]:    1192089 :         assert(!page->on_lru_list);
     199                 :            : 
     200         [ +  + ]:    1192089 :         TAILQ_INSERT_HEAD(&cache->lru_list, page, list_entry);
     201                 :            : 
     202                 :    1192089 :         page->on_lru_list = true;
     203                 :    1192089 : }
     204                 :            : 
     205                 :            : static void
     206                 :   14024835 : ftl_l2p_cache_lru_promote_page(struct ftl_l2p_cache *cache, struct ftl_l2p_page *page)
     207                 :            : {
     208   [ -  +  +  - ]:   14024835 :         if (!page->on_lru_list) {
     209                 :   14024835 :                 return;
     210                 :            :         }
     211                 :            : 
     212                 :          0 :         ftl_l2p_cache_lru_remove_page(cache, page);
     213                 :          0 :         ftl_l2p_cache_lru_add_page(cache, page);
     214                 :            : }
     215                 :            : 
     216                 :            : static inline void
     217                 :     123046 : ftl_l2p_cache_page_insert(struct ftl_l2p_cache *cache, struct ftl_l2p_page *page)
     218                 :            : {
     219                 :     123046 :         struct ftl_l2p_l1_map_entry *me = cache->l2_mapping;
     220         [ -  + ]:     123046 :         assert(me);
     221                 :            : 
     222         [ -  + ]:     123046 :         assert(me[page->page_no].page_obj_id == FTL_DF_OBJ_ID_INVALID);
     223                 :     123046 :         me[page->page_no].page_obj_id = page->obj_id;
     224                 :     123046 : }
     225                 :            : 
     226                 :            : static void
     227                 :     123353 : ftl_l2p_cache_page_remove(struct ftl_l2p_cache *cache, struct ftl_l2p_page *page)
     228                 :            : {
     229                 :     123353 :         struct ftl_l2p_l1_map_entry *me = cache->l2_mapping;
     230         [ -  + ]:     123353 :         assert(me);
     231         [ -  + ]:     123353 :         assert(me[page->page_no].page_obj_id != FTL_DF_OBJ_ID_INVALID);
     232         [ -  + ]:     123353 :         assert(TAILQ_EMPTY(&page->ppe_list));
     233                 :            : 
     234                 :     123353 :         me[page->page_no].page_obj_id = FTL_DF_OBJ_ID_INVALID;
     235                 :     123353 :         cache->l2_pgs_avail++;
     236                 :     123353 :         ftl_mempool_put(cache->l2_ctx_pool, page);
     237                 :     123353 : }
     238                 :            : 
     239                 :            : static inline struct ftl_l2p_page *
     240                 :      89017 : ftl_l2p_cache_get_coldest_page(struct ftl_l2p_cache *cache)
     241                 :            : {
     242                 :      89017 :         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                 :     226393 : ftl_l2p_cache_page_get_bdev_offset(struct ftl_l2p_cache *cache,
     253                 :            :                                    struct ftl_l2p_page *page)
     254                 :            : {
     255                 :     226393 :         return cache->cache_layout_offset + page->page_no;
     256                 :            : }
     257                 :            : 
     258                 :            : static inline struct spdk_bdev_desc *
     259                 :     226393 : ftl_l2p_cache_get_bdev_desc(struct ftl_l2p_cache *cache)
     260                 :            : {
     261                 :     226393 :         return cache->cache_layout_bdev_desc;
     262                 :            : }
     263                 :            : 
     264                 :            : static inline struct spdk_io_channel *
     265                 :     226393 : ftl_l2p_cache_get_bdev_iochannel(struct ftl_l2p_cache *cache)
     266                 :            : {
     267                 :     226393 :         return cache->cache_layout_ioch;
     268                 :            : }
     269                 :            : 
     270                 :            : static struct ftl_l2p_page *
     271                 :     123046 : ftl_l2p_cache_page_alloc(struct ftl_l2p_cache *cache, size_t page_no)
     272                 :            : {
     273                 :     123046 :         struct ftl_l2p_page *page = ftl_mempool_get(cache->l2_ctx_pool);
     274         [ -  + ]:     123046 :         ftl_bug(!page);
     275                 :            : 
     276                 :     123046 :         cache->l2_pgs_avail--;
     277                 :            : 
     278         [ -  + ]:     123046 :         memset(page, 0, sizeof(*page));
     279                 :            : 
     280                 :     123046 :         page->obj_id = ftl_mempool_get_df_obj_id(cache->l2_ctx_pool, page);
     281                 :            : 
     282                 :     246092 :         page->page_buffer = (char *)ftl_md_get_buffer(cache->l1_md) + ftl_mempool_get_df_obj_index(
     283                 :     123046 :                                     cache->l2_ctx_pool, page) * FTL_BLOCK_SIZE;
     284                 :            : 
     285                 :     123046 :         TAILQ_INIT(&page->ppe_list);
     286                 :            : 
     287                 :     123046 :         page->page_no = page_no;
     288                 :     123046 :         page->state = L2P_CACHE_PAGE_INIT;
     289                 :            : 
     290                 :     123046 :         return page;
     291                 :            : }
     292                 :            : 
     293                 :            : static inline bool
     294                 :      85043 : ftl_l2p_cache_page_can_remove(struct ftl_l2p_page *page)
     295                 :            : {
     296                 :      85043 :         return (!page->updates &&
     297   [ +  -  +  - ]:     170086 :                 page->state != L2P_CACHE_PAGE_INIT &&
     298         [ +  + ]:      85043 :                 !page->pin_ref_cnt);
     299                 :            : }
     300                 :            : 
     301                 :            : static inline ftl_addr
     302                 :   11287092 : 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         [ -  + ]:   11287092 :         return ftl_addr_load(dev, page->page_buffer, lba % cache->lbas_in_page);
     306                 :            : }
     307                 :            : 
     308                 :            : static inline void
     309                 :    2739791 : 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         [ -  + ]:    2739791 :         ftl_addr_store(dev, page->page_buffer, lba % cache->lbas_in_page, addr);
     313                 :    2739791 : }
     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                 :            :         }
     334                 :          4 : }
     335                 :            : 
     336                 :            : static inline void
     337                 :    4273291 : ftl_l2p_cache_page_pin(struct ftl_l2p_cache *cache, struct ftl_l2p_page *page)
     338                 :            : {
     339                 :    4273291 :         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   [ -  +  +  + ]:    4273291 :         if (page->on_lru_list) {
     342                 :    1068723 :                 ftl_l2p_cache_lru_remove_page(cache, page);
     343                 :            :         }
     344                 :    4273291 : }
     345                 :            : 
     346                 :            : static inline void
     347                 :    4273291 : ftl_l2p_cache_page_unpin(struct ftl_l2p_cache *cache, struct ftl_l2p_page *page)
     348                 :            : {
     349                 :    4273291 :         page->pin_ref_cnt--;
     350   [ +  +  -  +  :    4273291 :         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                 :    1191782 :                 ftl_l2p_cache_lru_add_page(cache, page);
     362                 :            :         }
     363                 :    4273291 : }
     364                 :            : 
     365                 :            : static inline bool
     366                 :      89017 : ftl_l2p_cache_page_can_evict(struct ftl_l2p_page *page)
     367                 :            : {
     368                 :      89017 :         return (page->state == L2P_CACHE_PAGE_FLUSHING ||
     369         [ +  - ]:      89017 :                 page->state == L2P_CACHE_PAGE_PERSISTING ||
     370         [ +  - ]:      89017 :                 page->state == L2P_CACHE_PAGE_INIT ||
     371   [ +  -  +  - ]:     178034 :                 page->pin_ref_cnt) ? false : true;
     372                 :            : }
     373                 :            : 
     374                 :            : static bool
     375                 :   18988144 : ftl_l2p_cache_evict_continue(struct ftl_l2p_cache *cache)
     376                 :            : {
     377                 :   18988144 :         return cache->l2_pgs_avail + cache->l2_pgs_evicting < cache->evict_keep;
     378                 :            : }
     379                 :            : 
     380                 :            : static void *
     381                 :         22 : _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                 :         22 :         uint64_t l2_pages = spdk_divide_round_up(l2p_size, ftl_l2p_cache_get_l1_page_size());
     385                 :         22 :         size_t l2_size = l2_pages * sizeof(struct ftl_l2p_l1_map_entry);
     386                 :            : 
     387                 :         22 :         cache = calloc(1, sizeof(struct ftl_l2p_cache));
     388         [ -  + ]:         22 :         if (cache == NULL) {
     389                 :          0 :                 return NULL;
     390                 :            :         }
     391                 :         22 :         cache->dev = dev;
     392                 :            : 
     393                 :         22 :         cache->l2_md = ftl_md_create(dev,
     394                 :            :                                      spdk_divide_round_up(l2_size, FTL_BLOCK_SIZE), 0,
     395                 :            :                                      FTL_L2P_CACHE_MD_NAME_L2,
     396                 :            :                                      ftl_md_create_shm_flags(dev), NULL);
     397                 :            : 
     398         [ -  + ]:         22 :         if (cache->l2_md == NULL) {
     399                 :          0 :                 goto fail_l2_md;
     400                 :            :         }
     401                 :         22 :         cache->l2_mapping = ftl_md_get_buffer(cache->l2_md);
     402                 :            : 
     403                 :         22 :         cache->lbas_in_page = dev->layout.l2p.lbas_in_page;
     404                 :         22 :         cache->num_pages = l2_pages;
     405                 :            : 
     406                 :         22 :         return cache;
     407                 :          0 : fail_l2_md:
     408                 :          0 :         free(cache);
     409                 :          0 :         return NULL;
     410                 :            : }
     411                 :            : 
     412                 :            : static struct ftl_l2p_page *
     413                 :   23437362 : get_l2p_page_by_df_id(struct ftl_l2p_cache *cache, size_t page_no)
     414                 :            : {
     415                 :   23437362 :         struct ftl_l2p_l1_map_entry *me = cache->l2_mapping;
     416                 :   23437362 :         ftl_df_obj_id obj_id = me[page_no].page_obj_id;
     417                 :            : 
     418         [ +  + ]:   23437362 :         if (obj_id != FTL_DF_OBJ_ID_INVALID) {
     419                 :   22482720 :                 return ftl_mempool_get_df_ptr(cache->l2_ctx_pool, obj_id);
     420                 :            :         }
     421                 :            : 
     422                 :     954642 :         return NULL;
     423                 :            : }
     424                 :            : 
     425                 :            : int
     426                 :         22 : ftl_l2p_cache_init(struct spdk_ftl_dev *dev)
     427                 :            : {
     428                 :         22 :         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                 :         22 :         void *l2p = _ftl_l2p_cache_init(dev, dev->layout.l2p.addr_size, l2p_size);
     432                 :         22 :         size_t page_sets_pool_size = 1 << 15;
     433                 :            :         size_t max_resident_size, max_resident_pgs;
     434                 :            : 
     435         [ -  + ]:         22 :         if (!l2p) {
     436                 :          0 :                 return -1;
     437                 :            :         }
     438                 :         22 :         dev->l2p = l2p;
     439                 :            : 
     440                 :         22 :         cache = (struct ftl_l2p_cache *)dev->l2p;
     441                 :         22 :         cache->page_sets_pool = ftl_mempool_create(page_sets_pool_size,
     442                 :            :                                 sizeof(struct ftl_l2p_page_set),
     443                 :            :                                 64, SPDK_ENV_SOCKET_ID_ANY);
     444         [ -  + ]:         22 :         if (!cache->page_sets_pool) {
     445                 :          0 :                 return -1;
     446                 :            :         }
     447                 :            : 
     448                 :         22 :         max_resident_size = dev->conf.l2p_dram_limit << 20;
     449         [ -  + ]:         22 :         max_resident_pgs = max_resident_size / ftl_l2p_cache_get_page_all_size();
     450                 :            : 
     451         [ -  + ]:         22 :         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                 :            :         }
     455                 :            : 
     456                 :            :         /* Round down max res pgs to the nearest # of l2/l1 pgs */
     457                 :         22 :         max_resident_size = max_resident_pgs * ftl_l2p_cache_get_page_all_size();
     458                 :         22 :         SPDK_NOTICELOG("l2p maximum resident size is: %"PRIu64" (of %"PRIu64") MiB\n",
     459                 :            :                        max_resident_size >> 20, dev->conf.l2p_dram_limit);
     460                 :            : 
     461                 :         22 :         TAILQ_INIT(&cache->deferred_page_set_list);
     462                 :         22 :         TAILQ_INIT(&cache->lru_list);
     463                 :            : 
     464                 :         22 :         cache->l2_ctx_md = ftl_md_create(dev,
     465                 :            :                                          spdk_divide_round_up(max_resident_pgs * SPDK_ALIGN_CEIL(sizeof(struct ftl_l2p_page), 64),
     466                 :            :                                                          FTL_BLOCK_SIZE), 0, FTL_L2P_CACHE_MD_NAME_L2_CTX, ftl_md_create_shm_flags(dev), NULL);
     467                 :            : 
     468         [ -  + ]:         22 :         if (cache->l2_ctx_md == NULL) {
     469                 :          0 :                 return -1;
     470                 :            :         }
     471                 :            : 
     472                 :         22 :         cache->l2_pgs_resident_max = max_resident_pgs;
     473                 :         22 :         cache->l2_pgs_avail = max_resident_pgs;
     474                 :         22 :         cache->l2_pgs_evicting = 0;
     475                 :         22 :         cache->l2_ctx_pool = ftl_mempool_create_ext(ftl_md_get_buffer(cache->l2_ctx_md),
     476                 :            :                              max_resident_pgs, sizeof(struct ftl_l2p_page), 64);
     477                 :            : 
     478         [ -  + ]:         22 :         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                 :         22 :         cache->evict_keep = spdk_divide_round_up(cache->num_pages * FTL_L2P_CACHE_PAGE_AVAIL_RATIO, 100);
     485                 :         22 :         cache->evict_keep = spdk_min(FTL_L2P_CACHE_PAGE_AVAIL_MAX, cache->evict_keep);
     486                 :            : 
     487   [ +  -  +  + ]:         22 :         if (!ftl_fast_startup(dev) && !ftl_fast_recovery(dev)) {
     488         [ -  + ]:         21 :                 memset(cache->l2_mapping, (int)FTL_DF_OBJ_ID_INVALID, ftl_md_get_buffer_size(cache->l2_md));
     489                 :         21 :                 ftl_mempool_initialize_ext(cache->l2_ctx_pool);
     490                 :            :         }
     491                 :            : 
     492                 :         22 :         cache->l1_md = ftl_md_create(dev,
     493                 :            :                                      max_resident_pgs, 0,
     494                 :            :                                      FTL_L2P_CACHE_MD_NAME_L1,
     495                 :            :                                      ftl_md_create_shm_flags(dev), NULL);
     496                 :            : 
     497         [ -  + ]:         22 :         if (cache->l1_md == NULL) {
     498                 :          0 :                 return -1;
     499                 :            :         }
     500                 :            : 
     501                 :            :         /* Cache MD layout */
     502                 :         22 :         reg = &dev->layout.region[FTL_LAYOUT_REGION_TYPE_L2P];
     503                 :         22 :         cache->cache_layout_offset = reg->current.offset;
     504                 :         22 :         cache->cache_layout_bdev_desc = reg->bdev_desc;
     505                 :         22 :         cache->cache_layout_ioch = reg->ioch;
     506                 :            : 
     507                 :         22 :         return 0;
     508                 :            : }
     509                 :            : 
     510                 :            : static void
     511                 :         22 : ftl_l2p_cache_deinit_l2(struct spdk_ftl_dev *dev, struct ftl_l2p_cache *cache)
     512                 :            : {
     513                 :         22 :         ftl_md_destroy(cache->l2_ctx_md, ftl_md_destroy_shm_flags(dev));
     514                 :         22 :         cache->l2_ctx_md = NULL;
     515                 :            : 
     516                 :         22 :         ftl_mempool_destroy_ext(cache->l2_ctx_pool);
     517                 :         22 :         cache->l2_ctx_pool = NULL;
     518                 :            : 
     519                 :         22 :         ftl_md_destroy(cache->l1_md, ftl_md_destroy_shm_flags(dev));
     520                 :         22 :         cache->l1_md = NULL;
     521                 :            : 
     522                 :         22 :         ftl_mempool_destroy(cache->page_sets_pool);
     523                 :         22 :         cache->page_sets_pool = NULL;
     524                 :         22 : }
     525                 :            : 
     526                 :            : static void
     527                 :         22 : _ftl_l2p_cache_deinit(struct spdk_ftl_dev *dev)
     528                 :            : {
     529                 :         22 :         struct ftl_l2p_cache *cache = (struct ftl_l2p_cache *)dev->l2p;
     530                 :            : 
     531                 :         22 :         ftl_l2p_cache_deinit_l2(dev, cache);
     532                 :         22 :         ftl_md_destroy(cache->l2_md, ftl_md_destroy_shm_flags(dev));
     533                 :         22 :         free(cache);
     534                 :         22 : }
     535                 :            : 
     536                 :            : void
     537                 :         22 : ftl_l2p_cache_deinit(struct spdk_ftl_dev *dev)
     538                 :            : {
     539                 :         22 :         struct ftl_l2p_cache *cache = (struct ftl_l2p_cache *)dev->l2p;
     540                 :            : 
     541         [ -  + ]:         22 :         if (!cache) {
     542                 :          0 :                 return;
     543                 :            :         }
     544   [ -  +  -  - ]:         22 :         assert(cache->state == L2P_CACHE_SHUTDOWN_DONE || cache->state == L2P_CACHE_INIT);
     545                 :            : 
     546                 :         22 :         _ftl_l2p_cache_deinit(dev);
     547                 :         22 :         dev->l2p = 0;
     548                 :            : }
     549                 :            : 
     550                 :            : static void
     551                 :         44 : process_init_ctx(struct spdk_ftl_dev *dev, struct ftl_l2p_cache *cache,
     552                 :            :                  ftl_l2p_cb cb, void *cb_ctx)
     553                 :            : {
     554                 :         44 :         struct ftl_l2p_cache_process_ctx *ctx = &cache->mctx;
     555                 :            : 
     556         [ -  + ]:         44 :         assert(NULL == ctx->cb_ctx);
     557         [ -  + ]:         44 :         assert(0 == cache->l2_pgs_evicting);
     558                 :            : 
     559         [ -  + ]:         44 :         memset(ctx, 0, sizeof(*ctx));
     560                 :            : 
     561                 :         44 :         ctx->cb = cb;
     562                 :         44 :         ctx->cb_ctx = cb_ctx;
     563                 :         44 : }
     564                 :            : 
     565                 :            : static void
     566                 :         44 : process_finish(struct ftl_l2p_cache *cache)
     567                 :            : {
     568                 :         44 :         struct ftl_l2p_cache_process_ctx ctx = cache->mctx;
     569                 :            : 
     570         [ -  + ]:         44 :         assert(cache->l2_pgs_avail == cache->l2_pgs_resident_max);
     571         [ -  + ]:         44 :         assert(0 == ctx.qd);
     572                 :            : 
     573         [ -  + ]:         44 :         memset(&cache->mctx, 0, sizeof(cache->mctx));
     574                 :         44 :         ctx.cb(cache->dev, ctx.status, ctx.cb_ctx);
     575                 :         44 : }
     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                 :            :                         ftl_l2p_cache_get_bdev_iochannel(cache),
     590                 :            :                         page->page_buffer, NULL, ftl_l2p_cache_page_get_bdev_offset(cache, page),
     591                 :            :                         1, cb, page);
     592                 :            : 
     593         [ #  # ]:          0 :         if (rc) {
     594                 :          0 :                 cb(NULL, false, page);
     595                 :            :         }
     596                 :          0 : }
     597                 :            : 
     598                 :            : static void
     599                 :      18304 : process_persist_page_out_cb(struct spdk_bdev_io *bdev_io, bool success, void *arg)
     600                 :            : {
     601                 :      18304 :         struct ftl_l2p_page *page = arg;
     602                 :      18304 :         struct ftl_l2p_cache *cache = page->ctx.cache;
     603                 :      18304 :         struct spdk_ftl_dev *dev = cache->dev;
     604                 :      18304 :         struct ftl_l2p_cache_process_ctx *ctx = &cache->mctx;
     605                 :            : 
     606         [ -  + ]:      18304 :         assert(bdev_io);
     607                 :      18304 :         ftl_stats_bdev_io_completed(dev, FTL_STATS_TYPE_L2P, bdev_io);
     608                 :      18304 :         spdk_bdev_free_io(bdev_io);
     609                 :            : 
     610         [ -  + ]:      18304 :         if (!success) {
     611                 :          0 :                 ctx->status = -EIO;
     612                 :            :         }
     613                 :            : 
     614         [ -  + ]:      18304 :         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                 :            :         }
     621                 :      18304 :         ftl_l2p_cache_page_remove(cache, page);
     622                 :            : 
     623                 :      18304 :         ctx->qd--;
     624                 :      18304 :         process_persist(cache);
     625                 :      18304 : }
     626                 :            : 
     627                 :            : static void
     628                 :      18304 : 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                 :      18304 :         struct ftl_l2p_cache *cache = page->ctx.cache;
     633                 :      18304 :         struct spdk_ftl_dev *dev = cache->dev;
     634                 :            :         int rc;
     635                 :            : 
     636         [ -  + ]:      18304 :         assert(page->page_buffer);
     637                 :            : 
     638                 :      18304 :         rc = ftl_nv_cache_bdev_write_blocks_with_md(dev, ftl_l2p_cache_get_bdev_desc(cache),
     639                 :            :                         ftl_l2p_cache_get_bdev_iochannel(cache),
     640                 :            :                         page->page_buffer, NULL, ftl_l2p_cache_page_get_bdev_offset(cache, page),
     641                 :            :                         1, cb, page);
     642                 :            : 
     643         [ +  - ]:      18304 :         if (spdk_likely(0 == rc)) {
     644                 :      18304 :                 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                 :            :         } else {
     658                 :          0 :                 ftl_abort();
     659                 :            :         }
     660                 :            : }
     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                 :            :         }
     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                 :            :         }
     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                 :            :         } else {
     714                 :          0 :                 ctx->status = -EIO;
     715                 :          0 :                 ctx->qd--;
     716                 :          0 :                 process_trim(cache);
     717                 :            :         }
     718                 :          0 : }
     719                 :            : 
     720                 :            : static void
     721                 :         22 : process_trim(struct ftl_l2p_cache *cache)
     722                 :            : {
     723                 :         22 :         struct ftl_l2p_cache_process_ctx *ctx = &cache->mctx;
     724                 :            : 
     725   [ +  +  +  - ]:     434916 :         while (ctx->idx < cache->num_pages && ctx->qd < 64) {
     726                 :            :                 struct ftl_l2p_page *page;
     727                 :            : 
     728         [ +  - ]:     434894 :                 if (!ftl_bitmap_get(cache->dev->trim_map, ctx->idx)) {
     729                 :            :                         /* Page had not been trimmed, continue */
     730                 :     434894 :                         ctx->idx++;
     731                 :     434894 :                         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         [ +  - ]:         22 :         if (0 == ctx->qd) {
     756                 :         22 :                 process_finish(cache);
     757                 :            :         }
     758                 :         22 : }
     759                 :            : 
     760                 :            : void
     761                 :         22 : ftl_l2p_cache_trim(struct spdk_ftl_dev *dev, ftl_l2p_cb cb, void *cb_ctx)
     762                 :            : {
     763                 :         22 :         struct ftl_l2p_cache *cache = (struct ftl_l2p_cache *)dev->l2p;
     764                 :            : 
     765                 :         22 :         process_init_ctx(dev, cache, cb, cb_ctx);
     766                 :         22 :         process_trim(cache);
     767                 :         22 : }
     768                 :            : 
     769                 :            : static void
     770                 :          5 : clear_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status)
     771                 :            : {
     772                 :          5 :         ftl_l2p_cb cb = md->owner.private;
     773                 :          5 :         void *cb_cntx = md->owner.cb_ctx;
     774                 :            : 
     775                 :          5 :         cb(dev, status, cb_cntx);
     776                 :          5 : }
     777                 :            : 
     778                 :            : void
     779                 :          5 : ftl_l2p_cache_clear(struct spdk_ftl_dev *dev, ftl_l2p_cb cb, void *cb_ctx)
     780                 :            : {
     781                 :          5 :         struct ftl_md *md = dev->layout.md[FTL_LAYOUT_REGION_TYPE_L2P];
     782                 :          5 :         ftl_addr invalid_addr = FTL_ADDR_INVALID;
     783                 :            : 
     784                 :          5 :         md->cb =  clear_cb;
     785                 :          5 :         md->owner.cb_ctx = cb_ctx;
     786                 :          5 :         md->owner.private = cb;
     787                 :            : 
     788                 :          5 :         ftl_md_clear(md, invalid_addr, NULL);
     789                 :          5 : }
     790                 :            : 
     791                 :            : static void
     792                 :          0 : l2p_shm_restore_clean(struct spdk_ftl_dev *dev)
     793                 :            : {
     794                 :          0 :         struct ftl_l2p_cache *cache = (struct ftl_l2p_cache *)dev->l2p;
     795                 :          0 :         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         [ #  # ]:          0 :         for (page_no = 0; page_no < cache->num_pages; ++page_no) {
     801                 :          0 :                 obj_id = me[page_no].page_obj_id;
     802         [ #  # ]:          0 :                 if (obj_id == FTL_DF_OBJ_ID_INVALID) {
     803                 :          0 :                         continue;
     804                 :            :                 }
     805                 :            : 
     806                 :          0 :                 page = ftl_mempool_claim_df(cache->l2_ctx_pool, obj_id);
     807         [ #  # ]:          0 :                 assert(page);
     808         [ #  # ]:          0 :                 assert(page->obj_id == ftl_mempool_get_df_obj_id(cache->l2_ctx_pool, page));
     809         [ #  # ]:          0 :                 assert(page->page_no == page_no);
     810         [ #  # ]:          0 :                 assert(page->state != L2P_CACHE_PAGE_INIT);
     811         [ #  # ]:          0 :                 assert(page->state != L2P_CACHE_PAGE_CLEARING);
     812         [ #  # ]:          0 :                 assert(cache->l2_pgs_avail > 0);
     813                 :          0 :                 cache->l2_pgs_avail--;
     814                 :            : 
     815                 :          0 :                 page->page_buffer = (char *)ftl_md_get_buffer(cache->l1_md) + ftl_mempool_get_df_obj_index(
     816                 :          0 :                                             cache->l2_ctx_pool, page) * FTL_BLOCK_SIZE;
     817                 :            : 
     818                 :          0 :                 TAILQ_INIT(&page->ppe_list);
     819                 :            : 
     820                 :          0 :                 page->pin_ref_cnt = 0;
     821                 :          0 :                 page->on_lru_list = 0;
     822         [ #  # ]:          0 :                 memset(&page->ctx, 0, sizeof(page->ctx));
     823                 :            : 
     824                 :          0 :                 ftl_l2p_cache_lru_add_page(cache, page);
     825                 :            :         }
     826                 :            : 
     827                 :          0 :         ftl_mempool_initialize_ext(cache->l2_ctx_pool);
     828                 :          0 : }
     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                 :            :         }
     874                 :            : 
     875                 :          1 :         ftl_mempool_initialize_ext(cache->l2_ctx_pool);
     876                 :          1 : }
     877                 :            : 
     878                 :            : void
     879                 :         17 : ftl_l2p_cache_restore(struct spdk_ftl_dev *dev, ftl_l2p_cb cb, void *cb_ctx)
     880                 :            : {
     881         [ -  + ]:         17 :         if (ftl_fast_startup(dev)) {
     882                 :          0 :                 l2p_shm_restore_clean(dev);
     883                 :            :         }
     884                 :            : 
     885         [ +  + ]:         17 :         if (ftl_fast_recovery(dev)) {
     886                 :          1 :                 l2p_shm_restore_dirty(dev);
     887                 :            :         }
     888                 :            : 
     889                 :         17 :         cb(dev, 0, cb_ctx);
     890                 :         17 : }
     891                 :            : 
     892                 :            : static void
     893                 :      18326 : process_persist(struct ftl_l2p_cache *cache)
     894                 :            : {
     895                 :      18326 :         struct ftl_l2p_cache_process_ctx *ctx = &cache->mctx;
     896                 :      18326 :         struct spdk_ftl_dev *dev = cache->dev;
     897                 :            : 
     898   [ +  +  +  + ]:     453220 :         while (ctx->idx < cache->num_pages && ctx->qd < 64) {
     899                 :     434894 :                 struct ftl_l2p_page *page = get_l2p_page_by_df_id(cache, ctx->idx);
     900                 :     434894 :                 ctx->idx++;
     901                 :            : 
     902         [ +  + ]:     434894 :                 if (!page) {
     903                 :     400545 :                         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                 :            :                 }
     910                 :            : 
     911   [ -  +  +  - ]:      34349 :                 if (page->on_lru_list) {
     912                 :      34349 :                         ftl_l2p_cache_lru_remove_page(cache, page);
     913                 :            :                 }
     914                 :            : 
     915         [ +  + ]:      34349 :                 if (page->updates) {
     916                 :            :                         /* Need to persist the page */
     917                 :      18304 :                         page->state = L2P_CACHE_PAGE_PERSISTING;
     918                 :      18304 :                         page->ctx.cache = cache;
     919                 :      18304 :                         ctx->qd++;
     920                 :      18304 :                         process_page_out(page, process_persist_page_out_cb);
     921                 :            :                 } else {
     922                 :      16045 :                         ftl_l2p_cache_page_remove(cache, page);
     923                 :            :                 }
     924                 :            :         }
     925                 :            : 
     926         [ +  + ]:      18326 :         if (0 == ctx->qd) {
     927                 :         22 :                 process_finish(cache);
     928                 :            :         }
     929                 :      18326 : }
     930                 :            : 
     931                 :            : void
     932                 :         22 : ftl_l2p_cache_persist(struct spdk_ftl_dev *dev, ftl_l2p_cb cb, void *cb_ctx)
     933                 :            : {
     934                 :         22 :         struct ftl_l2p_cache *cache = (struct ftl_l2p_cache *)dev->l2p;
     935                 :            : 
     936                 :         22 :         process_init_ctx(dev, cache, cb, cb_ctx);
     937                 :         22 :         process_persist(cache);
     938                 :         22 : }
     939                 :            : 
     940                 :            : bool
     941                 :         44 : ftl_l2p_cache_is_halted(struct spdk_ftl_dev *dev)
     942                 :            : {
     943                 :         44 :         struct ftl_l2p_cache *cache = (struct ftl_l2p_cache *)dev->l2p;
     944                 :            : 
     945                 :         44 :         return cache->state == L2P_CACHE_SHUTDOWN_DONE;
     946                 :            : }
     947                 :            : 
     948                 :            : void
     949                 :         22 : ftl_l2p_cache_halt(struct spdk_ftl_dev *dev)
     950                 :            : {
     951                 :         22 :         struct ftl_l2p_cache *cache = (struct ftl_l2p_cache *)dev->l2p;
     952                 :            : 
     953         [ +  - ]:         22 :         if (cache->state != L2P_CACHE_SHUTDOWN_DONE) {
     954                 :         22 :                 cache->state = L2P_CACHE_IN_SHUTDOWN;
     955   [ +  -  +  - ]:         22 :                 if (!cache->ios_in_flight && !cache->l2_pgs_evicting) {
     956                 :         22 :                         cache->state = L2P_CACHE_SHUTDOWN_DONE;
     957                 :            :                 }
     958                 :            :         }
     959                 :         22 : }
     960                 :            : 
     961                 :            : void
     962                 :         22 : ftl_l2p_cache_resume(struct spdk_ftl_dev *dev)
     963                 :            : {
     964                 :         22 :         struct ftl_l2p_cache *cache = (struct ftl_l2p_cache *)dev->l2p;
     965                 :            : 
     966         [ -  + ]:         22 :         assert(cache->state == L2P_CACHE_INIT);
     967                 :         22 :         cache->state = L2P_CACHE_RUNNING;
     968                 :         22 : }
     969                 :            : 
     970                 :            : static inline struct ftl_l2p_page *
     971                 :   14024835 : get_page(struct ftl_l2p_cache *cache, uint64_t lba)
     972                 :            : {
     973         [ -  + ]:   14024835 :         return get_l2p_page_by_df_id(cache, lba / cache->lbas_in_page);
     974                 :            : }
     975                 :            : 
     976                 :            : static inline void
     977                 :    4273291 : ftl_l2p_cache_init_page_set(struct ftl_l2p_page_set *page_set, struct ftl_l2p_pin_ctx *pin_ctx)
     978                 :            : {
     979                 :    4273291 :         page_set->to_pin_cnt = 0;
     980                 :    4273291 :         page_set->pinned_cnt = 0;
     981                 :    4273291 :         page_set->pin_fault_cnt = 0;
     982                 :    4273291 :         page_set->locked = 0;
     983                 :    4273291 :         page_set->deferred = 0;
     984                 :    4273291 :         page_set->pin_ctx = pin_ctx;
     985                 :    4273291 : }
     986                 :            : 
     987                 :            : static inline bool
     988                 :   18298130 : ftl_l2p_cache_running(struct ftl_l2p_cache *cache)
     989                 :            : {
     990                 :   18298130 :         return cache->state == L2P_CACHE_RUNNING;
     991                 :            : }
     992                 :            : 
     993                 :            : static inline bool
     994                 :    4273291 : ftl_l2p_cache_page_is_pinnable(struct ftl_l2p_page *page)
     995                 :            : {
     996                 :    4273291 :         return page->state != L2P_CACHE_PAGE_INIT;
     997                 :            : }
     998                 :            : 
     999                 :            : void
    1000                 :    4273291 : ftl_l2p_cache_pin(struct spdk_ftl_dev *dev, struct ftl_l2p_pin_ctx *pin_ctx)
    1001                 :            : {
    1002         [ -  + ]:    4273291 :         assert(dev->num_lbas >= pin_ctx->lba + pin_ctx->count);
    1003                 :    4273291 :         struct ftl_l2p_cache *cache = (struct ftl_l2p_cache *)dev->l2p;
    1004                 :            :         struct ftl_l2p_page_set *page_set;
    1005                 :    4273291 :         bool defer_pin = false;
    1006                 :            : 
    1007                 :            :         /* Calculate first and last page to pin, count of them */
    1008         [ -  + ]:    4273291 :         uint64_t start = pin_ctx->lba / cache->lbas_in_page;
    1009         [ -  + ]:    4273291 :         uint64_t end = (pin_ctx->lba + pin_ctx->count - 1) / cache->lbas_in_page;
    1010                 :    4273291 :         uint64_t count = end - start + 1;
    1011                 :            :         uint64_t i;
    1012                 :            : 
    1013         [ -  + ]:    4273291 :         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         [ -  + ]:    4273291 :         assert(ftl_l2p_cache_running(cache));
    1020                 :    4273291 :         page_set = ftl_mempool_get(cache->page_sets_pool);
    1021         [ -  + ]:    4273291 :         if (!page_set) {
    1022                 :          0 :                 ftl_l2p_pin_complete(dev, -EAGAIN, pin_ctx);
    1023                 :          0 :                 return;
    1024                 :            :         }
    1025                 :    4273291 :         ftl_l2p_cache_init_page_set(page_set, pin_ctx);
    1026                 :            : 
    1027                 :    4273291 :         struct ftl_l2p_page_wait_ctx *entry = page_set->entry;
    1028         [ +  + ]:    8546582 :         for (i = start; i <= end; i++, entry++) {
    1029                 :            :                 struct ftl_l2p_page *page;
    1030                 :    4273291 :                 entry->parent = page_set;
    1031                 :    4273291 :                 entry->pg_no = i;
    1032                 :    4273291 :                 entry->pg_pin_completed = false;
    1033                 :    4273291 :                 entry->pg_pin_issued = false;
    1034                 :            : 
    1035                 :    4273291 :                 page_set->to_pin_cnt++;
    1036                 :            : 
    1037                 :            :                 /* Try get page and pin */
    1038                 :    4273291 :                 page = get_l2p_page_by_df_id(cache, i);
    1039         [ +  + ]:    4273291 :                 if (page) {
    1040         [ +  + ]:    3842240 :                         if (ftl_l2p_cache_page_is_pinnable(page)) {
    1041                 :            :                                 /* Page available and we can pin it */
    1042                 :    3588412 :                                 page_set->pinned_cnt++;
    1043                 :    3588412 :                                 entry->pg_pin_issued = true;
    1044                 :    3588412 :                                 entry->pg_pin_completed = true;
    1045                 :    3588412 :                                 ftl_l2p_cache_page_pin(cache, page);
    1046                 :            :                         } else {
    1047                 :            :                                 /* The page is being loaded */
    1048                 :            :                                 /* Queue the page pin entry to be executed on page in */
    1049                 :     253828 :                                 ftl_l2p_page_queue_wait_ctx(page, entry);
    1050                 :     253828 :                                 entry->pg_pin_issued = true;
    1051                 :            :                         }
    1052                 :            :                 } else {
    1053                 :            :                         /* The page is not in the cache, queue the page_set to page in */
    1054                 :     431051 :                         defer_pin = true;
    1055                 :            :                 }
    1056                 :            :         }
    1057                 :            : 
    1058                 :            :         /* Check if page set is done */
    1059         [ +  + ]:    4273291 :         if (page_set_is_done(page_set)) {
    1060                 :    3588412 :                 page_set_end(dev, cache, page_set);
    1061         [ +  + ]:     684879 :         } else if (defer_pin) {
    1062                 :     431051 :                 TAILQ_INSERT_TAIL(&cache->deferred_page_set_list, page_set, list_entry);
    1063                 :     431051 :                 page_set->deferred = 1;
    1064                 :            :         }
    1065                 :            : }
    1066                 :            : 
    1067                 :            : void
    1068                 :    4273291 : ftl_l2p_cache_unpin(struct spdk_ftl_dev *dev, uint64_t lba, uint64_t count)
    1069                 :            : {
    1070         [ -  + ]:    4273291 :         assert(dev->num_lbas >= lba + count);
    1071                 :    4273291 :         struct ftl_l2p_cache *cache = (struct ftl_l2p_cache *)dev->l2p;
    1072                 :            :         struct ftl_l2p_page *page;
    1073         [ -  + ]:    4273291 :         uint64_t start = lba / cache->lbas_in_page;
    1074         [ -  + ]:    4273291 :         uint64_t end = (lba + count - 1) / cache->lbas_in_page;
    1075                 :            :         uint64_t i;
    1076                 :            : 
    1077         [ -  + ]:    4273291 :         assert(count);
    1078         [ -  + ]:    4273291 :         assert(start < cache->num_pages);
    1079         [ -  + ]:    4273291 :         assert(end < cache->num_pages);
    1080                 :            : 
    1081         [ +  + ]:    8546582 :         for (i = start; i <= end; i++) {
    1082                 :    4273291 :                 page = get_l2p_page_by_df_id(cache, i);
    1083         [ -  + ]:    4273291 :                 ftl_bug(!page);
    1084                 :    4273291 :                 ftl_l2p_cache_page_unpin(cache, page);
    1085                 :            :         }
    1086                 :    4273291 : }
    1087                 :            : 
    1088                 :            : ftl_addr
    1089                 :   11287092 : ftl_l2p_cache_get(struct spdk_ftl_dev *dev, uint64_t lba)
    1090                 :            : {
    1091         [ -  + ]:   11287092 :         assert(dev->num_lbas > lba);
    1092                 :   11287092 :         struct ftl_l2p_cache *cache = (struct ftl_l2p_cache *)dev->l2p;
    1093                 :   11287092 :         struct ftl_l2p_page *page = get_page(cache, lba);
    1094                 :            :         ftl_addr addr;
    1095                 :            : 
    1096         [ -  + ]:   11287092 :         ftl_bug(!page);
    1097         [ -  + ]:   11287092 :         assert(ftl_l2p_cache_running(cache));
    1098         [ -  + ]:   11287092 :         assert(page->pin_ref_cnt);
    1099                 :            : 
    1100         [ +  + ]:   11287092 :         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                 :            :         }
    1104                 :            : 
    1105                 :   11287092 :         ftl_l2p_cache_lru_promote_page(cache, page);
    1106                 :   11287092 :         addr = ftl_l2p_cache_get_addr(dev, cache, page, lba);
    1107                 :            : 
    1108                 :   11287092 :         return addr;
    1109                 :            : }
    1110                 :            : 
    1111                 :            : void
    1112                 :    2737743 : ftl_l2p_cache_set(struct spdk_ftl_dev *dev, uint64_t lba, ftl_addr addr)
    1113                 :            : {
    1114         [ -  + ]:    2737743 :         assert(dev->num_lbas > lba);
    1115                 :    2737743 :         struct ftl_l2p_cache *cache = (struct ftl_l2p_cache *)dev->l2p;
    1116                 :    2737743 :         struct ftl_l2p_page *page = get_page(cache, lba);
    1117                 :            : 
    1118         [ -  + ]:    2737743 :         ftl_bug(!page);
    1119         [ -  + ]:    2737743 :         assert(ftl_l2p_cache_running(cache));
    1120         [ -  + ]:    2737743 :         assert(page->pin_ref_cnt);
    1121                 :            : 
    1122         [ -  + ]:    2737743 :         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                 :            :         }
    1126                 :            : 
    1127                 :    2737743 :         page->updates++;
    1128                 :    2737743 :         ftl_l2p_cache_lru_promote_page(cache, page);
    1129                 :    2737743 :         ftl_l2p_cache_set_addr(dev, cache, page, lba, addr);
    1130                 :    2737743 : }
    1131                 :            : 
    1132                 :            : static struct ftl_l2p_page *
    1133                 :     123046 : page_allocate(struct ftl_l2p_cache *cache, uint64_t page_no)
    1134                 :            : {
    1135                 :     123046 :         struct ftl_l2p_page *page = ftl_l2p_cache_page_alloc(cache, page_no);
    1136                 :     123046 :         ftl_l2p_cache_page_insert(cache, page);
    1137                 :            : 
    1138                 :     123046 :         return page;
    1139                 :            : }
    1140                 :            : 
    1141                 :            : static bool
    1142                 :    5388147 : page_set_is_done(struct ftl_l2p_page_set *page_set)
    1143                 :            : {
    1144         [ -  + ]:    5388147 :         if (page_set->locked) {
    1145                 :          0 :                 return false;
    1146                 :            :         }
    1147                 :            : 
    1148         [ -  + ]:    5388147 :         assert(page_set->pinned_cnt + page_set->pin_fault_cnt <= page_set->to_pin_cnt);
    1149                 :    5388147 :         return (page_set->pinned_cnt + page_set->pin_fault_cnt == page_set->to_pin_cnt);
    1150                 :            : }
    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                 :            :         }
    1170                 :          0 : }
    1171                 :            : 
    1172                 :            : static void
    1173                 :    4273291 : page_set_end(struct spdk_ftl_dev *dev, struct ftl_l2p_cache *cache,
    1174                 :            :              struct ftl_l2p_page_set *page_set)
    1175                 :            : {
    1176         [ +  - ]:    4273291 :         if (spdk_likely(0 == page_set->pin_fault_cnt)) {
    1177                 :    4273291 :                 ftl_l2p_pin_complete(dev, 0, page_set->pin_ctx);
    1178                 :            :         } else {
    1179                 :          0 :                 page_set_unpin(cache, page_set);
    1180                 :          0 :                 ftl_l2p_pin_complete(dev, -EIO, page_set->pin_ctx);
    1181                 :            :         }
    1182                 :            : 
    1183         [ -  + ]:    4273291 :         if (page_set->deferred) {
    1184         [ #  # ]:          0 :                 TAILQ_REMOVE(&cache->deferred_page_set_list, page_set, list_entry);
    1185                 :            :         }
    1186                 :            : 
    1187         [ -  + ]:    4273291 :         assert(0 == page_set->locked);
    1188                 :    4273291 :         ftl_mempool_put(cache->page_sets_pool, page_set);
    1189                 :    4273291 : }
    1190                 :            : 
    1191                 :            : static void
    1192                 :     123046 : 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                 :     123046 :         cache->ios_in_flight--;
    1199                 :            : 
    1200         [ -  + ]:     123046 :         assert(0 == page->pin_ref_cnt);
    1201         [ -  + ]:     123046 :         assert(L2P_CACHE_PAGE_INIT == page->state);
    1202   [ -  +  -  + ]:     123046 :         assert(false == page->on_lru_list);
    1203                 :            : 
    1204         [ +  - ]:     123046 :         if (spdk_likely(success)) {
    1205                 :     123046 :                 page->state = L2P_CACHE_PAGE_READY;
    1206                 :            :         }
    1207                 :            : 
    1208         [ +  + ]:     929897 :         while ((pentry = TAILQ_FIRST(&page->ppe_list))) {
    1209         [ +  + ]:     683805 :                 TAILQ_REMOVE(&page->ppe_list, pentry, list_entry);
    1210                 :            : 
    1211                 :     683805 :                 page_set = pentry->parent;
    1212                 :            : 
    1213         [ -  + ]:     683805 :                 assert(false == pentry->pg_pin_completed);
    1214                 :            : 
    1215         [ +  - ]:     683805 :                 if (success) {
    1216                 :     683805 :                         ftl_l2p_cache_page_pin(cache, page);
    1217                 :     683805 :                         page_set->pinned_cnt++;
    1218                 :     683805 :                         pentry->pg_pin_completed = true;
    1219                 :            :                 } else {
    1220                 :          0 :                         page_set->pin_fault_cnt++;
    1221                 :            :                 }
    1222                 :            : 
    1223                 :            :                 /* Check if page_set is done */
    1224         [ +  - ]:     683805 :                 if (page_set_is_done(page_set)) {
    1225                 :     683805 :                         page_set_end(dev, cache, page_set);
    1226                 :            :                 }
    1227                 :            :         }
    1228                 :            : 
    1229         [ -  + ]:     123046 :         if (spdk_unlikely(!success)) {
    1230   [ #  #  #  # ]:          0 :                 ftl_bug(page->on_lru_list);
    1231                 :          0 :                 ftl_l2p_cache_page_remove(cache, page);
    1232                 :            :         }
    1233                 :     123046 : }
    1234                 :            : 
    1235                 :            : static void
    1236                 :     123046 : page_in_io_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
    1237                 :            : {
    1238                 :     123046 :         struct ftl_l2p_page *page = cb_arg;
    1239                 :     123046 :         struct ftl_l2p_cache *cache = page->ctx.cache;
    1240                 :     123046 :         struct spdk_ftl_dev *dev = cache->dev;
    1241                 :            : 
    1242                 :     123046 :         ftl_stats_bdev_io_completed(dev, FTL_STATS_TYPE_L2P, bdev_io);
    1243                 :     123046 :         spdk_bdev_free_io(bdev_io);
    1244                 :     123046 :         page_in_io_complete(dev, cache, page, success);
    1245                 :     123046 : }
    1246                 :            : 
    1247                 :            : static void
    1248                 :     123046 : 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                 :     123046 :         page->ctx.cache = cache;
    1255                 :            : 
    1256                 :     123046 :         rc = ftl_nv_cache_bdev_read_blocks_with_md(cache->dev, ftl_l2p_cache_get_bdev_desc(cache),
    1257                 :            :                         ftl_l2p_cache_get_bdev_iochannel(cache),
    1258                 :            :                         page->page_buffer, NULL, ftl_l2p_cache_page_get_bdev_offset(cache, page),
    1259                 :            :                         1, page_in_io_cb, page);
    1260                 :     123046 :         cache->ios_in_flight++;
    1261         [ +  - ]:     123046 :         if (spdk_likely(0 == rc)) {
    1262                 :     123046 :                 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                 :            :         } else {
    1276                 :          0 :                 ftl_abort();
    1277                 :            :         }
    1278                 :            : }
    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                 :     431051 : 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                 :     431051 :         bool page_in = false;
    1297                 :            : 
    1298                 :            :         /* Get page */
    1299                 :     431051 :         page = get_l2p_page_by_df_id(cache, pentry->pg_no);
    1300         [ +  + ]:     431051 :         if (!page) {
    1301                 :            :                 /* Page not allocated yet, do it */
    1302                 :     123046 :                 page = page_allocate(cache, pentry->pg_no);
    1303                 :     123046 :                 page_in = true;
    1304                 :            :         }
    1305                 :            : 
    1306         [ +  + ]:     431051 :         if (ftl_l2p_cache_page_is_pinnable(page)) {
    1307                 :       1074 :                 ftl_l2p_cache_page_pin(cache, page);
    1308                 :       1074 :                 page_set->pinned_cnt++;
    1309                 :       1074 :                 pentry->pg_pin_issued = true;
    1310                 :       1074 :                 pentry->pg_pin_completed = true;
    1311                 :            :         } else {
    1312                 :     429977 :                 pentry->pg_pin_issued = true;
    1313                 :     429977 :                 ftl_l2p_page_queue_wait_ctx(page, pentry);
    1314                 :            :         }
    1315                 :            : 
    1316         [ +  + ]:     431051 :         if (page_in) {
    1317                 :     123046 :                 page_in_io(dev, cache, page);
    1318                 :            :         }
    1319                 :     431051 : }
    1320                 :            : 
    1321                 :            : static int
    1322                 :   19418292 : 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                 :   19418292 :         page_set = TAILQ_FIRST(&cache->deferred_page_set_list);
    1329         [ +  + ]:   19418292 :         if (!page_set) {
    1330                 :            :                 /* No page_set */
    1331                 :   18941761 :                 return -ECHILD;
    1332                 :            :         }
    1333                 :            : 
    1334         [ +  + ]:     476531 :         if (page_set->to_pin_cnt > cache->l2_pgs_avail) {
    1335                 :            :                 /* No enough page to pin, wait */
    1336                 :      45480 :                 return -EBUSY;
    1337                 :            :         }
    1338         [ -  + ]:     431051 :         if (cache->ios_in_flight > 512) {
    1339                 :            :                 /* Too big QD */
    1340                 :          0 :                 return -EBUSY;
    1341                 :            :         }
    1342                 :            : 
    1343                 :     431051 :         ftl_add_io_activity(dev);
    1344                 :            : 
    1345         [ +  + ]:     431051 :         TAILQ_REMOVE(&cache->deferred_page_set_list, page_set, list_entry);
    1346                 :     431051 :         page_set->deferred = 0;
    1347                 :     431051 :         page_set->locked = 1;
    1348                 :            : 
    1349                 :            :         /* Now we can start pinning */
    1350                 :     431051 :         pentry = page_set->entry;
    1351         [ +  + ]:     862102 :         for (i = 0; i < page_set->to_pin_cnt; i++, pentry++) {
    1352         [ +  - ]:     431051 :                 if (!pentry->pg_pin_issued) {
    1353                 :     431051 :                         page_in(dev, cache, page_set, pentry);
    1354                 :            :                 }
    1355                 :            :         }
    1356                 :            : 
    1357                 :     431051 :         page_set->locked = 0;
    1358                 :            : 
    1359                 :            :         /* Check if page_set is done */
    1360         [ +  + ]:     431051 :         if (page_set_is_done(page_set)) {
    1361                 :       1074 :                 page_set_end(dev, cache, page_set);
    1362                 :            :         }
    1363                 :            : 
    1364                 :     431051 :         return 0;
    1365                 :            : }
    1366                 :            : 
    1367                 :            : static struct ftl_l2p_page *
    1368                 :      89017 : eviction_get_page(struct spdk_ftl_dev *dev, struct ftl_l2p_cache *cache)
    1369                 :            : {
    1370                 :      89017 :         uint64_t i = 0;
    1371                 :      89017 :         struct ftl_l2p_page *page = ftl_l2p_cache_get_coldest_page(cache);
    1372                 :            : 
    1373         [ +  - ]:      89017 :         while (page) {
    1374         [ -  + ]:      89017 :                 ftl_bug(L2P_CACHE_PAGE_READY != page->state);
    1375         [ -  + ]:      89017 :                 ftl_bug(page->pin_ref_cnt);
    1376                 :            : 
    1377         [ +  - ]:      89017 :                 if (ftl_l2p_cache_page_can_evict(page)) {
    1378                 :      89017 :                         ftl_l2p_cache_lru_remove_page(cache, page);
    1379                 :      89017 :                         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                 :            : }
    1393                 :            : 
    1394                 :            : static void
    1395                 :      85043 : page_out_io_complete(struct spdk_ftl_dev *dev, struct ftl_l2p_cache *cache,
    1396                 :            :                      struct ftl_l2p_page *page, bool success)
    1397                 :            : {
    1398                 :      85043 :         cache->l2_pgs_evicting--;
    1399                 :            : 
    1400         [ -  + ]:      85043 :         ftl_bug(page->ctx.updates > page->updates);
    1401         [ -  + ]:      85043 :         ftl_bug(!TAILQ_EMPTY(&page->ppe_list));
    1402   [ -  +  -  + ]:      85043 :         ftl_bug(page->on_lru_list);
    1403                 :            : 
    1404         [ +  - ]:      85043 :         if (spdk_likely(success)) {
    1405                 :      85043 :                 page->updates -= page->ctx.updates;
    1406                 :            :         }
    1407                 :            : 
    1408   [ +  -  +  + ]:      85043 :         if (success && ftl_l2p_cache_page_can_remove(page)) {
    1409                 :      85030 :                 ftl_l2p_cache_page_remove(cache, page);
    1410                 :            :         } else {
    1411         [ -  + ]:         13 :                 if (!page->pin_ref_cnt) {
    1412                 :          0 :                         ftl_l2p_cache_lru_add_page(cache, page);
    1413                 :            :                 }
    1414                 :         13 :                 page->state = L2P_CACHE_PAGE_READY;
    1415                 :            :         }
    1416                 :      85043 : }
    1417                 :            : 
    1418                 :            : static void
    1419                 :      85043 : page_out_io_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
    1420                 :            : {
    1421                 :      85043 :         struct ftl_l2p_page *page = cb_arg;
    1422                 :      85043 :         struct ftl_l2p_cache *cache = page->ctx.cache;
    1423                 :      85043 :         struct spdk_ftl_dev *dev = cache->dev;
    1424                 :            : 
    1425                 :      85043 :         ftl_stats_bdev_io_completed(dev, FTL_STATS_TYPE_L2P, bdev_io);
    1426                 :      85043 :         spdk_bdev_free_io(bdev_io);
    1427                 :      85043 :         page_out_io_complete(dev, cache, page, success);
    1428                 :      85043 : }
    1429                 :            : 
    1430                 :            : static void
    1431                 :      85043 : 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                 :      85043 :         page->ctx.cache = cache;
    1440                 :            : 
    1441                 :      85043 :         rc = ftl_nv_cache_bdev_write_blocks_with_md(dev, ftl_l2p_cache_get_bdev_desc(cache),
    1442                 :            :                         ftl_l2p_cache_get_bdev_iochannel(cache),
    1443                 :            :                         page->page_buffer, NULL, ftl_l2p_cache_page_get_bdev_offset(cache, page),
    1444                 :            :                         1, page_out_io_cb, page);
    1445                 :            : 
    1446                 :      85043 :         cache->l2_pgs_evicting++;
    1447         [ +  - ]:      85043 :         if (spdk_likely(0 == rc)) {
    1448                 :      85043 :                 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                 :            :         } else {
    1462                 :          0 :                 ftl_abort();
    1463                 :            :         }
    1464                 :            : }
    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                 :   18988144 : ftl_l2p_cache_process_eviction(struct spdk_ftl_dev *dev, struct ftl_l2p_cache *cache)
    1479                 :            : {
    1480                 :            :         struct ftl_l2p_page *page;
    1481                 :            : 
    1482         [ +  + ]:   18988144 :         if (!ftl_l2p_cache_evict_continue(cache)) {
    1483                 :   18899127 :                 return;
    1484                 :            :         }
    1485                 :            : 
    1486         [ -  + ]:      89017 :         if (cache->l2_pgs_evicting > 512) {
    1487                 :          0 :                 return;
    1488                 :            :         }
    1489                 :            : 
    1490                 :      89017 :         ftl_add_io_activity(dev);
    1491                 :            : 
    1492                 :      89017 :         page = eviction_get_page(dev, cache);
    1493         [ -  + ]:      89017 :         if (spdk_unlikely(!page)) {
    1494                 :          0 :                 return;
    1495                 :            :         }
    1496                 :            : 
    1497         [ +  + ]:      89017 :         if (page->updates) {
    1498                 :      85043 :                 page->state = L2P_CACHE_PAGE_FLUSHING;
    1499                 :      85043 :                 page->ctx.updates = page->updates;
    1500                 :      85043 :                 page_out_io(dev, cache, page);
    1501                 :            :         } else {
    1502                 :            :                 /* Page clean and we can remove it */
    1503                 :       3974 :                 ftl_l2p_cache_page_remove(cache, page);
    1504                 :            :         }
    1505                 :            : }
    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                 :            :         }
    1522                 :            : 
    1523                 :          4 :         ftl_l2p_cache_unpin(dev, pin_ctx->lba, pin_ctx->count);
    1524                 :            : }
    1525                 :            : 
    1526                 :            : static void
    1527                 :   18988144 : ftl_l2p_lazy_trim_process(struct spdk_ftl_dev *dev)
    1528                 :            : {
    1529                 :   18988144 :         struct ftl_l2p_cache *cache = dev->l2p;
    1530                 :            :         struct ftl_l2p_pin_ctx *pin_ctx;
    1531                 :            :         uint64_t page_no;
    1532                 :            : 
    1533   [ -  +  +  + ]:   18988144 :         if (spdk_likely(!dev->trim_in_progress)) {
    1534                 :   18988097 :                 return;
    1535                 :            :         }
    1536                 :            : 
    1537         [ +  + ]:         47 :         if (cache->lazy_trim.qd == FTL_L2P_MAX_LAZY_TRIM_QD) {
    1538                 :         39 :                 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                 :            :         }
    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                 :            : }
    1568                 :            : 
    1569                 :            : void
    1570                 :   18989134 : ftl_l2p_cache_process(struct spdk_ftl_dev *dev)
    1571                 :            : {
    1572                 :   18989134 :         struct ftl_l2p_cache *cache = dev->l2p;
    1573                 :            :         int i;
    1574                 :            : 
    1575         [ +  + ]:   18989134 :         if (spdk_unlikely(cache->state != L2P_CACHE_RUNNING)) {
    1576                 :        990 :                 return;
    1577                 :            :         }
    1578                 :            : 
    1579         [ +  + ]:   19419195 :         for (i = 0; i < 256; i++) {
    1580         [ +  + ]:   19418292 :                 if (ftl_l2p_cache_process_page_sets(dev, cache)) {
    1581                 :   18987241 :                         break;
    1582                 :            :                 }
    1583                 :            :         }
    1584                 :            : 
    1585                 :   18988144 :         ftl_l2p_cache_process_eviction(dev, cache);
    1586                 :   18988144 :         ftl_l2p_lazy_trim_process(dev);
    1587                 :            : }

Generated by: LCOV version 1.14