direct-io.c |   21 ++++++++++++++++++---
 filemap.c   |    7 +------
 2 files changed, 19 insertions(+), 9 deletions(-)

diff -puN mm/filemap.c~dio-eof-read mm/filemap.c
--- 25/mm/filemap.c~dio-eof-read	2003-02-14 01:00:56.000000000 -0800
+++ 25-akpm/mm/filemap.c	2003-02-14 01:00:56.000000000 -0800
@@ -761,13 +761,8 @@ __generic_file_aio_read(struct kiocb *io
 			goto out; /* skip atime */
 		size = inode->i_size;
 		if (pos < size) {
-			if (pos + count > size) {
-				count = size - pos;
-				nr_segs = iov_shorten((struct iovec *)iov,
-							nr_segs, count);
-			}
 			retval = generic_file_direct_IO(READ, iocb,
-					iov, pos, nr_segs);
+						iov, pos, nr_segs);
 			if (retval >= 0 && !is_sync_kiocb(iocb))
 				retval = -EIOCBQUEUED;
 			if (retval > 0)
diff -puN fs/direct-io.c~dio-eof-read fs/direct-io.c
--- 25/fs/direct-io.c~dio-eof-read	2003-02-14 01:00:56.000000000 -0800
+++ 25-akpm/fs/direct-io.c	2003-02-14 01:00:56.000000000 -0800
@@ -57,7 +57,7 @@ struct dio {
 	struct inode *inode;
 	int rw;
 	unsigned blkbits;		/* doesn't change */
-	unsigned blkfactor;		/* When we're using an aligment which
+	unsigned blkfactor;		/* When we're using an alignment which
 					   is finer than the filesystem's soft
 					   blocksize, this specifies how much
 					   finer.  blkfactor=2 means 1/4-block
@@ -754,7 +754,15 @@ static int do_direct_IO(struct dio *dio)
 do_holes:
 			/* Handle holes */
 			if (!buffer_mapped(map_bh)) {
-				char *kaddr = kmap_atomic(page, KM_USER0);
+				char *kaddr;
+
+				if (dio->block_in_file >=
+						dio->inode->i_size>>blkbits) {
+					/* We hit eof */
+					page_cache_release(page);
+					goto out;
+				}
+				kaddr = kmap_atomic(page, KM_USER0);
 				memset(kaddr + (block_in_page << blkbits),
 						0, 1 << blkbits);
 				flush_dcache_page(page);
@@ -934,8 +942,15 @@ direct_io_worker(int rw, struct kiocb *i
 			ret = ret2;
 		if (ret == 0)
 			ret = dio->page_errors;
-		if (ret == 0 && dio->result)
+		if (ret == 0 && dio->result) {
 			ret = dio->result;
+			/*
+			 * Adjust the return value if the read crossed a
+			 * non-block-aligned EOF.
+			 */
+			if (rw == READ && (offset + ret > inode->i_size))
+				ret = inode->i_size - offset;
+		}
 		kfree(dio);
 	}
 	return ret;

_