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:
@ -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));
|
||||
}
|
||||
|
Reference in New Issue
Block a user