From: John Groves <[email protected]> This commit adds vm_operations, plus famfs_mmap() and fault handlers. It is still missing iomap_ops, iomap mapping resolution, and famfs_ioctl() for setting up file-to-memory mappings.
Signed-off-by: John Groves <[email protected]> --- fs/famfs/famfs_file.c | 101 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 100 insertions(+), 1 deletion(-) diff --git a/fs/famfs/famfs_file.c b/fs/famfs/famfs_file.c index e192b573c51f..678f2035fd5f 100644 --- a/fs/famfs/famfs_file.c +++ b/fs/famfs/famfs_file.c @@ -16,6 +16,75 @@ #include "famfs_internal.h" +/********************************************************************* + * vm_operations + */ +static vm_fault_t +__famfs_filemap_fault(struct vm_fault *vmf, unsigned int order, + bool write_fault) +{ + struct inode *inode = file_inode(vmf->vma->vm_file); + struct super_block *sb = inode->i_sb; + struct famfs_fs_info *fsi = sb->s_fs_info; + vm_fault_t ret; + unsigned long pfn; + + if (fsi->deverror) + return VM_FAULT_SIGBUS; + + if (!IS_DAX(file_inode(vmf->vma->vm_file))) { + pr_err("%s: file not marked IS_DAX!!\n", __func__); + return VM_FAULT_SIGBUS; + } + + if (write_fault) { + sb_start_pagefault(inode->i_sb); + file_update_time(vmf->vma->vm_file); + } + + ret = dax_iomap_fault(vmf, order, &pfn, NULL, NULL /*&famfs_iomap_ops */); + if (ret & VM_FAULT_NEEDDSYNC) + ret = dax_finish_sync_fault(vmf, order, pfn); + + if (write_fault) + sb_end_pagefault(inode->i_sb); + + return ret; +} + +static inline bool +famfs_is_write_fault(struct vm_fault *vmf) +{ + return (vmf->flags & FAULT_FLAG_WRITE) && + (vmf->vma->vm_flags & VM_SHARED); +} + +static vm_fault_t +famfs_filemap_fault(struct vm_fault *vmf) +{ + return __famfs_filemap_fault(vmf, 0, famfs_is_write_fault(vmf)); +} + +static vm_fault_t +famfs_filemap_huge_fault(struct vm_fault *vmf, unsigned int order) +{ + return __famfs_filemap_fault(vmf, order, famfs_is_write_fault(vmf)); +} + +static vm_fault_t +famfs_filemap_mkwrite(struct vm_fault *vmf) +{ + return __famfs_filemap_fault(vmf, 0, true); +} + +const struct vm_operations_struct famfs_file_vm_ops = { + .fault = famfs_filemap_fault, + .huge_fault = famfs_filemap_huge_fault, + .map_pages = filemap_map_pages, + .page_mkwrite = famfs_filemap_mkwrite, + .pfn_mkwrite = famfs_filemap_mkwrite, +}; + /********************************************************************* * file_operations */ @@ -117,6 +186,36 @@ famfs_dax_write_iter(struct kiocb *iocb, struct iov_iter *from) return rc; } +static int +famfs_file_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct inode *inode = file_inode(file); + struct super_block *sb = inode->i_sb; + struct famfs_fs_info *fsi = sb->s_fs_info; + ssize_t rc; + + if (fsi->deverror) + return -ENODEV; + + /* + * Gate shared-writable mappings on FAMFS_OPT_WRITE. This is best + * effort: clearing the bit blocks new writable mappings and write(), + * but does not revoke mappings that already exist. + */ + if ((vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_WRITE) && + !famfs_opt_enabled(fsi, FAMFS_OPT_WRITE)) + return -EPERM; + + rc = famfs_file_invalid(inode); + if (rc) + return (int)rc; + + file_accessed(file); + vma->vm_ops = &famfs_file_vm_ops; + vm_flags_set(vma, VM_HUGEPAGE); + return 0; +} + const struct file_operations famfs_file_operations = { .owner = THIS_MODULE, @@ -124,7 +223,7 @@ const struct file_operations famfs_file_operations = { .write_iter = famfs_dax_write_iter, .read_iter = famfs_dax_read_iter, .unlocked_ioctl = NULL /*famfs_file_ioctl*/, - .mmap = NULL /* famfs_file_mmap */, + .mmap = famfs_file_mmap, /* Force PMD alignment for mmap */ .get_unmapped_area = thp_get_unmapped_area, -- 2.53.0

