Commit 50ce176c authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] direct-io hole fix

From: Chris Mason <mason@suse.com>

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: <akpm@osdl.org>:

- Simplify things by setting `ret' later on, fix up subsequent damage to the
  dio_complete() args.
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent dde27822
...@@ -987,13 +987,6 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode, ...@@ -987,13 +987,6 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode,
} }
} /* end iovec loop */ } /* 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 * There may be some unwritten disk at the end of a part-written
* fs-block-sized block. Go zero that now. * fs-block-sized block. Go zero that now.
...@@ -1060,24 +1053,29 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode, ...@@ -1060,24 +1053,29 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode,
kfree(dio); kfree(dio);
} }
} else { } else {
ssize_t transferred = 0;
finished_one_bio(dio); finished_one_bio(dio);
ret2 = dio_await_completion(dio); ret2 = dio_await_completion(dio);
if (ret == 0) if (ret == 0)
ret = ret2; ret = ret2;
if (ret == 0) if (ret == 0)
ret = dio->page_errors; ret = dio->page_errors;
if (ret == 0 && dio->result) { if (dio->result) {
loff_t i_size = i_size_read(inode); loff_t i_size = i_size_read(inode);
ret = dio->result; transferred = dio->result;
/* /*
* Adjust the return value if the read crossed a * Adjust the return value if the read crossed a
* non-block-aligned EOF. * non-block-aligned EOF.
*/ */
if (rw == READ && (offset + ret > i_size)) if (rw == READ && (offset + transferred > i_size))
ret = i_size - offset; 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 */ /* We could have also come here on an AIO file extend */
if (!is_sync_kiocb(iocb) && rw == WRITE && if (!is_sync_kiocb(iocb) && rw == WRITE &&
ret >= 0 && dio->result == dio->size) ret >= 0 && dio->result == dio->size)
...@@ -1088,6 +1086,13 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode, ...@@ -1088,6 +1086,13 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode,
aio_complete(iocb, ret, 0); aio_complete(iocb, ret, 0);
kfree(dio); 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; return ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment