Commit db8367f6 authored by Carlos Maiolino's avatar Carlos Maiolino
Browse files

xfs: factor out isize updates from xfs_dio_write_end_io



This is the only code needed for zoned inodes, so factor it out so
we can move zoned inodes ioend to its own callback.

Signed-off-by: default avatarCarlos Maiolino <cmaiolino@redhat.com>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarDamien Le Moal <dlemoal@kernel.org>
Signed-off-by: default avatarCarlos Maiolino <cem@kernel.org>
parent c6ce65cb
Loading
Loading
Loading
Loading
+37 −23
Original line number Diff line number Diff line
@@ -560,6 +560,42 @@ xfs_zoned_write_space_reserve(
			flags, ac);
}

/*
 * We need to lock the test/set EOF update as we can be racing with
 * other IO completions here to update the EOF. Failing to serialise
 * here can result in EOF moving backwards and Bad Things Happen when
 * that occurs.
 *
 * As IO completion only ever extends EOF, we can do an unlocked check
 * here to avoid taking the spinlock. If we land within the current EOF,
 * then we do not need to do an extending update at all, and we don't
 * need to take the lock to check this. If we race with an update moving
 * EOF, then we'll either still be beyond EOF and need to take the lock,
 * or we'll be within EOF and we don't need to take it at all.
 */
static int
xfs_dio_endio_set_isize(
	struct inode		*inode,
	loff_t			offset,
	ssize_t			size)
{
	struct xfs_inode	*ip = XFS_I(inode);

	if (offset + size <= i_size_read(inode))
		return 0;

	spin_lock(&ip->i_flags_lock);
	if (offset + size <= i_size_read(inode)) {
		spin_unlock(&ip->i_flags_lock);
		return 0;
	}

	i_size_write(inode, offset + size);
	spin_unlock(&ip->i_flags_lock);

	return xfs_setfilesize(ip, offset, size);
}

static int
xfs_dio_write_end_io(
	struct kiocb		*iocb,
@@ -623,30 +659,8 @@ xfs_dio_write_end_io(
	 * with the on-disk inode size being outside the in-core inode size. We
	 * have no other method of updating EOF for AIO, so always do it here
	 * if necessary.
	 *
	 * We need to lock the test/set EOF update as we can be racing with
	 * other IO completions here to update the EOF. Failing to serialise
	 * here can result in EOF moving backwards and Bad Things Happen when
	 * that occurs.
	 *
	 * As IO completion only ever extends EOF, we can do an unlocked check
	 * here to avoid taking the spinlock. If we land within the current EOF,
	 * then we do not need to do an extending update at all, and we don't
	 * need to take the lock to check this. If we race with an update moving
	 * EOF, then we'll either still be beyond EOF and need to take the lock,
	 * or we'll be within EOF and we don't need to take it at all.
	 */
	if (offset + size <= i_size_read(inode))
		goto out;

	spin_lock(&ip->i_flags_lock);
	if (offset + size > i_size_read(inode)) {
		i_size_write(inode, offset + size);
		spin_unlock(&ip->i_flags_lock);
		error = xfs_setfilesize(ip, offset, size);
	} else {
		spin_unlock(&ip->i_flags_lock);
	}
	error = xfs_dio_endio_set_isize(inode, offset, size);

out:
	memalloc_nofs_restore(nofs_flag);