diff options
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. |