Commit a5135eea authored by Martin Brandenburg's avatar Martin Brandenburg Committed by Mike Marshall

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: default avatarMartin Brandenburg <martin@omnibond.com>
Signed-off-by: default avatarMike Marshall <hubcap@omnibond.com>
parent dbcb5e7f
...@@ -528,6 +528,28 @@ static long orangefs_ioctl(struct file *file, unsigned int cmd, unsigned long ar ...@@ -528,6 +528,28 @@ static long orangefs_ioctl(struct file *file, unsigned int cmd, unsigned long ar
return ret; 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. * Memory map a region of a file.
*/ */
...@@ -539,12 +561,16 @@ static int orangefs_file_mmap(struct file *file, struct vm_area_struct *vma) ...@@ -539,12 +561,16 @@ static int orangefs_file_mmap(struct file *file, struct vm_area_struct *vma)
(char *)file->f_path.dentry->d_name.name : (char *)file->f_path.dentry->d_name.name :
(char *)"Unknown")); (char *)"Unknown"));
if ((vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_MAYWRITE))
return -EINVAL;
/* set the sequential readahead hint */ /* set the sequential readahead hint */
vma->vm_flags |= VM_SEQ_READ; vma->vm_flags |= VM_SEQ_READ;
vma->vm_flags &= ~VM_RAND_READ; vma->vm_flags &= ~VM_RAND_READ;
/* Use readonly mmap since we cannot support writable maps. */ file_accessed(file);
return generic_file_readonly_mmap(file, vma); vma->vm_ops = &orangefs_file_vm_ops;
return 0;
} }
#define mapping_nrpages(idata) ((idata)->nrpages) #define mapping_nrpages(idata) ((idata)->nrpages)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment