aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2015-02-23 05:45:32 -0500
committerDave Chinner <david@fromorbit.com>2015-02-23 05:45:32 -0500
commite8e9ad42c1f1e1bfbe0e8c32c8cac02e9ebfb7ef (patch)
treefe0f154df85bb57c24295f9ac06555be83c7c50c /fs/xfs
parent075a924d45cc69c75a35f20b4912b85aa98b180a (diff)
xfs: take i_mmap_lock on extent manipulation operations
Now we have the i_mmap_lock being held across the page fault IO path, we now add extent manipulation operation exclusion by adding the lock to the paths that directly modify extent maps. This includes truncate, hole punching and other fallocate based operations. The operations will now take both the i_iolock and the i_mmaplock in exclusive mode, thereby ensuring that all IO and page faults block without holding any page locks while the extent manipulation is in progress. This gives us the lock order during truncate of i_iolock -> i_mmaplock -> page_lock -> i_lock, hence providing the same lock order as the iolock provides the normal IO path without involving the mmap_sem. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Brian Foster <bfoster@redhat.com> Signed-off-by: Dave Chinner <david@fromorbit.com>
Diffstat (limited to 'fs/xfs')
-rw-r--r--fs/xfs/xfs_file.c3
-rw-r--r--fs/xfs/xfs_ioctl.c5
-rw-r--r--fs/xfs/xfs_iops.c7
3 files changed, 13 insertions, 2 deletions
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index d55f011401bf..609b5aaddd8e 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -841,6 +841,9 @@ xfs_file_fallocate(
841 if (error) 841 if (error)
842 goto out_unlock; 842 goto out_unlock;
843 843
844 xfs_ilock(ip, XFS_MMAPLOCK_EXCL);
845 iolock |= XFS_MMAPLOCK_EXCL;
846
844 if (mode & FALLOC_FL_PUNCH_HOLE) { 847 if (mode & FALLOC_FL_PUNCH_HOLE) {
845 error = xfs_free_file_space(ip, offset, len); 848 error = xfs_free_file_space(ip, offset, len);
846 if (error) 849 if (error)
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index ac4feae45eb3..4ee44ddfdfb7 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -631,7 +631,7 @@ xfs_ioc_space(
631 631
632 if (filp->f_flags & O_DSYNC) 632 if (filp->f_flags & O_DSYNC)
633 flags |= XFS_PREALLOC_SYNC; 633 flags |= XFS_PREALLOC_SYNC;
634 if (ioflags & XFS_IO_INVIS) 634 if (ioflags & XFS_IO_INVIS)
635 flags |= XFS_PREALLOC_INVISIBLE; 635 flags |= XFS_PREALLOC_INVISIBLE;
636 636
637 error = mnt_want_write_file(filp); 637 error = mnt_want_write_file(filp);
@@ -643,6 +643,9 @@ xfs_ioc_space(
643 if (error) 643 if (error)
644 goto out_unlock; 644 goto out_unlock;
645 645
646 xfs_ilock(ip, XFS_MMAPLOCK_EXCL);
647 iolock |= XFS_MMAPLOCK_EXCL;
648
646 switch (bf->l_whence) { 649 switch (bf->l_whence) {
647 case 0: /*SEEK_SET*/ 650 case 0: /*SEEK_SET*/
648 break; 651 break;
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index d919ad7b16bf..7f59ad34b5c5 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -765,6 +765,7 @@ xfs_setattr_size(
765 return error; 765 return error;
766 766
767 ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL)); 767 ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL));
768 ASSERT(xfs_isilocked(ip, XFS_MMAPLOCK_EXCL));
768 ASSERT(S_ISREG(ip->i_d.di_mode)); 769 ASSERT(S_ISREG(ip->i_d.di_mode));
769 ASSERT((iattr->ia_valid & (ATTR_UID|ATTR_GID|ATTR_ATIME|ATTR_ATIME_SET| 770 ASSERT((iattr->ia_valid & (ATTR_UID|ATTR_GID|ATTR_ATIME|ATTR_ATIME_SET|
770 ATTR_MTIME_SET|ATTR_KILL_PRIV|ATTR_TIMES_SET)) == 0); 771 ATTR_MTIME_SET|ATTR_KILL_PRIV|ATTR_TIMES_SET)) == 0);
@@ -984,8 +985,12 @@ xfs_vn_setattr(
984 985
985 xfs_ilock(ip, iolock); 986 xfs_ilock(ip, iolock);
986 error = xfs_break_layouts(dentry->d_inode, &iolock); 987 error = xfs_break_layouts(dentry->d_inode, &iolock);
987 if (!error) 988 if (!error) {
989 xfs_ilock(ip, XFS_MMAPLOCK_EXCL);
990 iolock |= XFS_MMAPLOCK_EXCL;
991
988 error = xfs_setattr_size(ip, iattr); 992 error = xfs_setattr_size(ip, iattr);
993 }
989 xfs_iunlock(ip, iolock); 994 xfs_iunlock(ip, iolock);
990 } else { 995 } else {
991 error = xfs_setattr_nonsize(ip, iattr, 0); 996 error = xfs_setattr_nonsize(ip, iattr, 0);