xfs: refactor locking and unlocking two inodes against userspace IO

Refactor the two functions that we use to lock and unlock two inodes to
block userspace from initiating IO against a file, whether via system
calls or mmap activity.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
This commit is contained in:
Darrick J. Wong 2020-06-29 14:47:20 -07:00
parent 451d34ee07
commit 10b4bd6c9c
3 changed files with 34 additions and 23 deletions

View file

@ -1065,7 +1065,7 @@ xfs_file_remap_range(
if (mp->m_flags & XFS_MOUNT_WSYNC)
xfs_log_force_inode(dest);
out_unlock:
xfs_reflink_remap_unlock(file_in, file_out);
xfs_reflink_remap_unlock(src, dest);
if (ret)
trace_xfs_reflink_remap_range_error(dest, ret, _RET_IP_);
return remapped > 0 ? remapped : ret;

View file

@ -1284,24 +1284,42 @@ xfs_iolock_two_inodes_and_break_layout(
return 0;
}
/* Unlock both inodes after they've been prepped for a range clone. */
/*
* Lock two files so that userspace cannot initiate I/O via file syscalls or
* mmap activity.
*/
static int
xfs_reflink_remap_lock(
struct xfs_inode *ip1,
struct xfs_inode *ip2)
{
int ret;
ret = xfs_iolock_two_inodes_and_break_layout(VFS_I(ip1), VFS_I(ip2));
if (ret)
return ret;
if (ip1 == ip2)
xfs_ilock(ip1, XFS_MMAPLOCK_EXCL);
else
xfs_lock_two_inodes(ip1, XFS_MMAPLOCK_EXCL,
ip2, XFS_MMAPLOCK_EXCL);
return 0;
}
/* Unlock both files to allow IO and mmap activity. */
void
xfs_reflink_remap_unlock(
struct file *file_in,
struct file *file_out)
struct xfs_inode *ip1,
struct xfs_inode *ip2)
{
struct inode *inode_in = file_inode(file_in);
struct xfs_inode *src = XFS_I(inode_in);
struct inode *inode_out = file_inode(file_out);
struct xfs_inode *dest = XFS_I(inode_out);
bool same_inode = (inode_in == inode_out);
bool same_inode = (ip1 == ip2);
xfs_iunlock(dest, XFS_MMAPLOCK_EXCL);
xfs_iunlock(ip2, XFS_MMAPLOCK_EXCL);
if (!same_inode)
xfs_iunlock(src, XFS_MMAPLOCK_EXCL);
inode_unlock(inode_out);
xfs_iunlock(ip1, XFS_MMAPLOCK_EXCL);
inode_unlock(VFS_I(ip2));
if (!same_inode)
inode_unlock(inode_in);
inode_unlock(VFS_I(ip1));
}
/*
@ -1366,18 +1384,12 @@ xfs_reflink_remap_prep(
struct xfs_inode *src = XFS_I(inode_in);
struct inode *inode_out = file_inode(file_out);
struct xfs_inode *dest = XFS_I(inode_out);
bool same_inode = (inode_in == inode_out);
int ret;
/* Lock both files against IO */
ret = xfs_iolock_two_inodes_and_break_layout(inode_in, inode_out);
ret = xfs_reflink_remap_lock(src, dest);
if (ret)
return ret;
if (same_inode)
xfs_ilock(src, XFS_MMAPLOCK_EXCL);
else
xfs_lock_two_inodes(src, XFS_MMAPLOCK_EXCL, dest,
XFS_MMAPLOCK_EXCL);
/* Check file eligibility and prepare for block sharing. */
ret = -EINVAL;
@ -1428,7 +1440,7 @@ xfs_reflink_remap_prep(
return 0;
out_unlock:
xfs_reflink_remap_unlock(file_in, file_out);
xfs_reflink_remap_unlock(src, dest);
return ret;
}

View file

@ -56,7 +56,6 @@ extern int xfs_reflink_remap_blocks(struct xfs_inode *src, loff_t pos_in,
loff_t *remapped);
extern int xfs_reflink_update_dest(struct xfs_inode *dest, xfs_off_t newlen,
xfs_extlen_t cowextsize, unsigned int remap_flags);
extern void xfs_reflink_remap_unlock(struct file *file_in,
struct file *file_out);
extern void xfs_reflink_remap_unlock(struct xfs_inode *ip1, struct xfs_inode *ip2);
#endif /* __XFS_REFLINK_H */