1b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */
2c94c2acfSMatthew Wilcox #ifndef _LINUX_DAX_H
3c94c2acfSMatthew Wilcox #define _LINUX_DAX_H
4c94c2acfSMatthew Wilcox
5c94c2acfSMatthew Wilcox #include <linux/fs.h>
6c94c2acfSMatthew Wilcox #include <linux/mm.h>
74f622938SJan Kara #include <linux/radix-tree.h>
8c94c2acfSMatthew Wilcox
927359fd6SMatthew Wilcox typedef unsigned long dax_entry_t;
1027359fd6SMatthew Wilcox
11fb08a190SChristoph Hellwig struct dax_device;
12fb08a190SChristoph Hellwig struct gendisk;
13a254e568SChristoph Hellwig struct iomap_ops;
14c6f40468SChristoph Hellwig struct iomap_iter;
154f3b4f16SVivek Goyal struct iomap;
16fb08a190SChristoph Hellwig
17e511c4a3SJane Chu enum dax_access_mode {
18e511c4a3SJane Chu DAX_ACCESS,
19e511c4a3SJane Chu DAX_RECOVERY_WRITE,
20e511c4a3SJane Chu };
21e511c4a3SJane Chu
226568b08bSDan Williams struct dax_operations {
236568b08bSDan Williams /*
246568b08bSDan Williams * direct_access: translate a device-relative
256568b08bSDan Williams * logical-page-offset into an absolute physical pfn. Return the
266568b08bSDan Williams * number of pages available for DAX at that pfn.
276568b08bSDan Williams */
286568b08bSDan Williams long (*direct_access)(struct dax_device *, pgoff_t, long,
29e511c4a3SJane Chu enum dax_access_mode, void **, pfn_t *);
30f605a263SVivek Goyal /* zero_page_range: required operation. Zero page range */
31f605a263SVivek Goyal int (*zero_page_range)(struct dax_device *, pgoff_t, size_t);
32047218ecSJane Chu /*
33047218ecSJane Chu * recovery_write: recover a poisoned range by DAX device driver
34047218ecSJane Chu * capable of clearing poison.
35047218ecSJane Chu */
36047218ecSJane Chu size_t (*recovery_write)(struct dax_device *dax_dev, pgoff_t pgoff,
37047218ecSJane Chu void *addr, size_t bytes, struct iov_iter *iter);
386568b08bSDan Williams };
39a254e568SChristoph Hellwig
408012b866SShiyang Ruan struct dax_holder_operations {
418012b866SShiyang Ruan /*
428012b866SShiyang Ruan * notify_failure - notify memory failure into inner holder device
438012b866SShiyang Ruan * @dax_dev: the dax device which contains the holder
448012b866SShiyang Ruan * @offset: offset on this dax device where memory failure occurs
458012b866SShiyang Ruan * @len: length of this memory failure event
468012b866SShiyang Ruan * @flags: action flags for memory failure handler
478012b866SShiyang Ruan */
488012b866SShiyang Ruan int (*notify_failure)(struct dax_device *dax_dev, u64 offset,
498012b866SShiyang Ruan u64 len, int mf_flags);
508012b866SShiyang Ruan };
518012b866SShiyang Ruan
52ef510424SDan Williams #if IS_ENABLED(CONFIG_DAX)
5330c6828aSChristoph Hellwig struct dax_device *alloc_dax(void *private, const struct dax_operations *ops);
548012b866SShiyang Ruan void *dax_holder(struct dax_device *dax_dev);
55ef510424SDan Williams void put_dax(struct dax_device *dax_dev);
56976431b0SDan Williams void kill_dax(struct dax_device *dax_dev);
57976431b0SDan Williams void dax_write_cache(struct dax_device *dax_dev, bool wc);
58976431b0SDan Williams bool dax_write_cache_enabled(struct dax_device *dax_dev);
59fd1d00ecSChristoph Hellwig bool dax_synchronous(struct dax_device *dax_dev);
602807c54bSMathieu Desnoyers void set_dax_nocache(struct dax_device *dax_dev);
612807c54bSMathieu Desnoyers void set_dax_nomc(struct dax_device *dax_dev);
62fd1d00ecSChristoph Hellwig void set_dax_synchronous(struct dax_device *dax_dev);
63047218ecSJane Chu size_t dax_recovery_write(struct dax_device *dax_dev, pgoff_t pgoff,
64047218ecSJane Chu void *addr, size_t bytes, struct iov_iter *i);
6532de1484SPankaj Gupta /*
6632de1484SPankaj Gupta * Check if given mapping is supported by the file / underlying device.
6732de1484SPankaj Gupta */
daxdev_mapping_supported(struct vm_area_struct * vma,struct dax_device * dax_dev)6832de1484SPankaj Gupta static inline bool daxdev_mapping_supported(struct vm_area_struct *vma,
6932de1484SPankaj Gupta struct dax_device *dax_dev)
7032de1484SPankaj Gupta {
7132de1484SPankaj Gupta if (!(vma->vm_flags & VM_SYNC))
7232de1484SPankaj Gupta return true;
7332de1484SPankaj Gupta if (!IS_DAX(file_inode(vma->vm_file)))
7432de1484SPankaj Gupta return false;
7532de1484SPankaj Gupta return dax_synchronous(dax_dev);
7632de1484SPankaj Gupta }
77ef510424SDan Williams #else
dax_holder(struct dax_device * dax_dev)788012b866SShiyang Ruan static inline void *dax_holder(struct dax_device *dax_dev)
798012b866SShiyang Ruan {
808012b866SShiyang Ruan return NULL;
818012b866SShiyang Ruan }
alloc_dax(void * private,const struct dax_operations * ops)82fb08a190SChristoph Hellwig static inline struct dax_device *alloc_dax(void *private,
8330c6828aSChristoph Hellwig const struct dax_operations *ops)
84976431b0SDan Williams {
856d439c18SMathieu Desnoyers return ERR_PTR(-EOPNOTSUPP);
86976431b0SDan Williams }
put_dax(struct dax_device * dax_dev)87ef510424SDan Williams static inline void put_dax(struct dax_device *dax_dev)
88ef510424SDan Williams {
89ef510424SDan Williams }
kill_dax(struct dax_device * dax_dev)90976431b0SDan Williams static inline void kill_dax(struct dax_device *dax_dev)
91976431b0SDan Williams {
92976431b0SDan Williams }
dax_write_cache(struct dax_device * dax_dev,bool wc)93976431b0SDan Williams static inline void dax_write_cache(struct dax_device *dax_dev, bool wc)
94976431b0SDan Williams {
95976431b0SDan Williams }
dax_write_cache_enabled(struct dax_device * dax_dev)96976431b0SDan Williams static inline bool dax_write_cache_enabled(struct dax_device *dax_dev)
97976431b0SDan Williams {
98976431b0SDan Williams return false;
99976431b0SDan Williams }
dax_synchronous(struct dax_device * dax_dev)100fefc1d97SPankaj Gupta static inline bool dax_synchronous(struct dax_device *dax_dev)
101fefc1d97SPankaj Gupta {
102fefc1d97SPankaj Gupta return true;
103fefc1d97SPankaj Gupta }
set_dax_nocache(struct dax_device * dax_dev)1042807c54bSMathieu Desnoyers static inline void set_dax_nocache(struct dax_device *dax_dev)
1052807c54bSMathieu Desnoyers {
1062807c54bSMathieu Desnoyers }
set_dax_nomc(struct dax_device * dax_dev)1072807c54bSMathieu Desnoyers static inline void set_dax_nomc(struct dax_device *dax_dev)
1082807c54bSMathieu Desnoyers {
1092807c54bSMathieu Desnoyers }
set_dax_synchronous(struct dax_device * dax_dev)110fefc1d97SPankaj Gupta static inline void set_dax_synchronous(struct dax_device *dax_dev)
111fefc1d97SPankaj Gupta {
112fefc1d97SPankaj Gupta }
daxdev_mapping_supported(struct vm_area_struct * vma,struct dax_device * dax_dev)11332de1484SPankaj Gupta static inline bool daxdev_mapping_supported(struct vm_area_struct *vma,
11432de1484SPankaj Gupta struct dax_device *dax_dev)
11532de1484SPankaj Gupta {
11632de1484SPankaj Gupta return !(vma->vm_flags & VM_SYNC);
11732de1484SPankaj Gupta }
dax_recovery_write(struct dax_device * dax_dev,pgoff_t pgoff,void * addr,size_t bytes,struct iov_iter * i)118047218ecSJane Chu static inline size_t dax_recovery_write(struct dax_device *dax_dev,
119047218ecSJane Chu pgoff_t pgoff, void *addr, size_t bytes, struct iov_iter *i)
120047218ecSJane Chu {
121047218ecSJane Chu return 0;
122047218ecSJane Chu }
123ef510424SDan Williams #endif
124ef510424SDan Williams
125f44c7763SDan Williams struct writeback_control;
1262ede8923SChristoph Hellwig #if defined(CONFIG_BLOCK) && defined(CONFIG_FS_DAX)
127fb08a190SChristoph Hellwig int dax_add_host(struct dax_device *dax_dev, struct gendisk *disk);
128fb08a190SChristoph Hellwig void dax_remove_host(struct gendisk *disk);
1298012b866SShiyang Ruan struct dax_device *fs_dax_get_by_bdev(struct block_device *bdev, u64 *start_off,
1308012b866SShiyang Ruan void *holder, const struct dax_holder_operations *ops);
1318012b866SShiyang Ruan void fs_put_dax(struct dax_device *dax_dev, void *holder);
132f5705aa8SDan Williams #else
dax_add_host(struct dax_device * dax_dev,struct gendisk * disk)133fb08a190SChristoph Hellwig static inline int dax_add_host(struct dax_device *dax_dev, struct gendisk *disk)
134fb08a190SChristoph Hellwig {
135fb08a190SChristoph Hellwig return 0;
136fb08a190SChristoph Hellwig }
dax_remove_host(struct gendisk * disk)137fb08a190SChristoph Hellwig static inline void dax_remove_host(struct gendisk *disk)
138fb08a190SChristoph Hellwig {
139fb08a190SChristoph Hellwig }
fs_dax_get_by_bdev(struct block_device * bdev,u64 * start_off,void * holder,const struct dax_holder_operations * ops)140cd913c76SChristoph Hellwig static inline struct dax_device *fs_dax_get_by_bdev(struct block_device *bdev,
1418012b866SShiyang Ruan u64 *start_off, void *holder,
1428012b866SShiyang Ruan const struct dax_holder_operations *ops)
14378f35473SDan Williams {
14478f35473SDan Williams return NULL;
14578f35473SDan Williams }
fs_put_dax(struct dax_device * dax_dev,void * holder)1468012b866SShiyang Ruan static inline void fs_put_dax(struct dax_device *dax_dev, void *holder)
1472ede8923SChristoph Hellwig {
1482ede8923SChristoph Hellwig }
1492ede8923SChristoph Hellwig #endif /* CONFIG_BLOCK && CONFIG_FS_DAX */
150f44c7763SDan Williams
1512ede8923SChristoph Hellwig #if IS_ENABLED(CONFIG_FS_DAX)
1522ede8923SChristoph Hellwig int dax_writeback_mapping_range(struct address_space *mapping,
1532ede8923SChristoph Hellwig struct dax_device *dax_dev, struct writeback_control *wbc);
1542ede8923SChristoph Hellwig
1552ede8923SChristoph Hellwig struct page *dax_layout_busy_page(struct address_space *mapping);
1562ede8923SChristoph Hellwig struct page *dax_layout_busy_page_range(struct address_space *mapping, loff_t start, loff_t end);
15791e79d22SMatthew Wilcox (Oracle) dax_entry_t dax_lock_folio(struct folio *folio);
15891e79d22SMatthew Wilcox (Oracle) void dax_unlock_folio(struct folio *folio, dax_entry_t cookie);
1592f437effSShiyang Ruan dax_entry_t dax_lock_mapping_entry(struct address_space *mapping,
1602f437effSShiyang Ruan unsigned long index, struct page **page);
1612f437effSShiyang Ruan void dax_unlock_mapping_entry(struct address_space *mapping,
1622f437effSShiyang Ruan unsigned long index, dax_entry_t cookie);
1632ede8923SChristoph Hellwig #else
dax_layout_busy_page(struct address_space * mapping)1645fac7408SDan Williams static inline struct page *dax_layout_busy_page(struct address_space *mapping)
1655fac7408SDan Williams {
1665fac7408SDan Williams return NULL;
1675fac7408SDan Williams }
1685fac7408SDan Williams
dax_layout_busy_page_range(struct address_space * mapping,pgoff_t start,pgoff_t nr_pages)1696bbdd563SVivek Goyal static inline struct page *dax_layout_busy_page_range(struct address_space *mapping, pgoff_t start, pgoff_t nr_pages)
1706bbdd563SVivek Goyal {
1716bbdd563SVivek Goyal return NULL;
1726bbdd563SVivek Goyal }
1736bbdd563SVivek Goyal
dax_writeback_mapping_range(struct address_space * mapping,struct dax_device * dax_dev,struct writeback_control * wbc)174f44c7763SDan Williams static inline int dax_writeback_mapping_range(struct address_space *mapping,
1753f666c56SVivek Goyal struct dax_device *dax_dev, struct writeback_control *wbc)
176f44c7763SDan Williams {
177f44c7763SDan Williams return -EOPNOTSUPP;
178f44c7763SDan Williams }
179c2a7d2a1SDan Williams
dax_lock_folio(struct folio * folio)18091e79d22SMatthew Wilcox (Oracle) static inline dax_entry_t dax_lock_folio(struct folio *folio)
181c2a7d2a1SDan Williams {
18291e79d22SMatthew Wilcox (Oracle) if (IS_DAX(folio->mapping->host))
18327359fd6SMatthew Wilcox return ~0UL;
18427359fd6SMatthew Wilcox return 0;
185c2a7d2a1SDan Williams }
186c2a7d2a1SDan Williams
dax_unlock_folio(struct folio * folio,dax_entry_t cookie)18791e79d22SMatthew Wilcox (Oracle) static inline void dax_unlock_folio(struct folio *folio, dax_entry_t cookie)
188c2a7d2a1SDan Williams {
189c2a7d2a1SDan Williams }
1902f437effSShiyang Ruan
dax_lock_mapping_entry(struct address_space * mapping,unsigned long index,struct page ** page)1912f437effSShiyang Ruan static inline dax_entry_t dax_lock_mapping_entry(struct address_space *mapping,
1922f437effSShiyang Ruan unsigned long index, struct page **page)
1932f437effSShiyang Ruan {
1942f437effSShiyang Ruan return 0;
1952f437effSShiyang Ruan }
1962f437effSShiyang Ruan
dax_unlock_mapping_entry(struct address_space * mapping,unsigned long index,dax_entry_t cookie)1972f437effSShiyang Ruan static inline void dax_unlock_mapping_entry(struct address_space *mapping,
1982f437effSShiyang Ruan unsigned long index, dax_entry_t cookie)
1992f437effSShiyang Ruan {
2002f437effSShiyang Ruan }
201f5705aa8SDan Williams #endif
202f5705aa8SDan Williams
203d984648eSShiyang Ruan int dax_file_unshare(struct inode *inode, loff_t pos, loff_t len,
204d984648eSShiyang Ruan const struct iomap_ops *ops);
205c6f40468SChristoph Hellwig int dax_zero_range(struct inode *inode, loff_t pos, loff_t len, bool *did_zero,
206c6f40468SChristoph Hellwig const struct iomap_ops *ops);
207c6f40468SChristoph Hellwig int dax_truncate_page(struct inode *inode, loff_t pos, bool *did_zero,
208c6f40468SChristoph Hellwig const struct iomap_ops *ops);
209c6f40468SChristoph Hellwig
dax_page_is_idle(struct page * page)210d5b3afeaSAlistair Popple static inline bool dax_page_is_idle(struct page *page)
211e6fa3963SAlistair Popple {
212*38607c62SAlistair Popple return page && page_ref_count(page) == 0;
213e6fa3963SAlistair Popple }
214e6fa3963SAlistair Popple
215e2ec5128SJan Kara #if IS_ENABLED(CONFIG_DAX)
2167b6be844SDan Williams int dax_read_lock(void);
2177b6be844SDan Williams void dax_read_unlock(int id);
218e2ec5128SJan Kara #else
dax_read_lock(void)219e2ec5128SJan Kara static inline int dax_read_lock(void)
220e2ec5128SJan Kara {
221e2ec5128SJan Kara return 0;
222e2ec5128SJan Kara }
223e2ec5128SJan Kara
dax_read_unlock(int id)224e2ec5128SJan Kara static inline void dax_read_unlock(int id)
225e2ec5128SJan Kara {
226e2ec5128SJan Kara }
227e2ec5128SJan Kara #endif /* CONFIG_DAX */
228d5b3afeaSAlistair Popple
229d5b3afeaSAlistair Popple #if !IS_ENABLED(CONFIG_FS_DAX)
dax_break_layout(struct inode * inode,loff_t start,loff_t end,void (cb)(struct inode *))230d5b3afeaSAlistair Popple static inline int __must_check dax_break_layout(struct inode *inode,
231d5b3afeaSAlistair Popple loff_t start, loff_t end, void (cb)(struct inode *))
232d5b3afeaSAlistair Popple {
233d5b3afeaSAlistair Popple return 0;
234d5b3afeaSAlistair Popple }
2350e2f80afSAlistair Popple
dax_break_layout_final(struct inode * inode)2360e2f80afSAlistair Popple static inline void dax_break_layout_final(struct inode *inode)
2370e2f80afSAlistair Popple {
2380e2f80afSAlistair Popple }
239d5b3afeaSAlistair Popple #endif
240d5b3afeaSAlistair Popple
241c1d6e828SDan Williams bool dax_alive(struct dax_device *dax_dev);
242c1d6e828SDan Williams void *dax_get_private(struct dax_device *dax_dev);
243b0686260SDan Williams long dax_direct_access(struct dax_device *dax_dev, pgoff_t pgoff, long nr_pages,
244e511c4a3SJane Chu enum dax_access_mode mode, void **kaddr, pfn_t *pfn);
2457e026c8cSDan Williams size_t dax_copy_from_iter(struct dax_device *dax_dev, pgoff_t pgoff, void *addr,
2467e026c8cSDan Williams size_t bytes, struct iov_iter *i);
247b3a9a0c3SDan Williams size_t dax_copy_to_iter(struct dax_device *dax_dev, pgoff_t pgoff, void *addr,
248b3a9a0c3SDan Williams size_t bytes, struct iov_iter *i);
249f605a263SVivek Goyal int dax_zero_page_range(struct dax_device *dax_dev, pgoff_t pgoff,
250f605a263SVivek Goyal size_t nr_pages);
2518012b866SShiyang Ruan int dax_holder_notify_failure(struct dax_device *dax_dev, u64 off, u64 len,
2528012b866SShiyang Ruan int mf_flags);
253c3ca015fSMikulas Patocka void dax_flush(struct dax_device *dax_dev, void *addr, size_t size);
2547b6be844SDan Williams
25511c59c92SRoss Zwisler ssize_t dax_iomap_rw(struct kiocb *iocb, struct iov_iter *iter,
2568ff6daa1SChristoph Hellwig const struct iomap_ops *ops);
2571d024e7aSMatthew Wilcox (Oracle) vm_fault_t dax_iomap_fault(struct vm_fault *vmf, unsigned int order,
258c0b24625SJan Kara pfn_t *pfnp, int *errp, const struct iomap_ops *ops);
259ab77dab4SSouptick Joarder vm_fault_t dax_finish_sync_fault(struct vm_fault *vmf,
2601d024e7aSMatthew Wilcox (Oracle) unsigned int order, pfn_t pfn);
261ac401cc7SJan Kara int dax_delete_mapping_entry(struct address_space *mapping, pgoff_t index);
262bde708f1SAlistair Popple void dax_delete_mapping_range(struct address_space *mapping,
263bde708f1SAlistair Popple loff_t start, loff_t end);
264c6dcf52cSJan Kara int dax_invalidate_mapping_entry_sync(struct address_space *mapping,
265c6dcf52cSJan Kara pgoff_t index);
266d5b3afeaSAlistair Popple int __must_check dax_break_layout(struct inode *inode, loff_t start,
267d5b3afeaSAlistair Popple loff_t end, void (cb)(struct inode *));
dax_break_layout_inode(struct inode * inode,void (cb)(struct inode *))268d5b3afeaSAlistair Popple static inline int __must_check dax_break_layout_inode(struct inode *inode,
269d5b3afeaSAlistair Popple void (cb)(struct inode *))
270d5b3afeaSAlistair Popple {
271d5b3afeaSAlistair Popple return dax_break_layout(inode, 0, LLONG_MAX, cb);
272d5b3afeaSAlistair Popple }
2730e2f80afSAlistair Popple void dax_break_layout_final(struct inode *inode);
2746f7db389SShiyang Ruan int dax_dedupe_file_range_compare(struct inode *src, loff_t srcoff,
2756f7db389SShiyang Ruan struct inode *dest, loff_t destoff,
2766f7db389SShiyang Ruan loff_t len, bool *is_same,
2776f7db389SShiyang Ruan const struct iomap_ops *ops);
2786f7db389SShiyang Ruan int dax_remap_file_range_prep(struct file *file_in, loff_t pos_in,
2796f7db389SShiyang Ruan struct file *file_out, loff_t pos_out,
2806f7db389SShiyang Ruan loff_t *len, unsigned int remap_flags,
2816f7db389SShiyang Ruan const struct iomap_ops *ops);
dax_mapping(struct address_space * mapping)282f9fe48beSRoss Zwisler static inline bool dax_mapping(struct address_space *mapping)
283f9fe48beSRoss Zwisler {
284f9fe48beSRoss Zwisler return mapping->host && IS_DAX(mapping->host);
285f9fe48beSRoss Zwisler }
2867f6d5b52SRoss Zwisler
2871ea7ca1bSJane Chu /*
2881ea7ca1bSJane Chu * Due to dax's memory and block duo personalities, hwpoison reporting
2891ea7ca1bSJane Chu * takes into consideration which personality is presently visible.
2901ea7ca1bSJane Chu * When dax acts like a block device, such as in block IO, an encounter of
2911ea7ca1bSJane Chu * dax hwpoison is reported as -EIO.
2921ea7ca1bSJane Chu * When dax acts like memory, such as in page fault, a detection of hwpoison
2931ea7ca1bSJane Chu * is reported as -EHWPOISON which leads to VM_FAULT_HWPOISON.
2941ea7ca1bSJane Chu */
dax_mem2blk_err(int err)2951ea7ca1bSJane Chu static inline int dax_mem2blk_err(int err)
2961ea7ca1bSJane Chu {
2971ea7ca1bSJane Chu return (err == -EHWPOISON) ? -EIO : err;
2981ea7ca1bSJane Chu }
2991ea7ca1bSJane Chu
300c01044ccSDan Williams #ifdef CONFIG_DEV_DAX_HMEM_DEVICES
3017dab174eSDan Williams void hmem_register_resource(int target_nid, struct resource *r);
302c01044ccSDan Williams #else
hmem_register_resource(int target_nid,struct resource * r)3037dab174eSDan Williams static inline void hmem_register_resource(int target_nid, struct resource *r)
304c01044ccSDan Williams {
305c01044ccSDan Williams }
306c01044ccSDan Williams #endif
307c01044ccSDan Williams
3087dab174eSDan Williams typedef int (*walk_hmem_fn)(struct device *dev, int target_nid,
3097dab174eSDan Williams const struct resource *res);
3107dab174eSDan Williams int walk_hmem_resources(struct device *dev, walk_hmem_fn fn);
311c94c2acfSMatthew Wilcox #endif
312