
From: Sebastien Dugue <sebastien.dugue@bull.net>

When reading a file in async mode (using kernel AIO), and the file size is
lower than the requested size (short read), the direct IO layer reports an
incorrect number of bytes read (transferred).

That case is handled for the sync path in 'direct_io_worker'
(fs/direct-io.c) where a check is made against the file size.

This patch does the same thing for the async path.

Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/fs/direct-io.c |   19 ++++++++++++++++---
 1 files changed, 16 insertions(+), 3 deletions(-)

diff -puN fs/direct-io.c~direct-io-async-short-read-fix fs/direct-io.c
--- 25/fs/direct-io.c~direct-io-async-short-read-fix	2005-03-07 22:26:26.000000000 -0800
+++ 25-akpm/fs/direct-io.c	2005-03-07 22:26:26.000000000 -0800
@@ -230,17 +230,30 @@ static void finished_one_bio(struct dio 
 	spin_lock_irqsave(&dio->bio_lock, flags);
 	if (dio->bio_count == 1) {
 		if (dio->is_async) {
+			ssize_t transferred;
+			ssize_t i_size;
+			loff_t offset;
+
 			/*
 			 * Last reference to the dio is going away.
 			 * Drop spinlock and complete the DIO.
 			 */
 			spin_unlock_irqrestore(&dio->bio_lock, flags);
-			dio_complete(dio, dio->block_in_file << dio->blkbits,
-					dio->result);
+
+			/* Check for short read case */
+			transferred = dio->result;
+			i_size = i_size_read (dio->inode);
+			offset = dio->iocb->ki_pos;
+
+			if ((dio->rw == READ) && ((offset + transferred) > i_size))
+				transferred = i_size - offset;
+
+			dio_complete(dio, offset, transferred);
+
 			/* Complete AIO later if falling back to buffered i/o */
 			if (dio->result == dio->size ||
 				((dio->rw == READ) && dio->result)) {
-				aio_complete(dio->iocb, dio->result, 0);
+				aio_complete(dio->iocb, transferred, 0);
 				kfree(dio);
 				return;
 			} else {
_
