diff options
author | Dave Chinner <dchinner@redhat.com> | 2015-11-02 20:37:02 -0500 |
---|---|---|
committer | Dave Chinner <david@fromorbit.com> | 2015-11-02 20:37:02 -0500 |
commit | 3af49285854df66260a263198cc15abb07b95287 (patch) | |
tree | 36cf3d76bccae803a58886953be4709454a16838 | |
parent | 01a155e6cf7db1a8ff2aa73162d7d9ec05ad298f (diff) |
xfs: add ->pfn_mkwrite support for DAX
->pfn_mkwrite support is needed so that when a page with allocated
backing store takes a write fault we can check that the fault has
not raced with a truncate and is pointing to a region beyond the
current end of file.
This also allows us to update the timestamp on the inode, too, which
fixes a generic/080 failure.
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Signed-off-by: Dave Chinner <david@fromorbit.com>
-rw-r--r-- | fs/xfs/xfs_file.c | 35 | ||||
-rw-r--r-- | fs/xfs/xfs_trace.h | 1 |
2 files changed, 36 insertions, 0 deletions
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index 9c8eef7c57b4..f429662d7d42 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c | |||
@@ -1572,11 +1572,46 @@ xfs_filemap_pmd_fault( | |||
1572 | return ret; | 1572 | return ret; |
1573 | } | 1573 | } |
1574 | 1574 | ||
1575 | /* | ||
1576 | * pfn_mkwrite was originally inteneded to ensure we capture time stamp | ||
1577 | * updates on write faults. In reality, it's need to serialise against | ||
1578 | * truncate similar to page_mkwrite. Hence we open-code dax_pfn_mkwrite() | ||
1579 | * here and cycle the XFS_MMAPLOCK_SHARED to ensure we serialise the fault | ||
1580 | * barrier in place. | ||
1581 | */ | ||
1582 | static int | ||
1583 | xfs_filemap_pfn_mkwrite( | ||
1584 | struct vm_area_struct *vma, | ||
1585 | struct vm_fault *vmf) | ||
1586 | { | ||
1587 | |||
1588 | struct inode *inode = file_inode(vma->vm_file); | ||
1589 | struct xfs_inode *ip = XFS_I(inode); | ||
1590 | int ret = VM_FAULT_NOPAGE; | ||
1591 | loff_t size; | ||
1592 | |||
1593 | trace_xfs_filemap_pfn_mkwrite(ip); | ||
1594 | |||
1595 | sb_start_pagefault(inode->i_sb); | ||
1596 | file_update_time(vma->vm_file); | ||
1597 | |||
1598 | /* check if the faulting page hasn't raced with truncate */ | ||
1599 | xfs_ilock(ip, XFS_MMAPLOCK_SHARED); | ||
1600 | size = (i_size_read(inode) + PAGE_SIZE - 1) >> PAGE_SHIFT; | ||
1601 | if (vmf->pgoff >= size) | ||
1602 | ret = VM_FAULT_SIGBUS; | ||
1603 | xfs_iunlock(ip, XFS_MMAPLOCK_SHARED); | ||
1604 | sb_end_pagefault(inode->i_sb); | ||
1605 | return ret; | ||
1606 | |||
1607 | } | ||
1608 | |||
1575 | static const struct vm_operations_struct xfs_file_vm_ops = { | 1609 | static const struct vm_operations_struct xfs_file_vm_ops = { |
1576 | .fault = xfs_filemap_fault, | 1610 | .fault = xfs_filemap_fault, |
1577 | .pmd_fault = xfs_filemap_pmd_fault, | 1611 | .pmd_fault = xfs_filemap_pmd_fault, |
1578 | .map_pages = filemap_map_pages, | 1612 | .map_pages = filemap_map_pages, |
1579 | .page_mkwrite = xfs_filemap_page_mkwrite, | 1613 | .page_mkwrite = xfs_filemap_page_mkwrite, |
1614 | .pfn_mkwrite = xfs_filemap_pfn_mkwrite, | ||
1580 | }; | 1615 | }; |
1581 | 1616 | ||
1582 | STATIC int | 1617 | STATIC int |
diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h index 5ed36b1e04c1..c53beda675d6 100644 --- a/fs/xfs/xfs_trace.h +++ b/fs/xfs/xfs_trace.h | |||
@@ -689,6 +689,7 @@ DEFINE_INODE_EVENT(xfs_inode_free_eofblocks_invalid); | |||
689 | DEFINE_INODE_EVENT(xfs_filemap_fault); | 689 | DEFINE_INODE_EVENT(xfs_filemap_fault); |
690 | DEFINE_INODE_EVENT(xfs_filemap_pmd_fault); | 690 | DEFINE_INODE_EVENT(xfs_filemap_pmd_fault); |
691 | DEFINE_INODE_EVENT(xfs_filemap_page_mkwrite); | 691 | DEFINE_INODE_EVENT(xfs_filemap_page_mkwrite); |
692 | DEFINE_INODE_EVENT(xfs_filemap_pfn_mkwrite); | ||
692 | 693 | ||
693 | DECLARE_EVENT_CLASS(xfs_iref_class, | 694 | DECLARE_EVENT_CLASS(xfs_iref_class, |
694 | TP_PROTO(struct xfs_inode *ip, unsigned long caller_ip), | 695 | TP_PROTO(struct xfs_inode *ip, unsigned long caller_ip), |