提交 187372a3 编写于 作者: C Christoph Hellwig 提交者: Dave Chinner

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: NChristoph Hellwig <hch@lst.de>
Reviewed-by: NDave Chinner <dchinner@redhat.com>
Signed-off-by: NDave Chinner <david@fromorbit.com>
上级 36f90b0a
...@@ -267,8 +267,13 @@ ssize_t dax_do_io(struct kiocb *iocb, struct inode *inode, ...@@ -267,8 +267,13 @@ ssize_t dax_do_io(struct kiocb *iocb, struct inode *inode,
if ((flags & DIO_LOCKING) && iov_iter_rw(iter) == READ) if ((flags & DIO_LOCKING) && iov_iter_rw(iter) == READ)
inode_unlock(inode); inode_unlock(inode);
if ((retval > 0) && end_io) if (end_io) {
end_io(iocb, pos, retval, bh.b_private); int err;
err = end_io(iocb, pos, retval, bh.b_private);
if (err)
retval = err;
}
if (!(flags & DIO_SKIP_DIO_COUNT)) if (!(flags & DIO_SKIP_DIO_COUNT))
inode_dio_end(inode); inode_dio_end(inode);
......
...@@ -253,8 +253,13 @@ static ssize_t dio_complete(struct dio *dio, loff_t offset, ssize_t ret, ...@@ -253,8 +253,13 @@ static ssize_t dio_complete(struct dio *dio, loff_t offset, ssize_t ret,
if (ret == 0) if (ret == 0)
ret = transferred; ret = transferred;
if (dio->end_io && dio->result) if (dio->end_io) {
dio->end_io(dio->iocb, offset, transferred, dio->private); int err;
err = dio->end_io(dio->iocb, offset, ret, dio->private);
if (err)
ret = err;
}
if (!(dio->flags & DIO_SKIP_DIO_COUNT)) if (!(dio->flags & DIO_SKIP_DIO_COUNT))
inode_dio_end(dio->inode); inode_dio_end(dio->inode);
......
...@@ -3161,14 +3161,17 @@ int ext4_dax_mmap_get_block(struct inode *inode, sector_t iblock, ...@@ -3161,14 +3161,17 @@ int ext4_dax_mmap_get_block(struct inode *inode, sector_t iblock,
} }
#endif #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) ssize_t size, void *private)
{ {
ext4_io_end_t *io_end = iocb->private; ext4_io_end_t *io_end = iocb->private;
if (size <= 0)
return 0;
/* if not async direct IO just return */ /* if not async direct IO just return */
if (!io_end) if (!io_end)
return; return 0;
ext_debug("ext4_end_io_dio(): io_end 0x%p " ext_debug("ext4_end_io_dio(): io_end 0x%p "
"for inode %lu, iocb 0x%p, offset %llu, size %zd\n", "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, ...@@ -3179,6 +3182,8 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset,
io_end->offset = offset; io_end->offset = offset;
io_end->size = size; io_end->size = size;
ext4_put_io_end(io_end); ext4_put_io_end(io_end);
return 0;
} }
/* /*
......
...@@ -620,7 +620,7 @@ static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock, ...@@ -620,7 +620,7 @@ static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock,
* particularly interested in the aio/dio case. We use the rw_lock DLM lock * particularly interested in the aio/dio case. We use the rw_lock DLM lock
* to protect io on one node from truncation on another. * 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, loff_t offset,
ssize_t bytes, ssize_t bytes,
void *private) void *private)
...@@ -628,6 +628,9 @@ static void ocfs2_dio_end_io(struct kiocb *iocb, ...@@ -628,6 +628,9 @@ static void ocfs2_dio_end_io(struct kiocb *iocb,
struct inode *inode = file_inode(iocb->ki_filp); struct inode *inode = file_inode(iocb->ki_filp);
int level; int level;
if (bytes <= 0)
return 0;
/* this io's submitter should not have unlocked this before we could */ /* this io's submitter should not have unlocked this before we could */
BUG_ON(!ocfs2_iocb_is_rw_locked(iocb)); BUG_ON(!ocfs2_iocb_is_rw_locked(iocb));
...@@ -644,6 +647,8 @@ static void ocfs2_dio_end_io(struct kiocb *iocb, ...@@ -644,6 +647,8 @@ static void ocfs2_dio_end_io(struct kiocb *iocb,
level = ocfs2_iocb_rw_locked_level(iocb); level = ocfs2_iocb_rw_locked_level(iocb);
ocfs2_rw_unlock(inode, level); ocfs2_rw_unlock(inode, level);
} }
return 0;
} }
static int ocfs2_releasepage(struct page *page, gfp_t wait) static int ocfs2_releasepage(struct page *page, gfp_t wait)
......
...@@ -1645,7 +1645,7 @@ __xfs_end_io_direct_write( ...@@ -1645,7 +1645,7 @@ __xfs_end_io_direct_write(
* case the completion can be called in interrupt context, whereas if we have an * 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). * ioend we will always be called in task context (i.e. from a workqueue).
*/ */
STATIC void STATIC int
xfs_end_io_direct_write( xfs_end_io_direct_write(
struct kiocb *iocb, struct kiocb *iocb,
loff_t offset, loff_t offset,
...@@ -1655,15 +1655,19 @@ xfs_end_io_direct_write( ...@@ -1655,15 +1655,19 @@ xfs_end_io_direct_write(
struct inode *inode = file_inode(iocb->ki_filp); struct inode *inode = file_inode(iocb->ki_filp);
struct xfs_ioend *ioend = private; struct xfs_ioend *ioend = private;
if (size <= 0)
return 0;
trace_xfs_gbmap_direct_endio(XFS_I(inode), offset, size, trace_xfs_gbmap_direct_endio(XFS_I(inode), offset, size,
ioend ? ioend->io_type : 0, NULL); ioend ? ioend->io_type : 0, NULL);
if (!ioend) { if (!ioend) {
ASSERT(offset + size <= i_size_read(inode)); ASSERT(offset + size <= i_size_read(inode));
return; return 0;
} }
__xfs_end_io_direct_write(inode, ioend, offset, size); __xfs_end_io_direct_write(inode, ioend, offset, size);
return 0;
} }
static inline ssize_t static inline ssize_t
...@@ -1672,10 +1676,7 @@ xfs_vm_do_dio( ...@@ -1672,10 +1676,7 @@ xfs_vm_do_dio(
struct kiocb *iocb, struct kiocb *iocb,
struct iov_iter *iter, struct iov_iter *iter,
loff_t offset, loff_t offset,
void (*endio)(struct kiocb *iocb, dio_iodone_t endio,
loff_t offset,
ssize_t size,
void *private),
int flags) int flags)
{ {
struct block_device *bdev; struct block_device *bdev;
......
...@@ -70,7 +70,7 @@ extern int sysctl_protected_hardlinks; ...@@ -70,7 +70,7 @@ extern int sysctl_protected_hardlinks;
struct buffer_head; struct buffer_head;
typedef int (get_block_t)(struct inode *inode, sector_t iblock, typedef int (get_block_t)(struct inode *inode, sector_t iblock,
struct buffer_head *bh_result, int create); struct buffer_head *bh_result, int create);
typedef void (dio_iodone_t)(struct kiocb *iocb, loff_t offset, typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
ssize_t bytes, void *private); ssize_t bytes, void *private);
typedef void (dax_iodone_t)(struct buffer_head *bh_map, int uptodate); typedef void (dax_iodone_t)(struct buffer_head *bh_map, int uptodate);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册