@@ -27,6 +27,29 @@
#include <linux/uio.h>
#include <linux/vmstat.h>
+/*
+ * flush the mapping to the persistent domain within the byte range of (start,
+ * end). This is required by data integrity operations to ensure file data is on
+ * persistent storage prior to completion of the operation. It also requires us
+ * to clean the mappings (i.e. write -> RO) so that we'll get a new fault when
+ * the file is written to again so wehave an indication that we need to flush
+ * the mapping if a data integrity operation takes place.
+ *
+ * We don't need commits to storage here - the filesystems will issue flushes
+ * appropriately at the conclusion of the data integrity operation via REQ_FUA
+ * writes or blkdev_issue_flush() commands. This requires the DAX block device
+ * to implement persistent storage domain fencing/commits on receiving a
+ * REQ_FLUSH or REQ_FUA request so that this works as expected by the higher
+ * layers.
+ */
+int dax_flush_mapping(struct address_space *mapping, loff_t start, loff_t end)
+{
+ /* XXX: make ptes in range clean */
+
+ /* XXX: flush CPU caches */
+ return 0;
+}
+
int dax_clear_blocks(struct inode *inode, sector_t block, long size)
{
struct block_device *bdev = inode->i_sb->s_bdev;
@@ -472,8 +495,10 @@ int dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf,
file_update_time(vma->vm_file);
}
result = __dax_fault(vma, vmf, get_block, complete_unwritten);
- if (vmf->flags & FAULT_FLAG_WRITE)
+ if (vmf->flags & FAULT_FLAG_WRITE) {
+ __mark_inode_dirty(file_inode(vma->vm_file, I_DIRTY_PAGES);
sb_end_pagefault(sb);
+ }
return result;
}
@@ -1453,6 +1453,8 @@ xfs_filemap_page_mkwrite(
}
xfs_iunlock(XFS_I(inode), XFS_MMAPLOCK_SHARED);
+ if (IS_DAX(inode))
+ __mark_inode_dirty(file_inode(vma->vm_file, I_DIRTY_PAGES);
sb_end_pagefault(inode->i_sb);
return ret;
@@ -2029,6 +2029,11 @@ int do_writepages(struct address_space *mapping, struct writeback_control *wbc)
if (wbc->nr_to_write <= 0)
return 0;
+
+ if (wbc->sync == WB_SYNC_ALL && IS_DAX(mapping->host))
+ return dax_flush_mapping(mapping, wbc->range_start,
+ wbc->range_end);
+
if (mapping->a_ops->writepages)
ret = mapping->a_ops->writepages(mapping, wbc);
else