Must retrieve size before running filemap_fault so the kernel has an up-to-date size. This should have been caught by xfstests generic/246, but it was masked by orangefs_new_inode, which set i_size to PAGE_SIZE. When nothing caused a getattr prior to a pagefault, i_size was still PAGE_SIZE. Since xfstests only read 10 bytes, it did not catch this bug. When orangefs_new_inode was modified to perform a getattr instead, i_size was set to zero, as it was a newly created file. Then orangefs_file_write_iter did NOT set i_size, instead prefering to invalidate the attribute cache and letting the next caller retrieve i_size. But the fault handler did not know it was supposed to retrieve i_size. So during xfstests, i_size was still zero, and filemap_fault returned VM_FAULT_SIGBUS. Fixes xfstests generic/080, generic/141, generic/215, generic/247, generic/248, generic/437, and generic/452. Signed-off-by: Martin Brandenburg <martin@xxxxxxxxxxxx> --- fs/orangefs/file.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/fs/orangefs/file.c b/fs/orangefs/file.c index 739b7b14bf68..f78a5902d5f7 100644 --- a/fs/orangefs/file.c +++ b/fs/orangefs/file.c @@ -527,6 +527,28 @@ static long orangefs_ioctl(struct file *file, unsigned int cmd, unsigned long ar return ret; } +static int orangefs_fault(struct vm_fault *vmf) +{ + struct file *file = vmf->vma->vm_file; + int rc; + rc = orangefs_inode_getattr(file->f_mapping->host, 0, 1, + STATX_SIZE); + if (rc == -ESTALE) + rc = -EIO; + if (rc) { + gossip_err("%s: orangefs_inode_getattr failed, " + "rc:%d:.\n", __func__, rc); + return rc; + } + return filemap_fault(vmf); +} + +const struct vm_operations_struct orangefs_file_vm_ops = { + .fault = orangefs_fault, + .map_pages = filemap_map_pages, + .page_mkwrite = filemap_page_mkwrite, +}; + /* * Memory map a region of a file. */ @@ -538,12 +560,16 @@ static int orangefs_file_mmap(struct file *file, struct vm_area_struct *vma) (char *)file->f_path.dentry->d_name.name : (char *)"Unknown")); + if ((vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_MAYWRITE)) + return -EINVAL; + /* set the sequential readahead hint */ vma->vm_flags |= VM_SEQ_READ; vma->vm_flags &= ~VM_RAND_READ; - /* Use readonly mmap since we cannot support writable maps. */ - return generic_file_readonly_mmap(file, vma); + file_accessed(file); + vma->vm_ops = &orangefs_file_vm_ops; + return 0; } #define mapping_nrpages(idata) ((idata)->nrpages) -- 2.16.2