aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Brandenburg <martin@omnibond.com>2018-04-03 12:27:12 -0400
committerMike Marshall <hubcap@omnibond.com>2018-04-03 21:55:27 -0400
commita5135eeab2e5ca1b94f34dcb772cb30f9f390efc (patch)
treeb0dfd6a088635db87a807a8dbecdce12e93aaca8
parentdbcb5e7fc470c9daec9cb4ae463670f2047163e3 (diff)
orangefs: implement vm_ops->fault
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 it invalidated the attribute cache, which should have caused the next caller to 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/452. Signed-off-by: Martin Brandenburg <martin@omnibond.com> Signed-off-by: Mike Marshall <hubcap@omnibond.com>
-rw-r--r--fs/orangefs/file.c30
1 files changed, 28 insertions, 2 deletions
diff --git a/fs/orangefs/file.c b/fs/orangefs/file.c
index 3a7319a1bfdb..26358efbf794 100644
--- a/fs/orangefs/file.c
+++ b/fs/orangefs/file.c
@@ -528,6 +528,28 @@ static long orangefs_ioctl(struct file *file, unsigned int cmd, unsigned long ar
528 return ret; 528 return ret;
529} 529}
530 530
531static int orangefs_fault(struct vm_fault *vmf)
532{
533 struct file *file = vmf->vma->vm_file;
534 int rc;
535 rc = orangefs_inode_getattr(file->f_mapping->host, 0, 1,
536 STATX_SIZE);
537 if (rc == -ESTALE)
538 rc = -EIO;
539 if (rc) {
540 gossip_err("%s: orangefs_inode_getattr failed, "
541 "rc:%d:.\n", __func__, rc);
542 return rc;
543 }
544 return filemap_fault(vmf);
545}
546
547const struct vm_operations_struct orangefs_file_vm_ops = {
548 .fault = orangefs_fault,
549 .map_pages = filemap_map_pages,
550 .page_mkwrite = filemap_page_mkwrite,
551};
552
531/* 553/*
532 * Memory map a region of a file. 554 * Memory map a region of a file.
533 */ 555 */
@@ -539,12 +561,16 @@ static int orangefs_file_mmap(struct file *file, struct vm_area_struct *vma)
539 (char *)file->f_path.dentry->d_name.name : 561 (char *)file->f_path.dentry->d_name.name :
540 (char *)"Unknown")); 562 (char *)"Unknown"));
541 563
564 if ((vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_MAYWRITE))
565 return -EINVAL;
566
542 /* set the sequential readahead hint */ 567 /* set the sequential readahead hint */
543 vma->vm_flags |= VM_SEQ_READ; 568 vma->vm_flags |= VM_SEQ_READ;
544 vma->vm_flags &= ~VM_RAND_READ; 569 vma->vm_flags &= ~VM_RAND_READ;
545 570
546 /* Use readonly mmap since we cannot support writable maps. */ 571 file_accessed(file);
547 return generic_file_readonly_mmap(file, vma); 572 vma->vm_ops = &orangefs_file_vm_ops;
573 return 0;
548} 574}
549 575
550#define mapping_nrpages(idata) ((idata)->nrpages) 576#define mapping_nrpages(idata) ((idata)->nrpages)