diff options
author | Daniel McNeil <daniel@osdl.org> | 2005-04-16 18:25:50 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:25:50 -0400 |
commit | 29504ff3be784372c4e2f7e31681a3e0292c4d9a (patch) | |
tree | 449f6598e10a1930d113fd7bbe3aa6ca37341d10 /fs | |
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')
-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 { | |||
66 | struct bio *bio; /* bio under assembly */ | 66 | struct bio *bio; /* bio under assembly */ |
67 | struct inode *inode; | 67 | struct inode *inode; |
68 | int rw; | 68 | int rw; |
69 | loff_t i_size; /* i_size when submitted */ | ||
69 | int lock_type; /* doesn't change */ | 70 | int lock_type; /* doesn't change */ |
70 | unsigned blkbits; /* doesn't change */ | 71 | unsigned blkbits; /* doesn't change */ |
71 | unsigned blkfactor; /* When we're using an alignment which | 72 | unsigned blkfactor; /* When we're using an alignment which |
@@ -230,17 +231,29 @@ static void finished_one_bio(struct dio *dio) | |||
230 | spin_lock_irqsave(&dio->bio_lock, flags); | 231 | spin_lock_irqsave(&dio->bio_lock, flags); |
231 | if (dio->bio_count == 1) { | 232 | if (dio->bio_count == 1) { |
232 | if (dio->is_async) { | 233 | if (dio->is_async) { |
234 | ssize_t transferred; | ||
235 | loff_t offset; | ||
236 | |||
233 | /* | 237 | /* |
234 | * Last reference to the dio is going away. | 238 | * Last reference to the dio is going away. |
235 | * Drop spinlock and complete the DIO. | 239 | * Drop spinlock and complete the DIO. |
236 | */ | 240 | */ |
237 | spin_unlock_irqrestore(&dio->bio_lock, flags); | 241 | spin_unlock_irqrestore(&dio->bio_lock, flags); |
238 | dio_complete(dio, dio->block_in_file << dio->blkbits, | 242 | |
239 | dio->result); | 243 | /* Check for short read case */ |
244 | transferred = dio->result; | ||
245 | offset = dio->iocb->ki_pos; | ||
246 | |||
247 | if ((dio->rw == READ) && | ||
248 | ((offset + transferred) > dio->i_size)) | ||
249 | transferred = dio->i_size - offset; | ||
250 | |||
251 | dio_complete(dio, offset, transferred); | ||
252 | |||
240 | /* Complete AIO later if falling back to buffered i/o */ | 253 | /* Complete AIO later if falling back to buffered i/o */ |
241 | if (dio->result == dio->size || | 254 | if (dio->result == dio->size || |
242 | ((dio->rw == READ) && dio->result)) { | 255 | ((dio->rw == READ) && dio->result)) { |
243 | aio_complete(dio->iocb, dio->result, 0); | 256 | aio_complete(dio->iocb, transferred, 0); |
244 | kfree(dio); | 257 | kfree(dio); |
245 | return; | 258 | return; |
246 | } else { | 259 | } else { |
@@ -951,6 +964,7 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode, | |||
951 | dio->page_errors = 0; | 964 | dio->page_errors = 0; |
952 | dio->result = 0; | 965 | dio->result = 0; |
953 | dio->iocb = iocb; | 966 | dio->iocb = iocb; |
967 | dio->i_size = i_size_read(inode); | ||
954 | 968 | ||
955 | /* | 969 | /* |
956 | * BIO completion state. | 970 | * BIO completion state. |