mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-04 17:44:14 +08:00
xfs: lock out page faults from extent swap operations
Extent swap operations are another extent manipulation operation that we need to ensure does not race against mmap page faults. The current code returns if the file is mapped prior to the swap being done, but it could potentially race against new page faults while the swap is in progress. Hence we should use the XFS_MMAPLOCK_EXCL for this operation, too. While there, fix the error path handling that can result in double unlocks of the inodes when cancelling the swapext transaction. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Brian Foster <bfoster@redhat.com> Signed-off-by: Dave Chinner <david@fromorbit.com>
This commit is contained in:
parent
0f9160b444
commit
723cac4847
@ -1599,13 +1599,6 @@ xfs_swap_extent_flush(
|
||||
/* Verify O_DIRECT for ftmp */
|
||||
if (VFS_I(ip)->i_mapping->nrpages)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Don't try to swap extents on mmap()d files because we can't lock
|
||||
* out races against page faults safely.
|
||||
*/
|
||||
if (mapping_mapped(VFS_I(ip)->i_mapping))
|
||||
return -EBUSY;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1633,13 +1626,14 @@ xfs_swap_extents(
|
||||
}
|
||||
|
||||
/*
|
||||
* Lock up the inodes against other IO and truncate to begin with.
|
||||
* Then we can ensure the inodes are flushed and have no page cache
|
||||
* safely. Once we have done this we can take the ilocks and do the rest
|
||||
* of the checks.
|
||||
* Lock the inodes against other IO, page faults and truncate to
|
||||
* begin with. Then we can ensure the inodes are flushed and have no
|
||||
* page cache safely. Once we have done this we can take the ilocks and
|
||||
* do the rest of the checks.
|
||||
*/
|
||||
lock_flags = XFS_IOLOCK_EXCL;
|
||||
lock_flags = XFS_IOLOCK_EXCL | XFS_MMAPLOCK_EXCL;
|
||||
xfs_lock_two_inodes(ip, tip, XFS_IOLOCK_EXCL);
|
||||
xfs_lock_two_inodes(ip, tip, XFS_MMAPLOCK_EXCL);
|
||||
|
||||
/* Verify that both files have the same format */
|
||||
if ((ip->i_d.di_mode & S_IFMT) != (tip->i_d.di_mode & S_IFMT)) {
|
||||
@ -1666,8 +1660,16 @@ xfs_swap_extents(
|
||||
xfs_trans_cancel(tp, 0);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
/*
|
||||
* Lock and join the inodes to the tansaction so that transaction commit
|
||||
* or cancel will unlock the inodes from this point onwards.
|
||||
*/
|
||||
xfs_lock_two_inodes(ip, tip, XFS_ILOCK_EXCL);
|
||||
lock_flags |= XFS_ILOCK_EXCL;
|
||||
xfs_trans_ijoin(tp, ip, lock_flags);
|
||||
xfs_trans_ijoin(tp, tip, lock_flags);
|
||||
|
||||
|
||||
/* Verify all data are being swapped */
|
||||
if (sxp->sx_offset != 0 ||
|
||||
@ -1720,9 +1722,6 @@ xfs_swap_extents(
|
||||
goto out_trans_cancel;
|
||||
}
|
||||
|
||||
xfs_trans_ijoin(tp, ip, lock_flags);
|
||||
xfs_trans_ijoin(tp, tip, lock_flags);
|
||||
|
||||
/*
|
||||
* Before we've swapped the forks, lets set the owners of the forks
|
||||
* appropriately. We have to do this as we are demand paging the btree
|
||||
@ -1856,5 +1855,5 @@ out_unlock:
|
||||
|
||||
out_trans_cancel:
|
||||
xfs_trans_cancel(tp, 0);
|
||||
goto out_unlock;
|
||||
goto out;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user