xfs: move helpers that lock and unlock two inodes against userspace IO
Move the double-inode locking helpers to xfs_inode.c since they're not specific to reflink. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> Reviewed-by: Brian Foster <bfoster@redhat.com>
This commit is contained in:
parent
10b4bd6c9c
commit
e2aaee9cd3
|
@ -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(src, dest);
|
||||
xfs_iunlock2_io_mmap(src, dest);
|
||||
if (ret)
|
||||
trace_xfs_reflink_remap_range_error(dest, ret, _RET_IP_);
|
||||
return remapped > 0 ? remapped : ret;
|
||||
|
|
|
@ -3881,3 +3881,96 @@ xfs_log_force_inode(
|
|||
return 0;
|
||||
return xfs_log_force_lsn(ip->i_mount, lsn, XFS_LOG_SYNC, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Grab the exclusive iolock for a data copy from src to dest, making sure to
|
||||
* abide vfs locking order (lowest pointer value goes first) and breaking the
|
||||
* layout leases before proceeding. The loop is needed because we cannot call
|
||||
* the blocking break_layout() with the iolocks held, and therefore have to
|
||||
* back out both locks.
|
||||
*/
|
||||
static int
|
||||
xfs_iolock_two_inodes_and_break_layout(
|
||||
struct inode *src,
|
||||
struct inode *dest)
|
||||
{
|
||||
int error;
|
||||
|
||||
if (src > dest)
|
||||
swap(src, dest);
|
||||
|
||||
retry:
|
||||
/* Wait to break both inodes' layouts before we start locking. */
|
||||
error = break_layout(src, true);
|
||||
if (error)
|
||||
return error;
|
||||
if (src != dest) {
|
||||
error = break_layout(dest, true);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Lock one inode and make sure nobody got in and leased it. */
|
||||
inode_lock(src);
|
||||
error = break_layout(src, false);
|
||||
if (error) {
|
||||
inode_unlock(src);
|
||||
if (error == -EWOULDBLOCK)
|
||||
goto retry;
|
||||
return error;
|
||||
}
|
||||
|
||||
if (src == dest)
|
||||
return 0;
|
||||
|
||||
/* Lock the other inode and make sure nobody got in and leased it. */
|
||||
inode_lock_nested(dest, I_MUTEX_NONDIR2);
|
||||
error = break_layout(dest, false);
|
||||
if (error) {
|
||||
inode_unlock(src);
|
||||
inode_unlock(dest);
|
||||
if (error == -EWOULDBLOCK)
|
||||
goto retry;
|
||||
return error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Lock two inodes so that userspace cannot initiate I/O via file syscalls or
|
||||
* mmap activity.
|
||||
*/
|
||||
int
|
||||
xfs_ilock2_io_mmap(
|
||||
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 inodes to allow IO and mmap activity. */
|
||||
void
|
||||
xfs_iunlock2_io_mmap(
|
||||
struct xfs_inode *ip1,
|
||||
struct xfs_inode *ip2)
|
||||
{
|
||||
bool same_inode = (ip1 == ip2);
|
||||
|
||||
xfs_iunlock(ip2, XFS_MMAPLOCK_EXCL);
|
||||
if (!same_inode)
|
||||
xfs_iunlock(ip1, XFS_MMAPLOCK_EXCL);
|
||||
inode_unlock(VFS_I(ip2));
|
||||
if (!same_inode)
|
||||
inode_unlock(VFS_I(ip1));
|
||||
}
|
||||
|
|
|
@ -499,4 +499,7 @@ void xfs_iunlink_destroy(struct xfs_perag *pag);
|
|||
|
||||
void xfs_end_io(struct work_struct *work);
|
||||
|
||||
int xfs_ilock2_io_mmap(struct xfs_inode *ip1, struct xfs_inode *ip2);
|
||||
void xfs_iunlock2_io_mmap(struct xfs_inode *ip1, struct xfs_inode *ip2);
|
||||
|
||||
#endif /* __XFS_INODE_H__ */
|
||||
|
|
|
@ -1229,99 +1229,6 @@ xfs_reflink_remap_blocks(
|
|||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Grab the exclusive iolock for a data copy from src to dest, making sure to
|
||||
* abide vfs locking order (lowest pointer value goes first) and breaking the
|
||||
* layout leases before proceeding. The loop is needed because we cannot call
|
||||
* the blocking break_layout() with the iolocks held, and therefore have to
|
||||
* back out both locks.
|
||||
*/
|
||||
static int
|
||||
xfs_iolock_two_inodes_and_break_layout(
|
||||
struct inode *src,
|
||||
struct inode *dest)
|
||||
{
|
||||
int error;
|
||||
|
||||
if (src > dest)
|
||||
swap(src, dest);
|
||||
|
||||
retry:
|
||||
/* Wait to break both inodes' layouts before we start locking. */
|
||||
error = break_layout(src, true);
|
||||
if (error)
|
||||
return error;
|
||||
if (src != dest) {
|
||||
error = break_layout(dest, true);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Lock one inode and make sure nobody got in and leased it. */
|
||||
inode_lock(src);
|
||||
error = break_layout(src, false);
|
||||
if (error) {
|
||||
inode_unlock(src);
|
||||
if (error == -EWOULDBLOCK)
|
||||
goto retry;
|
||||
return error;
|
||||
}
|
||||
|
||||
if (src == dest)
|
||||
return 0;
|
||||
|
||||
/* Lock the other inode and make sure nobody got in and leased it. */
|
||||
inode_lock_nested(dest, I_MUTEX_NONDIR2);
|
||||
error = break_layout(dest, false);
|
||||
if (error) {
|
||||
inode_unlock(src);
|
||||
inode_unlock(dest);
|
||||
if (error == -EWOULDBLOCK)
|
||||
goto retry;
|
||||
return error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 xfs_inode *ip1,
|
||||
struct xfs_inode *ip2)
|
||||
{
|
||||
bool same_inode = (ip1 == ip2);
|
||||
|
||||
xfs_iunlock(ip2, XFS_MMAPLOCK_EXCL);
|
||||
if (!same_inode)
|
||||
xfs_iunlock(ip1, XFS_MMAPLOCK_EXCL);
|
||||
inode_unlock(VFS_I(ip2));
|
||||
if (!same_inode)
|
||||
inode_unlock(VFS_I(ip1));
|
||||
}
|
||||
|
||||
/*
|
||||
* If we're reflinking to a point past the destination file's EOF, we must
|
||||
* zero any speculative post-EOF preallocations that sit between the old EOF
|
||||
|
@ -1387,7 +1294,7 @@ xfs_reflink_remap_prep(
|
|||
int ret;
|
||||
|
||||
/* Lock both files against IO */
|
||||
ret = xfs_reflink_remap_lock(src, dest);
|
||||
ret = xfs_ilock2_io_mmap(src, dest);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -1440,7 +1347,7 @@ xfs_reflink_remap_prep(
|
|||
|
||||
return 0;
|
||||
out_unlock:
|
||||
xfs_reflink_remap_unlock(src, dest);
|
||||
xfs_iunlock2_io_mmap(src, dest);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -56,6 +56,5 @@ 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 xfs_inode *ip1, struct xfs_inode *ip2);
|
||||
|
||||
#endif /* __XFS_REFLINK_H */
|
||||
|
|
Loading…
Reference in New Issue
Block a user