]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
xfs: take i_mmap_lock on extent manipulation operations
authorDave Chinner <dchinner@redhat.com>
Mon, 23 Feb 2015 10:45:32 +0000 (21:45 +1100)
committerBen Hutchings <ben@decadent.org.uk>
Wed, 15 Jun 2016 20:29:33 +0000 (21:29 +0100)
commit e8e9ad42c1f1e1bfbe0e8c32c8cac02e9ebfb7ef upstream.

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>
[bwh: Backported to 3.16:
 - We never need to break layouts, so take both i_iolock and i_mmaplock at the
   same time
 - Adjust context]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Cc: Jan Kara <jack@suse.cz>
Cc: xfs@oss.sgi.com
fs/xfs/xfs_file.c
fs/xfs/xfs_ioctl.c
fs/xfs/xfs_iops.c

index e9ae58e33c6cfe9964cf94c625dde7b4af783844..975aaac7494e4969217d9b98bd4ae49afa6c8af4 100644 (file)
@@ -786,7 +786,7 @@ xfs_file_fallocate(
                     FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_ZERO_RANGE))
                return -EOPNOTSUPP;
 
-       xfs_ilock(ip, XFS_IOLOCK_EXCL);
+       xfs_ilock(ip, XFS_IOLOCK_EXCL | XFS_MMAPLOCK_EXCL);
        if (mode & FALLOC_FL_PUNCH_HOLE) {
                error = xfs_free_file_space(ip, offset, len);
                if (error)
@@ -866,7 +866,7 @@ xfs_file_fallocate(
        }
 
 out_unlock:
-       xfs_iunlock(ip, XFS_IOLOCK_EXCL);
+       xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_MMAPLOCK_EXCL);
        return -error;
 }
 
index 8bc1bbce74517c95675dc661412e946e456fedbe..afc859f44d013b83711f74859643b36fe8663bd0 100644 (file)
@@ -640,7 +640,7 @@ xfs_ioc_space(
        if (error)
                return error;
 
-       xfs_ilock(ip, XFS_IOLOCK_EXCL);
+       xfs_ilock(ip, XFS_IOLOCK_EXCL | XFS_MMAPLOCK_EXCL);
 
        switch (bf->l_whence) {
        case 0: /*SEEK_SET*/
@@ -757,7 +757,7 @@ xfs_ioc_space(
        error = xfs_trans_commit(tp, 0);
 
 out_unlock:
-       xfs_iunlock(ip, XFS_IOLOCK_EXCL);
+       xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_MMAPLOCK_EXCL);
        mnt_drop_write_file(filp);
        return -error;
 }
index 537d8daeaa9ef0a8cdc3db6f56d23c50778510c5..1d392bbb2c9f16c217e9dba9855558e3564d578c 100644 (file)
@@ -759,6 +759,7 @@ xfs_setattr_size(
                return XFS_ERROR(error);
 
        ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL));
+       ASSERT(xfs_isilocked(ip, XFS_MMAPLOCK_EXCL));
        ASSERT(S_ISREG(ip->i_d.di_mode));
        ASSERT((iattr->ia_valid & (ATTR_UID|ATTR_GID|ATTR_ATIME|ATTR_ATIME_SET|
                ATTR_MTIME_SET|ATTR_KILL_PRIV|ATTR_TIMES_SET)) == 0);
@@ -935,9 +936,9 @@ xfs_vn_setattr(
        int                     error;
 
        if (iattr->ia_valid & ATTR_SIZE) {
-               xfs_ilock(ip, XFS_IOLOCK_EXCL);
+               xfs_ilock(ip, XFS_IOLOCK_EXCL | XFS_MMAPLOCK_EXCL);
                error = xfs_setattr_size(ip, iattr);
-               xfs_iunlock(ip, XFS_IOLOCK_EXCL);
+               xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_MMAPLOCK_EXCL);
        } else {
                error = xfs_setattr_nonsize(ip, iattr, 0);
        }