Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

dax: Add dax_operations for use by fs-dax on fsdev dax

fsdev: Add dax_operations for use by famfs.

This replicates the functionality from drivers/nvdimm/pmem.c that
conventional fs-dax file systems (e.g. xfs) use to support dax
read/write/mmap to a daxdev - without which famfs can't sit atop a
daxdev.

- These methods are based on pmem_dax_ops from drivers/nvdimm/pmem.c
- fsdev_dax_direct_access() returns the hpa, pfn and kva. The kva was
newly stored as dev_dax->virt_addr by dev_dax_probe().
- The hpa/pfn are used for mmap (dax_iomap_fault()), and the kva is used
for read/write (dax_iomap_rw())
- fsdev_dax_recovery_write() and dev_dax_zero_page_range() have not been
tested yet. I'm looking for suggestions as to how to test those.
- dax-private.h: add dev_dax->cached_size, which fsdev needs to
remember. The dev_dax size cannot change while a driver is bound
(dev_dax_resize returns -EBUSY if dev->driver is set). Caching the size
at probe time allows fsdev's direct_access path can use it without
acquiring dax_dev_rwsem (which isn't exported anyway).

Signed-off-by: John Groves <john@groves.net>
Link: https://patch.msgid.link/0100019d311d415a-bd6af0fe-5445-484c-9d39-210b8170b686-000000@email.amazonses.com
Signed-off-by: Ira Weiny <ira.weiny@intel.com>

authored by

John Groves and committed by
Ira Weiny
099c81a1 75945584

+86
+2
drivers/dax/dax-private.h
··· 70 70 * @region: parent region 71 71 * @dax_dev: core dax functionality 72 72 * @virt_addr: kva from memremap; used by fsdev_dax 73 + * @cached_size: size of daxdev cached by fsdev_dax 73 74 * @align: alignment of this instance 74 75 * @target_node: effective numa node if dev_dax memory range is onlined 75 76 * @dyn_id: is this a dynamic or statically created instance ··· 86 85 struct dax_region *region; 87 86 struct dax_device *dax_dev; 88 87 void *virt_addr; 88 + u64 cached_size; 89 89 unsigned int align; 90 90 int target_node; 91 91 bool dyn_id;
+84
drivers/dax/fsdev.c
··· 28 28 * - No mmap support - all access is through fs-dax/iomap 29 29 */ 30 30 31 + static void fsdev_write_dax(void *addr, struct page *page, 32 + unsigned int off, unsigned int len) 33 + { 34 + while (len) { 35 + void *mem = kmap_local_page(page); 36 + unsigned int chunk = min_t(unsigned int, len, PAGE_SIZE - off); 37 + 38 + memcpy_flushcache(addr, mem + off, chunk); 39 + kunmap_local(mem); 40 + len -= chunk; 41 + off = 0; 42 + page++; 43 + addr += chunk; 44 + } 45 + } 46 + 47 + static long __fsdev_dax_direct_access(struct dax_device *dax_dev, pgoff_t pgoff, 48 + long nr_pages, enum dax_access_mode mode, void **kaddr, 49 + unsigned long *pfn) 50 + { 51 + struct dev_dax *dev_dax = dax_get_private(dax_dev); 52 + size_t size = nr_pages << PAGE_SHIFT; 53 + size_t offset = pgoff << PAGE_SHIFT; 54 + void *virt_addr = dev_dax->virt_addr + offset; 55 + phys_addr_t phys; 56 + unsigned long local_pfn; 57 + 58 + phys = dax_pgoff_to_phys(dev_dax, pgoff, size); 59 + if (phys == -1) { 60 + dev_dbg(&dev_dax->dev, 61 + "pgoff (%#lx) out of range\n", pgoff); 62 + return -EFAULT; 63 + } 64 + 65 + if (kaddr) 66 + *kaddr = virt_addr; 67 + 68 + local_pfn = PHYS_PFN(phys); 69 + if (pfn) 70 + *pfn = local_pfn; 71 + 72 + /* 73 + * Use cached_size which was computed at probe time. The size cannot 74 + * change while the driver is bound (resize returns -EBUSY). 75 + */ 76 + return PHYS_PFN(min(size, dev_dax->cached_size - offset)); 77 + } 78 + 79 + static int fsdev_dax_zero_page_range(struct dax_device *dax_dev, 80 + pgoff_t pgoff, size_t nr_pages) 81 + { 82 + void *kaddr; 83 + 84 + WARN_ONCE(nr_pages > 1, "%s: nr_pages > 1\n", __func__); 85 + __fsdev_dax_direct_access(dax_dev, pgoff, 1, DAX_ACCESS, &kaddr, NULL); 86 + fsdev_write_dax(kaddr, ZERO_PAGE(0), 0, PAGE_SIZE); 87 + return 0; 88 + } 89 + 90 + static long fsdev_dax_direct_access(struct dax_device *dax_dev, 91 + pgoff_t pgoff, long nr_pages, enum dax_access_mode mode, 92 + void **kaddr, unsigned long *pfn) 93 + { 94 + return __fsdev_dax_direct_access(dax_dev, pgoff, nr_pages, mode, 95 + kaddr, pfn); 96 + } 97 + 98 + static size_t fsdev_dax_recovery_write(struct dax_device *dax_dev, pgoff_t pgoff, 99 + void *addr, size_t bytes, struct iov_iter *i) 100 + { 101 + return _copy_from_iter_flushcache(addr, bytes, i); 102 + } 103 + 104 + static const struct dax_operations dev_dax_ops = { 105 + .direct_access = fsdev_dax_direct_access, 106 + .zero_page_range = fsdev_dax_zero_page_range, 107 + .recovery_write = fsdev_dax_recovery_write, 108 + }; 109 + 31 110 static void fsdev_cdev_del(void *cdev) 32 111 { 33 112 cdev_del(cdev); ··· 245 166 return -EBUSY; 246 167 } 247 168 } 169 + 170 + /* Cache size now; it cannot change while driver is bound */ 171 + dev_dax->cached_size = 0; 172 + for (i = 0; i < dev_dax->nr_range; i++) 173 + dev_dax->cached_size += range_len(&dev_dax->ranges[i].range); 248 174 249 175 /* 250 176 * Use MEMORY_DEVICE_FS_DAX without setting vmemmap_shift, leaving