Commit 187372a3 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Dave Chinner
Browse files

direct-io: always call ->end_io if non-NULL



This way we can pass back errors to the file system, and allow for
cleanup required for all direct I/O invocations.

Also allow the ->end_io handlers to return errors on their own, so that
I/O completion errors can be passed on to the callers.

Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
Signed-off-by: default avatarDave Chinner <david@fromorbit.com>
parent 36f90b0a
Loading
Loading
Loading
Loading
+7 −2
Original line number Diff line number Diff line
@@ -267,8 +267,13 @@ ssize_t dax_do_io(struct kiocb *iocb, struct inode *inode,
	if ((flags & DIO_LOCKING) && iov_iter_rw(iter) == READ)
		inode_unlock(inode);

	if ((retval > 0) && end_io)
		end_io(iocb, pos, retval, bh.b_private);
	if (end_io) {
		int err;

		err = end_io(iocb, pos, retval, bh.b_private);
		if (err)
			retval = err;
	}

	if (!(flags & DIO_SKIP_DIO_COUNT))
		inode_dio_end(inode);
+7 −2
Original line number Diff line number Diff line
@@ -253,8 +253,13 @@ static ssize_t dio_complete(struct dio *dio, loff_t offset, ssize_t ret,
	if (ret == 0)
		ret = transferred;

	if (dio->end_io && dio->result)
		dio->end_io(dio->iocb, offset, transferred, dio->private);
	if (dio->end_io) {
		int err;

		err = dio->end_io(dio->iocb, offset, ret, dio->private);
		if (err)
			ret = err;
	}

	if (!(dio->flags & DIO_SKIP_DIO_COUNT))
		inode_dio_end(dio->inode);
+7 −2
Original line number Diff line number Diff line
@@ -3161,14 +3161,17 @@ out:
}
#endif

static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset,
static int ext4_end_io_dio(struct kiocb *iocb, loff_t offset,
			    ssize_t size, void *private)
{
        ext4_io_end_t *io_end = iocb->private;

	if (size <= 0)
		return 0;

	/* if not async direct IO just return */
	if (!io_end)
		return;
		return 0;

	ext_debug("ext4_end_io_dio(): io_end 0x%p "
		  "for inode %lu, iocb 0x%p, offset %llu, size %zd\n",
@@ -3179,6 +3182,8 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset,
	io_end->offset = offset;
	io_end->size = size;
	ext4_put_io_end(io_end);

	return 0;
}

/*
+6 −1
Original line number Diff line number Diff line
@@ -620,7 +620,7 @@ bail:
 * particularly interested in the aio/dio case.  We use the rw_lock DLM lock
 * to protect io on one node from truncation on another.
 */
static void ocfs2_dio_end_io(struct kiocb *iocb,
static int ocfs2_dio_end_io(struct kiocb *iocb,
			     loff_t offset,
			     ssize_t bytes,
			     void *private)
@@ -628,6 +628,9 @@ static void ocfs2_dio_end_io(struct kiocb *iocb,
	struct inode *inode = file_inode(iocb->ki_filp);
	int level;

	if (bytes <= 0)
		return 0;

	/* this io's submitter should not have unlocked this before we could */
	BUG_ON(!ocfs2_iocb_is_rw_locked(iocb));

@@ -644,6 +647,8 @@ static void ocfs2_dio_end_io(struct kiocb *iocb,
		level = ocfs2_iocb_rw_locked_level(iocb);
		ocfs2_rw_unlock(inode, level);
	}

	return 0;
}

static int ocfs2_releasepage(struct page *page, gfp_t wait)
+7 −6
Original line number Diff line number Diff line
@@ -1645,7 +1645,7 @@ out_end_io:
 * case the completion can be called in interrupt context, whereas if we have an
 * ioend we will always be called in task context (i.e. from a workqueue).
 */
STATIC void
STATIC int
xfs_end_io_direct_write(
	struct kiocb		*iocb,
	loff_t			offset,
@@ -1655,15 +1655,19 @@ xfs_end_io_direct_write(
	struct inode		*inode = file_inode(iocb->ki_filp);
	struct xfs_ioend	*ioend = private;

	if (size <= 0)
		return 0;

	trace_xfs_gbmap_direct_endio(XFS_I(inode), offset, size,
				     ioend ? ioend->io_type : 0, NULL);

	if (!ioend) {
		ASSERT(offset + size <= i_size_read(inode));
		return;
		return 0;
	}

	__xfs_end_io_direct_write(inode, ioend, offset, size);
	return 0;
}

static inline ssize_t
@@ -1672,10 +1676,7 @@ xfs_vm_do_dio(
	struct kiocb		*iocb,
	struct iov_iter		*iter,
	loff_t			offset,
	void			(*endio)(struct kiocb	*iocb,
					 loff_t		offset,
					 ssize_t	size,
					 void		*private),
	dio_iodone_t		endio,
	int			flags)
{
	struct block_device	*bdev;
Loading