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

Generated by: LCOV version 2.0-1