From 50ce176cea9518621b7c836af0a419d3a0c5e9e7 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 2 Jun 2004 18:02:02 -0700 Subject: [PATCH] [PATCH] direct-io hole fix From: Chris Mason When filling holes via DIRECT_IO, we fall back to normal buffered io. For this to work properly, the direct io funcs have to return a value of zero to the file write functions, so the file write functions know where to start writing. In some cases, dio->result was getting returned by direct_io_worker, and that wasn't always zero, causing some data not to be written. From: : - Simplify things by setting `ret' later on, fix up subsequent damage to the dio_complete() args. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/direct-io.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/fs/direct-io.c b/fs/direct-io.c index 0831f490f8713..3741932a4b935 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -987,13 +987,6 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode, } } /* end iovec loop */ - if (ret == -ENOTBLK && rw == WRITE) { - /* - * The remaining part of the request will be - * be handled by buffered I/O when we return - */ - ret = 0; - } /* * There may be some unwritten disk at the end of a part-written * fs-block-sized block. Go zero that now. @@ -1060,24 +1053,29 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode, kfree(dio); } } else { + ssize_t transferred = 0; + finished_one_bio(dio); ret2 = dio_await_completion(dio); if (ret == 0) ret = ret2; if (ret == 0) ret = dio->page_errors; - if (ret == 0 && dio->result) { + if (dio->result) { loff_t i_size = i_size_read(inode); - ret = dio->result; + transferred = dio->result; /* * Adjust the return value if the read crossed a * non-block-aligned EOF. */ - if (rw == READ && (offset + ret > i_size)) - ret = i_size - offset; + if (rw == READ && (offset + transferred > i_size)) + transferred = i_size - offset; } - dio_complete(dio, offset, ret); + dio_complete(dio, offset, transferred); + if (ret == 0) + ret = transferred; + /* We could have also come here on an AIO file extend */ if (!is_sync_kiocb(iocb) && rw == WRITE && ret >= 0 && dio->result == dio->size) @@ -1088,6 +1086,13 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode, aio_complete(iocb, ret, 0); kfree(dio); } + if (ret == -ENOTBLK && rw == WRITE) { + /* + * The entire request will be be handled by buffered I/O + * when we return + */ + ret = 0; + } return ret; } -- 2.53.0