]> asedeno.scripts.mit.edu Git - linux.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)
committerDave Chinner <david@fromorbit.com>
Mon, 23 Feb 2015 10:45:32 +0000 (21:45 +1100)
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>
fs/xfs/xfs_file.c
fs/xfs/xfs_ioctl.c
fs/xfs/xfs_iops.c

index d55f011401bfbcc65b4c94e6483ff788cc6426bd..609b5aaddd8e52cd5b6e4c52f8f227f82d7bcf32 100644 (file)
@@ -841,6 +841,9 @@ xfs_file_fallocate(
        if (error)
                goto out_unlock;
 
+       xfs_ilock(ip, XFS_MMAPLOCK_EXCL);
+       iolock |= XFS_MMAPLOCK_EXCL;
+
        if (mode & FALLOC_FL_PUNCH_HOLE) {
                error = xfs_free_file_space(ip, offset, len);
                if (error)
index ac4feae45eb308c39629f177c0b6620fae77fb69..4ee44ddfdfb766738ff33fd35375e4eb87a4dba0 100644 (file)
@@ -631,7 +631,7 @@ xfs_ioc_space(
 
        if (filp->f_flags & O_DSYNC)
                flags |= XFS_PREALLOC_SYNC;
-       if (ioflags & XFS_IO_INVIS)     
+       if (ioflags & XFS_IO_INVIS)
                flags |= XFS_PREALLOC_INVISIBLE;
 
        error = mnt_want_write_file(filp);
@@ -643,6 +643,9 @@ xfs_ioc_space(
        if (error)
                goto out_unlock;
 
+       xfs_ilock(ip, XFS_MMAPLOCK_EXCL);
+       iolock |= XFS_MMAPLOCK_EXCL;
+
        switch (bf->l_whence) {
        case 0: /*SEEK_SET*/
                break;
index d919ad7b16bf9acbe01c6531a9254b372426911a..7f59ad34b5c5c48fedd9c3919fb2a401a070f56d 100644 (file)
@@ -765,6 +765,7 @@ xfs_setattr_size(
                return 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);
@@ -984,8 +985,12 @@ xfs_vn_setattr(
 
                xfs_ilock(ip, iolock);
                error = xfs_break_layouts(dentry->d_inode, &iolock);
-               if (!error)
+               if (!error) {
+                       xfs_ilock(ip, XFS_MMAPLOCK_EXCL);
+                       iolock |= XFS_MMAPLOCK_EXCL;
+
                        error = xfs_setattr_size(ip, iattr);
+               }
                xfs_iunlock(ip, iolock);
        } else {
                error = xfs_setattr_nonsize(ip, iattr, 0);