diff options
| author | Daniel McNeil <daniel@osdl.org> | 2005-04-16 15:25:50 -0700 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:25:50 -0700 | 
| commit | 29504ff3be784372c4e2f7e31681a3e0292c4d9a (patch) | |
| tree | 449f6598e10a1930d113fd7bbe3aa6ca37341d10 /fs/direct-io.c | |
| parent | 1f08ad02379530e1c970d3d104343b9907b4d1b4 (diff) | |
[PATCH] Direct IO async short read fix
The direct I/O code is mapping the read request to the file system block.  If
the file size was not on a block boundary, the result would show the the read
reading past EOF.  This was only happening for the AIO case.  The non-AIO case
truncates the result to match file size (in direct_io_worker).  This patch
does the same thing for the AIO case, it truncates the result to match the
file size if the read reads past EOF.
When I/O completes the result can be truncated to match the file size
without using i_size_read(), thus the aio result now matches the number of
bytes read to the end of file.
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/direct-io.c')
| -rw-r--r-- | fs/direct-io.c | 20 | 
1 files changed, 17 insertions, 3 deletions
| diff --git a/fs/direct-io.c b/fs/direct-io.c index 5a674a0c7146..1d55e7e67342 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -66,6 +66,7 @@ struct dio {  	struct bio *bio;		/* bio under assembly */  	struct inode *inode;  	int rw; +	loff_t i_size;			/* i_size when submitted */  	int lock_type;			/* doesn't change */  	unsigned blkbits;		/* doesn't change */  	unsigned blkfactor;		/* When we're using an alignment which @@ -230,17 +231,29 @@ static void finished_one_bio(struct dio *dio)  	spin_lock_irqsave(&dio->bio_lock, flags);  	if (dio->bio_count == 1) {  		if (dio->is_async) { +			ssize_t transferred; +			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; +			offset = dio->iocb->ki_pos; + +			if ((dio->rw == READ) && +			    ((offset + transferred) > dio->i_size)) +				transferred = dio->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 { @@ -951,6 +964,7 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode,  	dio->page_errors = 0;  	dio->result = 0;  	dio->iocb = iocb; +	dio->i_size = i_size_read(inode);  	/*  	 * BIO completion state. | 
