Commit 8626b67a authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Chandan Babu R
Browse files

xfs: move the dio write relocking out of xfs_ilock_for_iomap



About half of xfs_ilock_for_iomap deals with a special case for direct
I/O writes to COW files that need to take the ilock exclusively.  Move
this code into the one callers that cares and simplify
xfs_ilock_for_iomap.

Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarDarrick J. Wong <djwong@kernel.org>
Signed-off-by: default avatarChandan Babu R <chandanbabu@kernel.org>
parent 0c7fcdb6
Loading
Loading
Loading
Loading
+34 −37
Original line number Diff line number Diff line
@@ -717,53 +717,30 @@ imap_needs_cow(
	return true;
}

/*
 * Extents not yet cached requires exclusive access, don't block for
 * IOMAP_NOWAIT.
 *
 * This is basically an opencoded xfs_ilock_data_map_shared() call, but with
 * support for IOMAP_NOWAIT.
 */
static int
xfs_ilock_for_iomap(
	struct xfs_inode	*ip,
	unsigned		flags,
	unsigned		*lockmode)
{
	unsigned int		mode = *lockmode;
	bool			is_write = flags & (IOMAP_WRITE | IOMAP_ZERO);

	/*
	 * COW writes may allocate delalloc space or convert unwritten COW
	 * extents, so we need to make sure to take the lock exclusively here.
	 */
	if (xfs_is_cow_inode(ip) && is_write)
		mode = XFS_ILOCK_EXCL;

	/*
	 * Extents not yet cached requires exclusive access, don't block.  This
	 * is an opencoded xfs_ilock_data_map_shared() call but with
	 * non-blocking behaviour.
	 */
	if (xfs_need_iread_extents(&ip->i_df)) {
		if (flags & IOMAP_NOWAIT)
			return -EAGAIN;
		mode = XFS_ILOCK_EXCL;
	}

relock:
	if (flags & IOMAP_NOWAIT) {
		if (!xfs_ilock_nowait(ip, mode))
		if (xfs_need_iread_extents(&ip->i_df))
			return -EAGAIN;
		if (!xfs_ilock_nowait(ip, *lockmode))
			return -EAGAIN;
	} else {
		xfs_ilock(ip, mode);
	}

	/*
	 * The reflink iflag could have changed since the earlier unlocked
	 * check, so if we got ILOCK_SHARED for a write and but we're now a
	 * reflink inode we have to switch to ILOCK_EXCL and relock.
	 */
	if (mode == XFS_ILOCK_SHARED && is_write && xfs_is_cow_inode(ip)) {
		xfs_iunlock(ip, mode);
		mode = XFS_ILOCK_EXCL;
		goto relock;
		if (xfs_need_iread_extents(&ip->i_df))
			*lockmode = XFS_ILOCK_EXCL;
		xfs_ilock(ip, *lockmode);
	}

	*lockmode = mode;
	return 0;
}

@@ -801,7 +778,7 @@ xfs_direct_write_iomap_begin(
	int			nimaps = 1, error = 0;
	bool			shared = false;
	u16			iomap_flags = 0;
	unsigned int		lockmode = XFS_ILOCK_SHARED;
	unsigned int		lockmode;
	u64			seq;

	ASSERT(flags & (IOMAP_WRITE | IOMAP_ZERO));
@@ -817,10 +794,30 @@ xfs_direct_write_iomap_begin(
	if (offset + length > i_size_read(inode))
		iomap_flags |= IOMAP_F_DIRTY;

	/*
	 * COW writes may allocate delalloc space or convert unwritten COW
	 * extents, so we need to make sure to take the lock exclusively here.
	 */
	if (xfs_is_cow_inode(ip))
		lockmode = XFS_ILOCK_EXCL;
	else
		lockmode = XFS_ILOCK_SHARED;

relock:
	error = xfs_ilock_for_iomap(ip, flags, &lockmode);
	if (error)
		return error;

	/*
	 * The reflink iflag could have changed since the earlier unlocked
	 * check, check if it again and relock if needed.
	 */
	if (xfs_is_cow_inode(ip) && lockmode == XFS_ILOCK_SHARED) {
		xfs_iunlock(ip, lockmode);
		lockmode = XFS_ILOCK_EXCL;
		goto relock;
	}

	error = xfs_bmapi_read(ip, offset_fsb, end_fsb - offset_fsb, &imap,
			       &nimaps, 0);
	if (error)