diff options
Diffstat (limited to 'fs/xfs/xfs_file.c')
-rw-r--r-- | fs/xfs/xfs_file.c | 141 |
1 files changed, 76 insertions, 65 deletions
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index b240ea5241dc..4cdc54dc9686 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c @@ -213,29 +213,18 @@ xfs_ilock_iocb_for_write( if (ret) return ret; - if (*lock_mode == XFS_IOLOCK_EXCL) - return 0; - if (!xfs_iflags_test(ip, XFS_IREMAPPING)) - return 0; - - xfs_iunlock(ip, *lock_mode); - *lock_mode = XFS_IOLOCK_EXCL; - return xfs_ilock_iocb(iocb, *lock_mode); -} - -static unsigned int -xfs_ilock_for_write_fault( - struct xfs_inode *ip) -{ - /* get a shared lock if no remapping in progress */ - xfs_ilock(ip, XFS_MMAPLOCK_SHARED); - if (!xfs_iflags_test(ip, XFS_IREMAPPING)) - return XFS_MMAPLOCK_SHARED; + /* + * If a reflink remap is in progress we always need to take the iolock + * exclusively to wait for it to finish. + */ + if (*lock_mode == XFS_IOLOCK_SHARED && + xfs_iflags_test(ip, XFS_IREMAPPING)) { + xfs_iunlock(ip, *lock_mode); + *lock_mode = XFS_IOLOCK_EXCL; + return xfs_ilock_iocb(iocb, *lock_mode); + } - /* wait for remapping to complete */ - xfs_iunlock(ip, XFS_MMAPLOCK_SHARED); - xfs_ilock(ip, XFS_MMAPLOCK_EXCL); - return XFS_MMAPLOCK_EXCL; + return 0; } STATIC ssize_t @@ -1247,31 +1236,77 @@ xfs_file_llseek( return vfs_setpos(file, offset, inode->i_sb->s_maxbytes); } -#ifdef CONFIG_FS_DAX static inline vm_fault_t -xfs_dax_fault( +xfs_dax_fault_locked( struct vm_fault *vmf, unsigned int order, - bool write_fault, - pfn_t *pfn) + bool write_fault) { - return dax_iomap_fault(vmf, order, pfn, NULL, + vm_fault_t ret; + pfn_t pfn; + + if (!IS_ENABLED(CONFIG_FS_DAX)) { + ASSERT(0); + return VM_FAULT_SIGBUS; + } + ret = dax_iomap_fault(vmf, order, &pfn, NULL, (write_fault && !vmf->cow_page) ? &xfs_dax_write_iomap_ops : &xfs_read_iomap_ops); + if (ret & VM_FAULT_NEEDDSYNC) + ret = dax_finish_sync_fault(vmf, order, pfn); + return ret; } -#else -static inline vm_fault_t -xfs_dax_fault( + +static vm_fault_t +xfs_dax_read_fault( struct vm_fault *vmf, - unsigned int order, - bool write_fault, - pfn_t *pfn) + unsigned int order) { - ASSERT(0); - return VM_FAULT_SIGBUS; + struct xfs_inode *ip = XFS_I(file_inode(vmf->vma->vm_file)); + vm_fault_t ret; + + xfs_ilock(ip, XFS_MMAPLOCK_SHARED); + ret = xfs_dax_fault_locked(vmf, order, false); + xfs_iunlock(ip, XFS_MMAPLOCK_SHARED); + + return ret; +} + +static vm_fault_t +xfs_write_fault( + struct vm_fault *vmf, + unsigned int order) +{ + struct inode *inode = file_inode(vmf->vma->vm_file); + struct xfs_inode *ip = XFS_I(inode); + unsigned int lock_mode = XFS_MMAPLOCK_SHARED; + vm_fault_t ret; + + sb_start_pagefault(inode->i_sb); + file_update_time(vmf->vma->vm_file); + + /* + * Normally we only need the shared mmaplock, but if a reflink remap is + * in progress we take the exclusive lock to wait for the remap to + * finish before taking a write fault. + */ + xfs_ilock(ip, XFS_MMAPLOCK_SHARED); + if (xfs_iflags_test(ip, XFS_IREMAPPING)) { + xfs_iunlock(ip, XFS_MMAPLOCK_SHARED); + xfs_ilock(ip, XFS_MMAPLOCK_EXCL); + lock_mode = XFS_MMAPLOCK_EXCL; + } + + if (IS_DAX(inode)) + ret = xfs_dax_fault_locked(vmf, order, true); + else + ret = iomap_page_mkwrite(vmf, &xfs_page_mkwrite_iomap_ops); + xfs_iunlock(ip, lock_mode); + + sb_end_pagefault(inode->i_sb); + return ret; } -#endif /* * Locking for serialisation of IO during page faults. This results in a lock @@ -1290,38 +1325,14 @@ __xfs_filemap_fault( bool write_fault) { struct inode *inode = file_inode(vmf->vma->vm_file); - struct xfs_inode *ip = XFS_I(inode); - vm_fault_t ret; - unsigned int lock_mode = 0; - - trace_xfs_filemap_fault(ip, order, write_fault); - - if (write_fault) { - sb_start_pagefault(inode->i_sb); - file_update_time(vmf->vma->vm_file); - } - - if (IS_DAX(inode) || write_fault) - lock_mode = xfs_ilock_for_write_fault(XFS_I(inode)); - if (IS_DAX(inode)) { - pfn_t pfn; - - ret = xfs_dax_fault(vmf, order, write_fault, &pfn); - if (ret & VM_FAULT_NEEDDSYNC) - ret = dax_finish_sync_fault(vmf, order, pfn); - } else if (write_fault) { - ret = iomap_page_mkwrite(vmf, &xfs_page_mkwrite_iomap_ops); - } else { - ret = filemap_fault(vmf); - } - - if (lock_mode) - xfs_iunlock(XFS_I(inode), lock_mode); + trace_xfs_filemap_fault(XFS_I(inode), order, write_fault); if (write_fault) - sb_end_pagefault(inode->i_sb); - return ret; + return xfs_write_fault(vmf, order); + if (IS_DAX(inode)) + return xfs_dax_read_fault(vmf, order); + return filemap_fault(vmf); } static inline bool |