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 --- 25-akpm/fs/direct-io.c | 29 +++++++++++++++++------------ 1 files changed, 17 insertions(+), 12 deletions(-) diff -puN fs/direct-io.c~direct-io-hole-fix fs/direct-io.c --- 25/fs/direct-io.c~direct-io-hole-fix 2004-06-03 00:07:07.956123120 -0700 +++ 25-akpm/fs/direct-io.c 2004-06-03 00:07:07.961122360 -0700 @@ -990,13 +990,6 @@ direct_io_worker(int rw, struct kiocb *i } } /* 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. @@ -1063,24 +1056,29 @@ direct_io_worker(int rw, struct kiocb *i 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) @@ -1091,6 +1089,13 @@ direct_io_worker(int rw, struct kiocb *i 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; } _