virtiofs: add DAX mmap support
authorStefan Hajnoczi <stefanha@redhat.com>
Wed, 19 Aug 2020 22:19:52 +0000 (18:19 -0400)
committerMiklos Szeredi <mszeredi@redhat.com>
Thu, 10 Sep 2020 09:39:23 +0000 (11:39 +0200)
Add DAX mmap() support.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
fs/fuse/dax.c
fs/fuse/file.c

index a8d311b..b8ec7d6 100644 (file)
@@ -575,6 +575,65 @@ out:
        return ret;
 }
 
+static vm_fault_t __fuse_dax_fault(struct vm_fault *vmf,
+                                  enum page_entry_size pe_size, bool write)
+{
+       vm_fault_t ret;
+       struct inode *inode = file_inode(vmf->vma->vm_file);
+       struct super_block *sb = inode->i_sb;
+       pfn_t pfn;
+
+       if (write)
+               sb_start_pagefault(sb);
+
+       ret = dax_iomap_fault(vmf, pe_size, &pfn, NULL, &fuse_iomap_ops);
+
+       if (ret & VM_FAULT_NEEDDSYNC)
+               ret = dax_finish_sync_fault(vmf, pe_size, pfn);
+
+       if (write)
+               sb_end_pagefault(sb);
+
+       return ret;
+}
+
+static vm_fault_t fuse_dax_fault(struct vm_fault *vmf)
+{
+       return __fuse_dax_fault(vmf, PE_SIZE_PTE,
+                               vmf->flags & FAULT_FLAG_WRITE);
+}
+
+static vm_fault_t fuse_dax_huge_fault(struct vm_fault *vmf,
+                              enum page_entry_size pe_size)
+{
+       return __fuse_dax_fault(vmf, pe_size, vmf->flags & FAULT_FLAG_WRITE);
+}
+
+static vm_fault_t fuse_dax_page_mkwrite(struct vm_fault *vmf)
+{
+       return __fuse_dax_fault(vmf, PE_SIZE_PTE, true);
+}
+
+static vm_fault_t fuse_dax_pfn_mkwrite(struct vm_fault *vmf)
+{
+       return __fuse_dax_fault(vmf, PE_SIZE_PTE, true);
+}
+
+static const struct vm_operations_struct fuse_dax_vm_ops = {
+       .fault          = fuse_dax_fault,
+       .huge_fault     = fuse_dax_huge_fault,
+       .page_mkwrite   = fuse_dax_page_mkwrite,
+       .pfn_mkwrite    = fuse_dax_pfn_mkwrite,
+};
+
+int fuse_dax_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       file_accessed(file);
+       vma->vm_ops = &fuse_dax_vm_ops;
+       vma->vm_flags |= VM_MIXEDMAP | VM_HUGEPAGE;
+       return 0;
+}
+
 static void fuse_free_dax_mem_ranges(struct list_head *mem_list)
 {
        struct fuse_dax_mapping *range, *temp;
index 6c586bc..2aac787 100644 (file)
@@ -2325,6 +2325,10 @@ static int fuse_file_mmap(struct file *file, struct vm_area_struct *vma)
 {
        struct fuse_file *ff = file->private_data;
 
+       /* DAX mmap is superior to direct_io mmap */
+       if (FUSE_IS_DAX(file_inode(file)))
+               return fuse_dax_mmap(file, vma);
+
        if (ff->open_flags & FOPEN_DIRECT_IO) {
                /* Can't provide the coherency needed for MAP_SHARED */
                if (vma->vm_flags & VM_MAYSHARE)
@@ -3413,6 +3417,7 @@ static const struct file_operations fuse_file_operations = {
        .release        = fuse_release,
        .fsync          = fuse_fsync,
        .lock           = fuse_file_lock,
+       .get_unmapped_area = thp_get_unmapped_area,
        .flock          = fuse_file_flock,
        .splice_read    = generic_file_splice_read,
        .splice_write   = iter_file_splice_write,