LCOV - code coverage report
Current view: top level - dm-pcache - cache_dev.c (source / functions) Coverage Total Hit
Test: dm_pcache.info Lines: 77.8 % 167 130
Test Date: 2025-08-08 03:56:04 Functions: 100.0 % 12 12
Legend: Lines: hit not hit

            Line data    Source code
       1              : // SPDX-License-Identifier: GPL-2.0-or-later
       2              : 
       3              : #include <linux/blkdev.h>
       4              : #include <linux/dax.h>
       5              : #include <linux/vmalloc.h>
       6              : #include <linux/pfn_t.h>
       7              : #include <linux/parser.h>
       8              : 
       9              : #include "cache_dev.h"
      10              : #include "backing_dev.h"
      11              : #include "cache.h"
      12              : #include "dm_pcache.h"
      13              : 
      14          404 : static void cache_dev_dax_exit(struct pcache_cache_dev *cache_dev)
      15              : {
      16          404 :         if (cache_dev->use_vmap)
      17          137 :                 vunmap(cache_dev->mapping);
      18          404 : }
      19              : 
      20          137 : static int build_vmap(struct dax_device *dax_dev, long total_pages, void **vaddr)
      21              : {
      22          137 :         struct page **pages;
      23          137 :         long i = 0, chunk;
      24          137 :         pfn_t pfn;
      25          137 :         int ret;
      26              : 
      27          137 :         pages = vmalloc_array(total_pages, sizeof(struct page *));
      28          137 :         if (!pages)
      29              :                 return -ENOMEM;
      30              : 
      31    143654912 :         do {
      32    143654912 :                 chunk = dax_direct_access(dax_dev, i, total_pages - i,
      33              :                                           DAX_ACCESS, NULL, &pfn);
      34    143654912 :                 if (chunk <= 0) {
      35            0 :                         ret = chunk ? chunk : -EINVAL;
      36            0 :                         goto out_free;
      37              :                 }
      38              : 
      39    143654912 :                 if (!pfn_t_has_page(pfn)) {
      40            0 :                         ret = -EOPNOTSUPP;
      41            0 :                         goto out_free;
      42              :                 }
      43              : 
      44    287309824 :                 while (chunk-- && i < total_pages) {
      45    143654912 :                         pages[i++] = pfn_t_to_page(pfn);
      46    143654912 :                         pfn.val++;
      47    143654912 :                         if (!(i & 15))
      48      8978432 :                                 cond_resched();
      49              :                 }
      50    143654912 :         } while (i < total_pages);
      51              : 
      52          137 :         *vaddr = vmap(pages, total_pages, VM_MAP, PAGE_KERNEL);
      53          137 :         if (!*vaddr)
      54            0 :                 ret = -ENOMEM;
      55          137 : out_free:
      56          137 :         vfree(pages);
      57          137 :         return ret;
      58              : }
      59              : 
      60          404 : static int cache_dev_dax_init(struct pcache_cache_dev *cache_dev)
      61              : {
      62          404 :         struct dm_pcache        *pcache = CACHE_DEV_TO_PCACHE(cache_dev);
      63          404 :         struct dax_device       *dax_dev;
      64          404 :         long                    total_pages, mapped_pages;
      65          404 :         u64                     bdev_size;
      66          404 :         void                    *vaddr;
      67          404 :         int                     ret;
      68          404 :         int                     id;
      69          404 :         pfn_t                   pfn;
      70              : 
      71          404 :         dax_dev = cache_dev->dm_dev->dax_dev;
      72              :         /* total size check */
      73          404 :         bdev_size = bdev_nr_bytes(cache_dev->dm_dev->bdev);
      74          404 :         if (bdev_size < PCACHE_CACHE_DEV_SIZE_MIN) {
      75            0 :                 pcache_dev_err(pcache, "dax device is too small, required at least %llu",
      76              :                                 PCACHE_CACHE_DEV_SIZE_MIN);
      77            0 :                 ret = -ENOSPC;
      78            0 :                 goto out;
      79              :         }
      80              : 
      81          404 :         total_pages = bdev_size >> PAGE_SHIFT;
      82              :         /* attempt: direct-map the whole range */
      83          404 :         id = dax_read_lock();
      84          404 :         mapped_pages = dax_direct_access(dax_dev, 0, total_pages,
      85              :                                          DAX_ACCESS, &vaddr, &pfn);
      86          404 :         if (mapped_pages < 0) {
      87            0 :                 pcache_dev_err(pcache, "dax_direct_access failed: %ld\n", mapped_pages);
      88            0 :                 ret = mapped_pages;
      89            0 :                 goto unlock;
      90              :         }
      91              : 
      92          404 :         if (!pfn_t_has_page(pfn)) {
      93            0 :                 ret = -EOPNOTSUPP;
      94            0 :                 goto unlock;
      95              :         }
      96              : 
      97          404 :         if (mapped_pages == total_pages) {
      98              :                 /* success: contiguous direct mapping */
      99          267 :                 cache_dev->mapping = vaddr;
     100              :         } else {
     101              :                 /* need vmap fallback */
     102          137 :                 ret = build_vmap(dax_dev, total_pages, &vaddr);
     103          137 :                 if (ret) {
     104            0 :                         pcache_dev_err(pcache, "vmap fallback failed: %d\n", ret);
     105            0 :                         goto unlock;
     106              :                 }
     107              : 
     108          137 :                 cache_dev->mapping   = vaddr;
     109          137 :                 cache_dev->use_vmap  = true;
     110              :         }
     111          404 :         dax_read_unlock(id);
     112              : 
     113          404 :         return 0;
     114            0 : unlock:
     115            0 :         dax_read_unlock(id);
     116              : out:
     117              :         return ret;
     118              : }
     119              : 
     120        74816 : void cache_dev_zero_range(struct pcache_cache_dev *cache_dev, void *pos, u32 size)
     121              : {
     122        74816 :         memset(pos, 0, size);
     123        74816 :         dax_flush(cache_dev->dm_dev->dax_dev, pos, size);
     124        74816 : }
     125              : 
     126          404 : static int sb_read(struct pcache_cache_dev *cache_dev, struct pcache_sb *sb)
     127              : {
     128          404 :         struct pcache_sb *sb_addr = CACHE_DEV_SB(cache_dev);
     129              : 
     130          404 :         if (copy_mc_to_kernel(sb, sb_addr, sizeof(struct pcache_sb)))
     131            0 :                 return -EIO;
     132              : 
     133              :         return 0;
     134              : }
     135              : 
     136          268 : static void sb_write(struct pcache_cache_dev *cache_dev, struct pcache_sb *sb)
     137              : {
     138          268 :         struct pcache_sb *sb_addr = CACHE_DEV_SB(cache_dev);
     139              : 
     140          268 :         memcpy_flushcache(sb_addr, sb, sizeof(struct pcache_sb));
     141          268 :         pmem_wmb();
     142          268 : }
     143              : 
     144          268 : static int sb_init(struct pcache_cache_dev *cache_dev, struct pcache_sb *sb)
     145              : {
     146          268 :         struct dm_pcache *pcache = CACHE_DEV_TO_PCACHE(cache_dev);
     147          268 :         u64 nr_segs;
     148          268 :         u64 cache_dev_size;
     149          268 :         u64 magic;
     150          268 :         u32 flags = 0;
     151              : 
     152          268 :         magic = le64_to_cpu(sb->magic);
     153          268 :         if (magic)
     154              :                 return -EEXIST;
     155              : 
     156          268 :         cache_dev_size = bdev_nr_bytes(file_bdev(cache_dev->dm_dev->bdev_file));
     157          268 :         if (cache_dev_size < PCACHE_CACHE_DEV_SIZE_MIN) {
     158            0 :                 pcache_dev_err(pcache, "dax device is too small, required at least %llu",
     159              :                                 PCACHE_CACHE_DEV_SIZE_MIN);
     160            0 :                 return -ENOSPC;
     161              :         }
     162              : 
     163          268 :         nr_segs = (cache_dev_size - PCACHE_SEGMENTS_OFF) / ((PCACHE_SEG_SIZE));
     164              : 
     165              : #if defined(__BYTE_ORDER) ? (__BIG_ENDIAN == __BYTE_ORDER) : defined(__BIG_ENDIAN)
     166              :         flags |= PCACHE_SB_F_BIGENDIAN;
     167              : #endif
     168          268 :         sb->flags = cpu_to_le32(flags);
     169          268 :         sb->magic = cpu_to_le64(PCACHE_MAGIC);
     170          268 :         sb->seg_num = cpu_to_le32(nr_segs);
     171          268 :         sb->crc = cpu_to_le32(crc32c(PCACHE_CRC_SEED, (void *)(sb) + 4, sizeof(struct pcache_sb) - 4));
     172              : 
     173          268 :         cache_dev_zero_range(cache_dev, CACHE_DEV_CACHE_INFO(cache_dev),
     174              :                              PCACHE_CACHE_INFO_SIZE * PCACHE_META_INDEX_MAX +
     175              :                              PCACHE_CACHE_CTRL_SIZE);
     176              : 
     177          268 :         return 0;
     178              : }
     179              : 
     180          404 : static int sb_validate(struct pcache_cache_dev *cache_dev, struct pcache_sb *sb)
     181              : {
     182          404 :         struct dm_pcache *pcache = CACHE_DEV_TO_PCACHE(cache_dev);
     183          404 :         u32 flags;
     184          404 :         u32 crc;
     185              : 
     186          404 :         if (le64_to_cpu(sb->magic) != PCACHE_MAGIC) {
     187            0 :                 pcache_dev_err(pcache, "unexpected magic: %llx\n",
     188              :                                 le64_to_cpu(sb->magic));
     189            0 :                 return -EINVAL;
     190              :         }
     191              : 
     192          404 :         crc = crc32c(PCACHE_CRC_SEED, (void *)(sb) + 4, sizeof(struct pcache_sb) - 4);
     193          404 :         if (crc != le32_to_cpu(sb->crc)) {
     194            0 :                 pcache_dev_err(pcache, "corrupted sb: %u, expected: %u\n", crc, le32_to_cpu(sb->crc));
     195            0 :                 return -EINVAL;
     196              :         }
     197              : 
     198          404 :         flags = le32_to_cpu(sb->flags);
     199              : #if defined(__BYTE_ORDER) ? (__BIG_ENDIAN == __BYTE_ORDER) : defined(__BIG_ENDIAN)
     200              :         if (!(flags & PCACHE_SB_F_BIGENDIAN)) {
     201              :                 pcache_dev_err(pcache, "cache_dev is not big endian\n");
     202              :                 return -EINVAL;
     203              :         }
     204              : #else
     205          404 :         if (flags & PCACHE_SB_F_BIGENDIAN) {
     206            0 :                 pcache_dev_err(pcache, "cache_dev is big endian\n");
     207            0 :                 return -EINVAL;
     208              :         }
     209              : #endif
     210              :         return 0;
     211              : }
     212              : 
     213          404 : static int cache_dev_init(struct pcache_cache_dev *cache_dev, u32 seg_num)
     214              : {
     215          404 :         cache_dev->seg_num = seg_num;
     216          404 :         cache_dev->seg_bitmap = kvcalloc(BITS_TO_LONGS(cache_dev->seg_num), sizeof(unsigned long), GFP_KERNEL);
     217          404 :         if (!cache_dev->seg_bitmap)
     218            0 :                 return -ENOMEM;
     219              : 
     220              :         return 0;
     221              : }
     222              : 
     223          404 : static void cache_dev_exit(struct pcache_cache_dev *cache_dev)
     224              : {
     225          404 :         kvfree(cache_dev->seg_bitmap);
     226              : }
     227              : 
     228          404 : void cache_dev_stop(struct dm_pcache *pcache)
     229              : {
     230          404 :         struct pcache_cache_dev *cache_dev = &pcache->cache_dev;
     231              : 
     232          404 :         cache_dev_exit(cache_dev);
     233          404 :         cache_dev_dax_exit(cache_dev);
     234          404 : }
     235              : 
     236          404 : int cache_dev_start(struct dm_pcache *pcache)
     237              : {
     238          404 :         struct pcache_cache_dev *cache_dev = &pcache->cache_dev;
     239          404 :         struct pcache_sb sb;
     240          404 :         bool format = false;
     241          404 :         int ret;
     242              : 
     243          404 :         mutex_init(&cache_dev->seg_lock);
     244              : 
     245          404 :         ret = cache_dev_dax_init(cache_dev);
     246          404 :         if (ret) {
     247            0 :                 pcache_dev_err(pcache, "failed to init cache_dev %s via dax way: %d.",
     248              :                                cache_dev->dm_dev->name, ret);
     249            0 :                 goto err;
     250              :         }
     251              : 
     252          404 :         ret = sb_read(cache_dev, &sb);
     253          404 :         if (ret)
     254            0 :                 goto dax_release;
     255              : 
     256          404 :         if (le64_to_cpu(sb.magic) == 0) {
     257          268 :                 format = true;
     258          268 :                 ret = sb_init(cache_dev, &sb);
     259          268 :                 if (ret < 0)
     260            0 :                         goto dax_release;
     261              :         }
     262              : 
     263          404 :         ret = sb_validate(cache_dev, &sb);
     264          404 :         if (ret)
     265            0 :                 goto dax_release;
     266              : 
     267          404 :         cache_dev->sb_flags = le32_to_cpu(sb.flags);
     268          404 :         ret = cache_dev_init(cache_dev, le32_to_cpu(sb.seg_num));
     269          404 :         if (ret)
     270            0 :                 goto dax_release;
     271              : 
     272          404 :         if (format)
     273          268 :                 sb_write(cache_dev, &sb);
     274              : 
     275              :         return 0;
     276              : 
     277            0 : dax_release:
     278            0 :         cache_dev_dax_exit(cache_dev);
     279              : err:
     280              :         return ret;
     281              : }
     282              : 
     283        74548 : int cache_dev_get_empty_segment_id(struct pcache_cache_dev *cache_dev, u32 *seg_id)
     284              : {
     285        74548 :         int ret;
     286              : 
     287        74548 :         mutex_lock(&cache_dev->seg_lock);
     288        74548 :         *seg_id = find_next_zero_bit(cache_dev->seg_bitmap, cache_dev->seg_num, 0);
     289        74548 :         if (*seg_id == cache_dev->seg_num) {
     290            0 :                 ret = -ENOSPC;
     291            0 :                 goto unlock;
     292              :         }
     293              : 
     294        74548 :         __set_bit(*seg_id, cache_dev->seg_bitmap);
     295              :         ret = 0;
     296        74548 : unlock:
     297        74548 :         mutex_unlock(&cache_dev->seg_lock);
     298        74548 :         return ret;
     299              : }
        

Generated by: LCOV version 2.0-1