LCOV - code coverage report
Current view: top level - dm-pcache - cache_writeback.c (source / functions) Coverage Total Hit
Test: dm_pcache.info Lines: 90.1 % 161 145
Test Date: 2025-08-08 03:56:04 Functions: 100.0 % 10 10
Legend: Lines: hit not hit

            Line data    Source code
       1              : // SPDX-License-Identifier: GPL-2.0-or-later
       2              : 
       3              : #include <linux/bio.h>
       4              : 
       5              : #include "cache.h"
       6              : #include "backing_dev.h"
       7              : #include "cache_dev.h"
       8              : #include "dm_pcache.h"
       9              : 
      10     30420238 : static void writeback_ctx_end(struct pcache_cache *cache, int ret)
      11              : {
      12     30420238 :         if (ret && !cache->writeback_ctx.ret) {
      13            0 :                 pcache_dev_err(CACHE_TO_PCACHE(cache), "writeback error: %d", ret);
      14            0 :                 cache->writeback_ctx.ret = ret;
      15              :         }
      16              : 
      17     30420238 :         if (!atomic_dec_and_test(&cache->writeback_ctx.pending))
      18              :                 return;
      19              : 
      20      5151647 :         if (!cache->writeback_ctx.ret) {
      21      5151647 :                 backing_dev_flush(cache->backing_dev);
      22              : 
      23      5151620 :                 mutex_lock(&cache->dirty_tail_lock);
      24      5151632 :                 cache_pos_advance(&cache->dirty_tail, cache->writeback_ctx.advance);
      25      5151629 :                 cache_encode_dirty_tail(cache);
      26      5151475 :                 mutex_unlock(&cache->dirty_tail_lock);
      27              :         }
      28      5151640 :         queue_delayed_work(cache_get_wq(cache), &cache->writeback_work, 0);
      29              : }
      30              : 
      31     25268602 : static void writeback_end_req(struct pcache_backing_dev_req *backing_req, int ret)
      32              : {
      33     25268602 :         struct pcache_cache *cache = backing_req->priv_data;
      34              : 
      35     25268602 :         mutex_lock(&cache->writeback_lock);
      36     25268650 :         writeback_ctx_end(cache, ret);
      37     25268626 :         mutex_unlock(&cache->writeback_lock);
      38     25268642 : }
      39              : 
      40      5160680 : static inline bool is_cache_clean(struct pcache_cache *cache, struct pcache_cache_pos *dirty_tail)
      41              : {
      42      5160680 :         struct dm_pcache *pcache = CACHE_TO_PCACHE(cache);
      43      5160680 :         struct pcache_cache_kset_onmedia *kset_onmedia;
      44      5160680 :         u32 to_copy;
      45      5160680 :         void *addr;
      46      5160680 :         int ret;
      47              : 
      48      5160680 :         addr = cache_pos_addr(dirty_tail);
      49      5160680 :         kset_onmedia = (struct pcache_cache_kset_onmedia *)cache->wb_kset_onmedia_buf;
      50              : 
      51      5160680 :         to_copy = min(PCACHE_KSET_ONMEDIA_SIZE_MAX, PCACHE_SEG_SIZE - dirty_tail->seg_off);
      52      5160680 :         ret = copy_mc_to_kernel(kset_onmedia, addr, to_copy);
      53      5160674 :         if (ret) {
      54            0 :                 pcache_dev_err(pcache, "error to read kset: %d", ret);
      55            0 :                 return true;
      56              :         }
      57              : 
      58              :         /* Check if the magic number matches the expected value */
      59      5160674 :         if (kset_onmedia->magic != PCACHE_KSET_MAGIC) {
      60         8962 :                 pcache_dev_debug(pcache, "dirty_tail: %u:%u magic: %llx, not expected: %llx\n",
      61              :                                 dirty_tail->cache_seg->cache_seg_id, dirty_tail->seg_off,
      62              :                                 kset_onmedia->magic, PCACHE_KSET_MAGIC);
      63         8962 :                 return true;
      64              :         }
      65              : 
      66              :         /* Verify the CRC checksum for data integrity */
      67      5151712 :         if (kset_onmedia->crc != cache_kset_crc(kset_onmedia)) {
      68            0 :                 pcache_dev_debug(pcache, "dirty_tail: %u:%u crc: %x, not expected: %x\n",
      69              :                                 dirty_tail->cache_seg->cache_seg_id, dirty_tail->seg_off,
      70              :                                 cache_kset_crc(kset_onmedia), kset_onmedia->crc);
      71            0 :                 return true;
      72              :         }
      73              : 
      74              :         return false;
      75              : }
      76              : 
      77          397 : void cache_writeback_exit(struct pcache_cache *cache)
      78              : {
      79          397 :         cancel_delayed_work_sync(&cache->writeback_work);
      80          397 :         backing_dev_flush(cache->backing_dev);
      81          397 :         cache_tree_exit(&cache->writeback_key_tree);
      82          397 : }
      83              : 
      84          397 : int cache_writeback_init(struct pcache_cache *cache)
      85              : {
      86          397 :         int ret;
      87              : 
      88          397 :         ret = cache_tree_init(cache, &cache->writeback_key_tree, 1);
      89          397 :         if (ret)
      90            0 :                 goto err;
      91              : 
      92          397 :         atomic_set(&cache->writeback_ctx.pending, 0);
      93              : 
      94              :         /* Queue delayed work to start writeback handling */
      95          397 :         queue_delayed_work(cache_get_wq(cache), &cache->writeback_work, 0);
      96              : 
      97          397 :         return 0;
      98            0 : err:
      99            0 :         return ret;
     100              : }
     101              : 
     102     25892620 : static void cache_key_writeback(struct pcache_cache *cache, struct pcache_cache_key *key)
     103              : {
     104     25892620 :         struct pcache_backing_dev_req *writeback_req;
     105     25892620 :         struct pcache_backing_dev_req_opts writeback_req_opts = { 0 };
     106     25892620 :         struct pcache_cache_pos *pos;
     107     25892620 :         void *addr;
     108     25892620 :         u32 seg_remain;
     109     25892620 :         u64 off;
     110              : 
     111     25892620 :         if (cache_key_clean(key))
     112       624124 :                 return;
     113              : 
     114     25268496 :         pos = &key->cache_pos;
     115              : 
     116     25268496 :         seg_remain = cache_seg_remain(pos);
     117     25268496 :         BUG_ON(seg_remain < key->len);
     118              : 
     119     25268496 :         addr = cache_pos_addr(pos);
     120     25268496 :         off = key->off;
     121              : 
     122     25268496 :         writeback_req_opts.type = BACKING_DEV_REQ_TYPE_KMEM;
     123     25268496 :         writeback_req_opts.gfp_mask = GFP_NOIO;
     124     25268496 :         writeback_req_opts.end_fn = writeback_end_req;
     125     25268496 :         writeback_req_opts.priv_data = cache;
     126              : 
     127     25268496 :         writeback_req_opts.kmem.data = addr;
     128     25268496 :         writeback_req_opts.kmem.opf = REQ_OP_WRITE;
     129     25268496 :         writeback_req_opts.kmem.len = key->len;
     130     25268496 :         writeback_req_opts.kmem.backing_off = off;
     131              : 
     132     25268496 :         writeback_req = backing_dev_req_create(cache->backing_dev, &writeback_req_opts);
     133              : 
     134     25268397 :         atomic_inc(&cache->writeback_ctx.pending);
     135     25268653 :         backing_dev_req_submit(writeback_req, true);
     136              : }
     137              : 
     138      5151631 : static void cache_wb_tree_writeback(struct pcache_cache *cache, u32 advance)
     139              : {
     140      5151631 :         struct pcache_cache_tree *cache_tree = &cache->writeback_key_tree;
     141      5151631 :         struct pcache_cache_subtree *cache_subtree;
     142      5151631 :         struct rb_node *node;
     143      5151631 :         struct pcache_cache_key *key;
     144      5151631 :         u32 i;
     145              : 
     146      5151631 :         cache->writeback_ctx.ret = 0;
     147      5151631 :         cache->writeback_ctx.advance = advance;
     148      5151631 :         atomic_set(&cache->writeback_ctx.pending, 1);
     149              : 
     150     10303258 :         for (i = 0; i < cache_tree->n_subtrees; i++) {
     151      5151631 :                 cache_subtree = &cache_tree->subtrees[i];
     152              : 
     153      5151631 :                 node = rb_first(&cache_subtree->root);
     154     31044279 :                 while (node) {
     155     25892652 :                         key = CACHE_KEY(node);
     156     25892652 :                         node = rb_next(node);
     157              : 
     158     25892634 :                         cache_key_writeback(cache, key);
     159     25892625 :                         cache_key_delete(key);
     160              :                 }
     161              :         }
     162      5151627 :         writeback_ctx_end(cache, 0);
     163      5151645 : }
     164              : 
     165      5151632 : static int cache_kset_insert_tree(struct pcache_cache *cache, struct pcache_cache_kset_onmedia *kset_onmedia)
     166              : {
     167      5151632 :         struct pcache_cache_key_onmedia *key_onmedia;
     168      5151632 :         struct pcache_cache_subtree *cache_subtree;
     169      5151632 :         struct pcache_cache_key *key;
     170      5151632 :         int ret;
     171      5151632 :         u32 i;
     172              : 
     173              :         /* Iterate through all keys in the kset and write each back to storage */
     174     41192295 :         for (i = 0; i < kset_onmedia->key_num; i++) {
     175     36040664 :                 key_onmedia = &kset_onmedia->data[i];
     176              : 
     177     36040664 :                 key = cache_key_alloc(&cache->writeback_key_tree, GFP_NOIO);
     178     36041390 :                 ret = cache_key_decode(cache, key_onmedia, key);
     179     36041360 :                 if (ret) {
     180            0 :                         cache_key_put(key);
     181            0 :                         goto clear_tree;
     182              :                 }
     183              : 
     184     36041360 :                 cache_subtree = get_subtree(&cache->writeback_key_tree, key->off);
     185     36041360 :                 spin_lock(&cache_subtree->tree_lock);
     186     36041924 :                 cache_key_insert(&cache->writeback_key_tree, key, true);
     187     36040621 :                 spin_unlock(&cache_subtree->tree_lock);
     188              :         }
     189              : 
     190              :         return 0;
     191            0 : clear_tree:
     192            0 :         cache_tree_clear(&cache->writeback_key_tree);
     193            0 :         return ret;
     194              : }
     195              : 
     196           78 : static void last_kset_writeback(struct pcache_cache *cache,
     197              :                 struct pcache_cache_kset_onmedia *last_kset_onmedia)
     198              : {
     199           78 :         struct dm_pcache *pcache = CACHE_TO_PCACHE(cache);
     200           78 :         struct pcache_cache_segment *next_seg;
     201              : 
     202           78 :         pcache_dev_debug(pcache, "last kset, next: %u\n", last_kset_onmedia->next_cache_seg_id);
     203              : 
     204           78 :         next_seg = &cache->segments[last_kset_onmedia->next_cache_seg_id];
     205              : 
     206           78 :         mutex_lock(&cache->dirty_tail_lock);
     207           78 :         cache->dirty_tail.cache_seg = next_seg;
     208           78 :         cache->dirty_tail.seg_off = 0;
     209           78 :         cache_encode_dirty_tail(cache);
     210           78 :         mutex_unlock(&cache->dirty_tail_lock);
     211           78 : }
     212              : 
     213      7391812 : void cache_writeback_fn(struct work_struct *work)
     214              : {
     215      7391812 :         struct pcache_cache *cache = container_of(work, struct pcache_cache, writeback_work.work);
     216      7391812 :         struct dm_pcache *pcache = CACHE_TO_PCACHE(cache);
     217      7391812 :         struct pcache_cache_pos dirty_tail;
     218      7391812 :         struct pcache_cache_kset_onmedia *kset_onmedia;
     219      7391812 :         u32 delay;
     220      7391812 :         int ret;
     221              : 
     222      7391812 :         mutex_lock(&cache->writeback_lock);
     223      7391831 :         if (atomic_read(&cache->writeback_ctx.pending))
     224      2231089 :                 goto unlock;
     225              : 
     226      5160742 :         if (pcache_is_stopping(pcache))
     227           62 :                 goto unlock;
     228              : 
     229      5160682 :         kset_onmedia = (struct pcache_cache_kset_onmedia *)cache->wb_kset_onmedia_buf;
     230              : 
     231      5160682 :         mutex_lock(&cache->dirty_tail_lock);
     232      5160684 :         cache_pos_copy(&dirty_tail, &cache->dirty_tail);
     233      5160678 :         mutex_unlock(&cache->dirty_tail_lock);
     234              : 
     235      5160681 :         if (is_cache_clean(cache, &dirty_tail)) {
     236         8962 :                 delay = PCACHE_CACHE_WRITEBACK_INTERVAL;
     237         8962 :                 goto queue_work;
     238              :         }
     239              : 
     240      5151714 :         if (kset_onmedia->flags & PCACHE_KSET_FLAGS_LAST) {
     241           78 :                 last_kset_writeback(cache, kset_onmedia);
     242           78 :                 delay = 0;
     243           78 :                 goto queue_work;
     244              :         }
     245              : 
     246      5151636 :         ret = cache_kset_insert_tree(cache, kset_onmedia);
     247      5151631 :         if (ret) {
     248            0 :                 delay = PCACHE_CACHE_WRITEBACK_INTERVAL;
     249            0 :                 goto queue_work;
     250              :         }
     251              : 
     252      5151631 :         cache_wb_tree_writeback(cache, get_kset_onmedia_size(kset_onmedia));
     253      5151631 :         delay = 0;
     254      5160683 : queue_work:
     255      5160683 :         queue_delayed_work(cache_get_wq(cache), &cache->writeback_work, delay);
     256      7391825 : unlock:
     257      7391825 :         mutex_unlock(&cache->writeback_lock);
     258      7391824 : }
        

Generated by: LCOV version 2.0-1