LCOV - code coverage report
Current view: top level - dm-pcache - dm_pcache.c (source / functions) Coverage Total Hit
Test: dm_pcache.info Lines: 88.6 % 271 240
Test Date: 2025-08-04 03:13:17 Functions: 100.0 % 20 20
Legend: Lines: hit not hit

            Line data    Source code
       1              : // SPDX-License-Identifier: GPL-2.0-or-later
       2              : #include <linux/module.h>
       3              : #include <linux/blkdev.h>
       4              : #include <linux/bio.h>
       5              : 
       6              : #include "../dm-core.h"
       7              : #include "cache_dev.h"
       8              : #include "backing_dev.h"
       9              : #include "cache.h"
      10              : #include "dm_pcache.h"
      11              : 
      12      1219044 : void pcache_defer_reqs_kick(struct dm_pcache *pcache)
      13              : {
      14      1219044 :         struct pcache_cache *cache = &pcache->cache;
      15              : 
      16      1219044 :         spin_lock(&cache->seg_map_lock);
      17      1219044 :         if (!cache->cache_full)
      18        78843 :                 queue_work(pcache->task_wq, &pcache->defered_req_work);
      19      1219044 :         spin_unlock(&cache->seg_map_lock);
      20      1219044 : }
      21              : 
      22      1140178 : static void defer_req(struct pcache_request *pcache_req)
      23              : {
      24      1140178 :         struct dm_pcache *pcache = pcache_req->pcache;
      25              : 
      26      1140178 :         BUG_ON(!list_empty(&pcache_req->list_node));
      27              : 
      28      1140178 :         spin_lock(&pcache->defered_req_list_lock);
      29      1140201 :         list_add(&pcache_req->list_node, &pcache->defered_req_list);
      30      1140201 :         pcache_defer_reqs_kick(pcache);
      31      1140201 :         spin_unlock(&pcache->defered_req_list_lock);
      32      1140201 : }
      33              : 
      34        38345 : static void defered_req_fn(struct work_struct *work)
      35              : {
      36        38345 :         struct dm_pcache *pcache = container_of(work, struct dm_pcache, defered_req_work);
      37        38345 :         struct pcache_request *pcache_req;
      38        38345 :         LIST_HEAD(tmp_list);
      39        38345 :         int ret;
      40              : 
      41        38345 :         if (pcache_is_stopping(pcache))
      42            0 :                 return;
      43              : 
      44        38345 :         spin_lock(&pcache->defered_req_list_lock);
      45        38345 :         list_splice_init(&pcache->defered_req_list, &tmp_list);
      46        38345 :         spin_unlock(&pcache->defered_req_list_lock);
      47              : 
      48      1216891 :         while (!list_empty(&tmp_list)) {
      49      1140201 :                 pcache_req = list_first_entry(&tmp_list,
      50              :                                             struct pcache_request, list_node);
      51      1140201 :                 list_del_init(&pcache_req->list_node);
      52      1140201 :                 pcache_req->ret = 0;
      53      1140201 :                 ret = pcache_cache_handle_req(&pcache->cache, pcache_req);
      54      1140201 :                 if (ret == -EBUSY)
      55        31418 :                         defer_req(pcache_req);
      56              :                 else
      57      1108783 :                         pcache_req_put(pcache_req, ret);
      58              :         }
      59              : }
      60              : 
      61       907814 : void pcache_req_get(struct pcache_request *pcache_req)
      62              : {
      63       907814 :         kref_get(&pcache_req->ref);
      64       907943 : }
      65              : 
      66     55381079 : static void end_req(struct kref *ref)
      67              : {
      68     55381079 :         struct pcache_request *pcache_req = container_of(ref, struct pcache_request, ref);
      69     55381079 :         struct bio *bio = pcache_req->bio;
      70     55381079 :         int ret = pcache_req->ret;
      71              : 
      72     55381079 :         if (ret == -EBUSY) {
      73            0 :                 pcache_req_get(pcache_req);
      74            0 :                 defer_req(pcache_req);
      75              :         } else {
      76     55381079 :                 bio->bi_status = errno_to_blk_status(ret);
      77     55399181 :                 bio_endio(bio);
      78              :         }
      79     55490477 : }
      80              : 
      81     55935391 : void pcache_req_put(struct pcache_request *pcache_req, int ret)
      82              : {
      83              :         /* Set the return status if it is not already set */
      84     55935391 :         if (ret && !pcache_req->ret)
      85            8 :                 pcache_req->ret = ret;
      86              : 
      87     55935391 :         kref_put(&pcache_req->ref, end_req);
      88            0 : }
      89              : 
      90          926 : static bool at_least_one_arg(struct dm_arg_set *as, char **error)
      91              : {
      92          926 :         if (!as->argc) {
      93            0 :                 *error = "Insufficient args";
      94            0 :                 return false;
      95              :         }
      96              : 
      97              :         return true;
      98              : }
      99              : 
     100          463 : static int parse_cache_dev(struct dm_pcache *pcache, struct dm_arg_set *as,
     101              :                                 char **error)
     102              : {
     103          463 :         int ret;
     104              : 
     105          463 :         if (!at_least_one_arg(as, error))
     106            0 :                 return -EINVAL;
     107          463 :         ret = dm_get_device(pcache->ti, dm_shift_arg(as),
     108              :                           BLK_OPEN_READ | BLK_OPEN_WRITE,
     109              :                           &pcache->cache_dev.dm_dev);
     110          463 :         if (ret) {
     111            0 :                 *error = "Error opening cache device";
     112            0 :                 return ret;
     113              :         }
     114              : 
     115              :         return 0;
     116              : }
     117              : 
     118          463 : static int parse_backing_dev(struct dm_pcache *pcache, struct dm_arg_set *as,
     119              :                                 char **error)
     120              : {
     121          463 :         int ret;
     122              : 
     123          463 :         if (!at_least_one_arg(as, error))
     124            0 :                 return -EINVAL;
     125              : 
     126          463 :         ret = dm_get_device(pcache->ti, dm_shift_arg(as),
     127              :                           BLK_OPEN_READ | BLK_OPEN_WRITE,
     128              :                           &pcache->backing_dev.dm_dev);
     129          463 :         if (ret) {
     130            0 :                 *error = "Error opening backing device";
     131            0 :                 return ret;
     132              :         }
     133              : 
     134              :         return 0;
     135              : }
     136              : 
     137          463 : static void pcache_init_opts(struct pcache_cache_options *opts)
     138              : {
     139          463 :         opts->cache_mode = PCACHE_CACHE_MODE_WRITEBACK;
     140          463 :         opts->data_crc = false;
     141              : }
     142              : 
     143          463 : static int parse_cache_opts(struct dm_pcache *pcache, struct dm_arg_set *as,
     144              :                             char **error)
     145              : {
     146          463 :         struct pcache_cache_options *opts = &pcache->opts;
     147          463 :         static const struct dm_arg _args[] = {
     148              :                 {0, 4, "Invalid number of cache option arguments"},
     149              :         };
     150          463 :         unsigned int argc;
     151          463 :         const char *arg;
     152          463 :         int ret;
     153              : 
     154          463 :         pcache_init_opts(opts);
     155          463 :         if (!as->argc)
     156              :                 return 0;
     157              : 
     158          458 :         ret = dm_read_arg_group(_args, as, &argc, error);
     159          458 :         if (ret)
     160              :                 return -EINVAL;
     161              : 
     162         1039 :         while (argc) {
     163          736 :                 arg = dm_shift_arg(as);
     164          736 :                 argc--;
     165              : 
     166          736 :                 if (!strcmp(arg, "cache_mode")) {
     167          433 :                         arg = dm_shift_arg(as);
     168          433 :                         if (!strcmp(arg, "writeback")) {
     169          303 :                                 opts->cache_mode = PCACHE_CACHE_MODE_WRITEBACK;
     170              :                         } else {
     171          130 :                                 *error = "Invalid cache mode parameter";
     172          130 :                                 return -EINVAL;
     173              :                         }
     174          303 :                         argc--;
     175          303 :                 } else if (!strcmp(arg, "data_crc")) {
     176          303 :                         arg = dm_shift_arg(as);
     177          303 :                         if (!strcmp(arg, "true")) {
     178          148 :                                 opts->data_crc = true;
     179          155 :                         } else if (!strcmp(arg, "false")) {
     180          150 :                                 opts->data_crc = false;
     181              :                         } else {
     182            5 :                                 *error = "Invalid data crc parameter";
     183            5 :                                 return -EINVAL;
     184              :                         }
     185          298 :                         argc--;
     186              :                 } else {
     187            0 :                         *error = "Unrecognised cache option requested";
     188            0 :                         return -EINVAL;
     189              :                 }
     190              :         }
     191              : 
     192              :         return 0;
     193              : }
     194              : 
     195          308 : static int pcache_start(struct dm_pcache *pcache, char **error)
     196              : {
     197          308 :         int ret;
     198              : 
     199          308 :         ret = cache_dev_start(pcache);
     200          308 :         if (ret) {
     201            0 :                 *error = "Failed to start cache dev";
     202            0 :                 return ret;
     203              :         }
     204              : 
     205          308 :         ret = backing_dev_start(pcache);
     206          308 :         if (ret) {
     207            0 :                 *error = "Failed to start backing dev";
     208            0 :                 goto stop_cache;
     209              :         }
     210              : 
     211          308 :         ret = pcache_cache_start(pcache);
     212          308 :         if (ret) {
     213            5 :                 *error = "Failed to start pcache";
     214            5 :                 goto stop_backing;
     215              :         }
     216              : 
     217              :         return 0;
     218            5 : stop_backing:
     219            5 :         backing_dev_stop(pcache);
     220            5 : stop_cache:
     221            5 :         cache_dev_stop(pcache);
     222              : 
     223            5 :         return ret;
     224              : }
     225              : 
     226          465 : static void pcache_destroy_args(struct dm_pcache *pcache)
     227              : {
     228          465 :         if (pcache->cache_dev.dm_dev)
     229          465 :                 dm_put_device(pcache->ti, pcache->cache_dev.dm_dev);
     230          465 :         if (pcache->backing_dev.dm_dev)
     231          465 :                 dm_put_device(pcache->ti, pcache->backing_dev.dm_dev);
     232          465 : }
     233              : 
     234          463 : static int pcache_parse_args(struct dm_pcache *pcache, unsigned int argc, char **argv,
     235              :                                 char **error)
     236              : {
     237          463 :         struct dm_arg_set as;
     238          463 :         int ret;
     239              : 
     240          463 :         as.argc = argc;
     241          463 :         as.argv = argv;
     242              : 
     243              :         /*
     244              :          * Parse cache device
     245              :          */
     246          463 :         ret = parse_cache_dev(pcache, &as, error);
     247          463 :         if (ret)
     248              :                 return ret;
     249              :         /*
     250              :          * Parse backing device
     251              :          */
     252          463 :         ret = parse_backing_dev(pcache, &as, error);
     253          463 :         if (ret)
     254            0 :                 goto out;
     255              :         /*
     256              :          * Parse optional arguments
     257              :          */
     258          463 :         ret = parse_cache_opts(pcache, &as, error);
     259          463 :         if (ret)
     260          155 :                 goto out;
     261              : 
     262              :         return 0;
     263          155 : out:
     264          155 :         pcache_destroy_args(pcache);
     265          155 :         return ret;
     266              : }
     267              : 
     268          469 : static int dm_pcache_ctr(struct dm_target *ti, unsigned int argc, char **argv)
     269              : {
     270          469 :         struct mapped_device *md = ti->table->md;
     271          469 :         struct dm_pcache *pcache;
     272          469 :         int ret;
     273              : 
     274          469 :         if (md->map) {
     275            6 :                 ti->error = "Don't support table loading for live md";
     276            6 :                 return -EOPNOTSUPP;
     277              :         }
     278              : 
     279              :         /* Allocate memory for the cache structure */
     280          463 :         pcache = kzalloc(sizeof(struct dm_pcache), GFP_KERNEL);
     281          463 :         if (!pcache)
     282              :                 return -ENOMEM;
     283              : 
     284          926 :         pcache->task_wq = alloc_workqueue("pcache-%s-wq",  WQ_UNBOUND | WQ_MEM_RECLAIM,
     285          463 :                                           0, md->name);
     286          463 :         if (!pcache->task_wq) {
     287            0 :                 ret = -ENOMEM;
     288            0 :                 goto free_pcache;
     289              :         }
     290              : 
     291          463 :         spin_lock_init(&pcache->defered_req_list_lock);
     292          463 :         INIT_LIST_HEAD(&pcache->defered_req_list);
     293          463 :         INIT_WORK(&pcache->defered_req_work, defered_req_fn);
     294          463 :         pcache->ti = ti;
     295              : 
     296          463 :         ret = pcache_parse_args(pcache, argc, argv, &ti->error);
     297          463 :         if (ret)
     298          155 :                 goto destroy_wq;
     299              : 
     300          308 :         ret = pcache_start(pcache, &ti->error);
     301          308 :         if (ret)
     302            5 :                 goto destroy_args;
     303              : 
     304          303 :         ti->num_flush_bios = 1;
     305          303 :         ti->flush_supported = true;
     306          303 :         ti->per_io_data_size = sizeof(struct pcache_request);
     307          303 :         ti->private = pcache;
     308          303 :         atomic_set(&pcache->state, PCACHE_STATE_RUNNING);
     309              : 
     310          303 :         return 0;
     311            5 : destroy_args:
     312            5 :         pcache_destroy_args(pcache);
     313          160 : destroy_wq:
     314          160 :         destroy_workqueue(pcache->task_wq);
     315          160 : free_pcache:
     316          160 :         kfree(pcache);
     317              : 
     318          160 :         return ret;
     319              : }
     320              : 
     321          305 : static void defer_req_stop(struct dm_pcache *pcache)
     322              : {
     323          305 :         struct pcache_request *pcache_req;
     324          305 :         LIST_HEAD(tmp_list);
     325              : 
     326          305 :         flush_work(&pcache->defered_req_work);
     327              : 
     328          305 :         spin_lock(&pcache->defered_req_list_lock);
     329          305 :         list_splice_init(&pcache->defered_req_list, &tmp_list);
     330          305 :         spin_unlock(&pcache->defered_req_list_lock);
     331              : 
     332          610 :         while (!list_empty(&tmp_list)) {
     333            0 :                 pcache_req = list_first_entry(&tmp_list,
     334              :                                             struct pcache_request, list_node);
     335            0 :                 list_del_init(&pcache_req->list_node);
     336            0 :                 pcache_req_put(pcache_req, -EIO);
     337              :         }
     338          305 : }
     339              : 
     340          305 : static void dm_pcache_dtr(struct dm_target *ti)
     341              : {
     342          305 :         struct dm_pcache *pcache;
     343              : 
     344          305 :         pcache = ti->private;
     345              : 
     346          305 :         atomic_set(&pcache->state, PCACHE_STATE_STOPPING);
     347              : 
     348          305 :         defer_req_stop(pcache);
     349          305 :         pcache_cache_stop(pcache);
     350          305 :         backing_dev_stop(pcache);
     351          305 :         cache_dev_stop(pcache);
     352              : 
     353          305 :         pcache_destroy_args(pcache);
     354          305 :         drain_workqueue(pcache->task_wq);
     355          305 :         destroy_workqueue(pcache->task_wq);
     356              : 
     357          305 :         kfree(pcache);
     358          305 : }
     359              : 
     360     55477005 : static int dm_pcache_map_bio(struct dm_target *ti, struct bio *bio)
     361              : {
     362     55477005 :         struct pcache_request *pcache_req = dm_per_bio_data(bio, sizeof(struct pcache_request));
     363     55475788 :         struct dm_pcache *pcache = ti->private;
     364     55475788 :         int ret;
     365              : 
     366     55475788 :         pcache_req->pcache = pcache;
     367     55475788 :         kref_init(&pcache_req->ref);
     368     55475788 :         pcache_req->ret = 0;
     369     55475788 :         pcache_req->bio = bio;
     370     55475788 :         pcache_req->off = (u64)bio->bi_iter.bi_sector << SECTOR_SHIFT;
     371     55475788 :         pcache_req->data_len = bio->bi_iter.bi_size;
     372     55475788 :         INIT_LIST_HEAD(&pcache_req->list_node);
     373              : 
     374     55475788 :         ret = pcache_cache_handle_req(&pcache->cache, pcache_req);
     375     55041709 :         if (ret == -EBUSY)
     376      1108770 :                 defer_req(pcache_req);
     377              :         else
     378     53932939 :                 pcache_req_put(pcache_req, ret);
     379              : 
     380     55345173 :         return DM_MAPIO_SUBMITTED;
     381              : }
     382              : 
     383         1021 : static void dm_pcache_status(struct dm_target *ti, status_type_t type,
     384              :                              unsigned int status_flags, char *result,
     385              :                              unsigned int maxlen)
     386              : {
     387         1021 :         struct dm_pcache *pcache = ti->private;
     388         1021 :         struct pcache_cache_dev *cache_dev = &pcache->cache_dev;
     389         1021 :         struct pcache_backing_dev *backing_dev = &pcache->backing_dev;
     390         1021 :         struct pcache_cache *cache = &pcache->cache;
     391         1021 :         unsigned int sz = 0;
     392              : 
     393         1021 :         switch (type) {
     394           78 :         case STATUSTYPE_INFO:
     395          156 :                 DMEMIT("%x %u %u %u %u %x %u:%u %u:%u %u:%u",
     396              :                        cache_dev->sb_flags,
     397              :                        cache_dev->seg_num,
     398              :                        cache->n_segs,
     399              :                        bitmap_weight(cache->seg_map, cache->n_segs),
     400              :                        pcache_cache_get_gc_percent(cache),
     401              :                        cache->cache_info.flags,
     402              :                        cache->key_head.cache_seg->cache_seg_id,
     403              :                        cache->key_head.seg_off,
     404              :                        cache->dirty_tail.cache_seg->cache_seg_id,
     405              :                        cache->dirty_tail.seg_off,
     406              :                        cache->key_tail.cache_seg->cache_seg_id,
     407              :                        cache->key_tail.seg_off);
     408           78 :                 break;
     409          640 :         case STATUSTYPE_TABLE:
     410          954 :                 DMEMIT("%s %s 4 cache_mode writeback crc %s",
     411              :                        cache_dev->dm_dev->name,
     412              :                        backing_dev->dm_dev->name,
     413              :                        cache_data_crc_on(cache) ? "true" : "false");
     414          640 :                 break;
     415          303 :         case STATUSTYPE_IMA:
     416          303 :                 *result = '\0';
     417          303 :                 break;
     418              :         }
     419         1021 : }
     420              : 
     421          104 : static int dm_pcache_message(struct dm_target *ti, unsigned int argc,
     422              :                              char **argv, char *result, unsigned int maxlen)
     423              : {
     424          104 :         struct dm_pcache *pcache = ti->private;
     425          104 :         unsigned long val;
     426              : 
     427          104 :         if (argc != 2)
     428            6 :                 goto err;
     429              : 
     430           98 :         if (!strcasecmp(argv[0], "gc_percent")) {
     431           92 :                 if (kstrtoul(argv[1], 10, &val))
     432            6 :                         goto err;
     433              : 
     434           86 :                 return pcache_cache_set_gc_percent(&pcache->cache, val);
     435              :         }
     436            6 : err:
     437              :         return -EINVAL;
     438              : }
     439              : 
     440              : static struct target_type dm_pcache_target = {
     441              :         .name           = "pcache",
     442              :         .version        = {0, 1, 0},
     443              :         .module         = THIS_MODULE,
     444              :         .features       = DM_TARGET_SINGLETON,
     445              :         .ctr            = dm_pcache_ctr,
     446              :         .dtr            = dm_pcache_dtr,
     447              :         .map            = dm_pcache_map_bio,
     448              :         .status         = dm_pcache_status,
     449              :         .message        = dm_pcache_message,
     450              : };
     451              : 
     452          289 : static int __init dm_pcache_init(void)
     453              : {
     454          289 :         int ret;
     455              : 
     456          289 :         ret = pcache_backing_init();
     457          289 :         if (ret)
     458            0 :                 goto err;
     459              : 
     460          289 :         ret = pcache_cache_init();
     461          289 :         if (ret)
     462            0 :                 goto backing_exit;
     463              : 
     464          289 :         ret = dm_register_target(&dm_pcache_target);
     465          289 :         if (ret)
     466            0 :                 goto cache_exit;
     467              :         return 0;
     468              : 
     469            0 : cache_exit:
     470            0 :         pcache_cache_exit();
     471            0 : backing_exit:
     472            0 :         pcache_backing_exit();
     473              : err:
     474              :         return ret;
     475              : }
     476              : module_init(dm_pcache_init);
     477              : 
     478          165 : static void __exit dm_pcache_exit(void)
     479              : {
     480          165 :         dm_unregister_target(&dm_pcache_target);
     481          165 :         pcache_cache_exit();
     482          165 :         pcache_backing_exit();
     483          165 : }
     484              : module_exit(dm_pcache_exit);
     485              : 
     486              : MODULE_DESCRIPTION("dm-pcache Persistent Cache for block device");
     487              : MODULE_AUTHOR("Dongsheng Yang <dongsheng.yang@linux.dev>");
     488              : MODULE_LICENSE("GPL");
        

Generated by: LCOV version 2.0-1