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-04 03:13:17 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          310 : static void cache_dev_dax_exit(struct pcache_cache_dev *cache_dev)
      15              : {
      16          310 :         if (cache_dev->use_vmap)
      17          126 :                 vunmap(cache_dev->mapping);
      18          310 : }
      19              : 
      20          124 : static int build_vmap(struct dax_device *dax_dev, long total_pages, void **vaddr)
      21              : {
      22          124 :         struct page **pages;
      23          124 :         long i = 0, chunk;
      24          124 :         pfn_t pfn;
      25          124 :         int ret;
      26              : 
      27          124 :         pages = vmalloc_array(total_pages, sizeof(struct page *));
      28          124 :         if (!pages)
      29              :                 return -ENOMEM;
      30              : 
      31    130023424 :         do {
      32    130023424 :                 chunk = dax_direct_access(dax_dev, i, total_pages - i,
      33              :                                           DAX_ACCESS, NULL, &pfn);
      34    130023424 :                 if (chunk <= 0) {
      35            0 :                         ret = chunk ? chunk : -EINVAL;
      36            0 :                         goto out_free;
      37              :                 }
      38              : 
      39    130023424 :                 if (!pfn_t_has_page(pfn)) {
      40            0 :                         ret = -EOPNOTSUPP;
      41            0 :                         goto out_free;
      42              :                 }
      43              : 
      44    260046848 :                 while (chunk-- && i < total_pages) {
      45    130023424 :                         pages[i++] = pfn_t_to_page(pfn);
      46    130023424 :                         pfn.val++;
      47    130023424 :                         if (!(i & 15))
      48      8126464 :                                 cond_resched();
      49              :                 }
      50    130023424 :         } while (i < total_pages);
      51              : 
      52          124 :         *vaddr = vmap(pages, total_pages, VM_MAP, PAGE_KERNEL);
      53          124 :         if (!*vaddr)
      54            0 :                 ret = -ENOMEM;
      55          124 : out_free:
      56          124 :         vfree(pages);
      57          124 :         return ret;
      58              : }
      59              : 
      60          308 : static int cache_dev_dax_init(struct pcache_cache_dev *cache_dev)
      61              : {
      62          308 :         struct dm_pcache        *pcache = CACHE_DEV_TO_PCACHE(cache_dev);
      63          308 :         struct dax_device       *dax_dev;
      64          308 :         long                    total_pages, mapped_pages;
      65          308 :         u64                     bdev_size;
      66          308 :         void                    *vaddr;
      67          308 :         int                     ret;
      68          308 :         int                     id;
      69          308 :         pfn_t                   pfn;
      70              : 
      71          308 :         dax_dev = cache_dev->dm_dev->dax_dev;
      72              :         /* total size check */
      73          308 :         bdev_size = bdev_nr_bytes(cache_dev->dm_dev->bdev);
      74          308 :         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          308 :         total_pages = bdev_size >> PAGE_SHIFT;
      82              :         /* attempt: direct-map the whole range */
      83          308 :         id = dax_read_lock();
      84          308 :         mapped_pages = dax_direct_access(dax_dev, 0, total_pages,
      85              :                                          DAX_ACCESS, &vaddr, &pfn);
      86          308 :         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          308 :         if (!pfn_t_has_page(pfn)) {
      93            0 :                 ret = -EOPNOTSUPP;
      94            0 :                 goto unlock;
      95              :         }
      96              : 
      97          308 :         if (mapped_pages == total_pages) {
      98              :                 /* success: contiguous direct mapping */
      99          184 :                 cache_dev->mapping = vaddr;
     100              :         } else {
     101              :                 /* need vmap fallback */
     102          124 :                 ret = build_vmap(dax_dev, total_pages, &vaddr);
     103          124 :                 if (ret) {
     104            0 :                         pcache_dev_err(pcache, "vmap fallback failed: %d\n", ret);
     105            0 :                         goto unlock;
     106              :                 }
     107              : 
     108          124 :                 cache_dev->mapping   = vaddr;
     109          124 :                 cache_dev->use_vmap  = true;
     110              :         }
     111          308 :         dax_read_unlock(id);
     112              : 
     113          308 :         return 0;
     114            0 : unlock:
     115            0 :         dax_read_unlock(id);
     116              : out:
     117              :         return ret;
     118              : }
     119              : 
     120        71808 : void cache_dev_zero_range(struct pcache_cache_dev *cache_dev, void *pos, u32 size)
     121              : {
     122        71808 :         memset(pos, 0, size);
     123        71808 :         dax_flush(cache_dev->dm_dev->dax_dev, pos, size);
     124        71808 : }
     125              : 
     126          308 : static int sb_read(struct pcache_cache_dev *cache_dev, struct pcache_sb *sb)
     127              : {
     128          308 :         struct pcache_sb *sb_addr = CACHE_DEV_SB(cache_dev);
     129              : 
     130          308 :         if (copy_mc_to_kernel(sb, sb_addr, sizeof(struct pcache_sb)))
     131            0 :                 return -EIO;
     132              : 
     133              :         return 0;
     134              : }
     135              : 
     136          253 : static void sb_write(struct pcache_cache_dev *cache_dev, struct pcache_sb *sb)
     137              : {
     138          253 :         struct pcache_sb *sb_addr = CACHE_DEV_SB(cache_dev);
     139              : 
     140          253 :         memcpy_flushcache(sb_addr, sb, sizeof(struct pcache_sb));
     141          253 :         pmem_wmb();
     142          253 : }
     143              : 
     144          253 : static int sb_init(struct pcache_cache_dev *cache_dev, struct pcache_sb *sb)
     145              : {
     146          253 :         struct dm_pcache *pcache = CACHE_DEV_TO_PCACHE(cache_dev);
     147          253 :         u64 nr_segs;
     148          253 :         u64 cache_dev_size;
     149          253 :         u64 magic;
     150          253 :         u32 flags = 0;
     151              : 
     152          253 :         magic = le64_to_cpu(sb->magic);
     153          253 :         if (magic)
     154              :                 return -EEXIST;
     155              : 
     156          253 :         cache_dev_size = bdev_nr_bytes(file_bdev(cache_dev->dm_dev->bdev_file));
     157          253 :         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          253 :         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          253 :         sb->flags = cpu_to_le32(flags);
     169          253 :         sb->magic = cpu_to_le64(PCACHE_MAGIC);
     170          253 :         sb->seg_num = cpu_to_le32(nr_segs);
     171          253 :         sb->crc = cpu_to_le32(crc32c(PCACHE_CRC_SEED, (void *)(sb) + 4, sizeof(struct pcache_sb) - 4));
     172              : 
     173          253 :         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          253 :         return 0;
     178              : }
     179              : 
     180          308 : static int sb_validate(struct pcache_cache_dev *cache_dev, struct pcache_sb *sb)
     181              : {
     182          308 :         struct dm_pcache *pcache = CACHE_DEV_TO_PCACHE(cache_dev);
     183          308 :         u32 flags;
     184          308 :         u32 crc;
     185              : 
     186          308 :         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          308 :         crc = crc32c(PCACHE_CRC_SEED, (void *)(sb) + 4, sizeof(struct pcache_sb) - 4);
     193          308 :         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          308 :         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          308 :         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          308 : static int cache_dev_init(struct pcache_cache_dev *cache_dev, u32 seg_num)
     214              : {
     215          308 :         cache_dev->seg_num = seg_num;
     216          308 :         cache_dev->seg_bitmap = kvcalloc(BITS_TO_LONGS(cache_dev->seg_num), sizeof(unsigned long), GFP_KERNEL);
     217          308 :         if (!cache_dev->seg_bitmap)
     218            0 :                 return -ENOMEM;
     219              : 
     220              :         return 0;
     221              : }
     222              : 
     223          310 : static void cache_dev_exit(struct pcache_cache_dev *cache_dev)
     224              : {
     225          310 :         kvfree(cache_dev->seg_bitmap);
     226              : }
     227              : 
     228          310 : void cache_dev_stop(struct dm_pcache *pcache)
     229              : {
     230          310 :         struct pcache_cache_dev *cache_dev = &pcache->cache_dev;
     231              : 
     232          310 :         cache_dev_exit(cache_dev);
     233          310 :         cache_dev_dax_exit(cache_dev);
     234          310 : }
     235              : 
     236          308 : int cache_dev_start(struct dm_pcache *pcache)
     237              : {
     238          308 :         struct pcache_cache_dev *cache_dev = &pcache->cache_dev;
     239          308 :         struct pcache_sb sb;
     240          308 :         bool format = false;
     241          308 :         int ret;
     242              : 
     243          308 :         mutex_init(&cache_dev->seg_lock);
     244              : 
     245          308 :         ret = cache_dev_dax_init(cache_dev);
     246          308 :         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          308 :         ret = sb_read(cache_dev, &sb);
     253          308 :         if (ret)
     254            0 :                 goto dax_release;
     255              : 
     256          308 :         if (le64_to_cpu(sb.magic) == 0) {
     257          253 :                 format = true;
     258          253 :                 ret = sb_init(cache_dev, &sb);
     259          253 :                 if (ret < 0)
     260            0 :                         goto dax_release;
     261              :         }
     262              : 
     263          308 :         ret = sb_validate(cache_dev, &sb);
     264          308 :         if (ret)
     265            0 :                 goto dax_release;
     266              : 
     267          308 :         cache_dev->sb_flags = le32_to_cpu(sb.flags);
     268          308 :         ret = cache_dev_init(cache_dev, le32_to_cpu(sb.seg_num));
     269          308 :         if (ret)
     270            0 :                 goto dax_release;
     271              : 
     272          308 :         if (format)
     273          253 :                 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        71555 : int cache_dev_get_empty_segment_id(struct pcache_cache_dev *cache_dev, u32 *seg_id)
     284              : {
     285        71555 :         int ret;
     286              : 
     287        71555 :         mutex_lock(&cache_dev->seg_lock);
     288        71555 :         *seg_id = find_next_zero_bit(cache_dev->seg_bitmap, cache_dev->seg_num, 0);
     289        71555 :         if (*seg_id == cache_dev->seg_num) {
     290            0 :                 ret = -ENOSPC;
     291            0 :                 goto unlock;
     292              :         }
     293              : 
     294        71555 :         __set_bit(*seg_id, cache_dev->seg_bitmap);
     295              :         ret = 0;
     296        71555 : unlock:
     297        71555 :         mutex_unlock(&cache_dev->seg_lock);
     298        71555 :         return ret;
     299              : }
        

Generated by: LCOV version 2.0-1