diff options
Diffstat (limited to 'fs/direct-io.c')
| -rw-r--r-- | fs/direct-io.c | 94 |
1 files changed, 42 insertions, 52 deletions
diff --git a/fs/direct-io.c b/fs/direct-io.c index 45d34d807391..b57b671e1106 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c | |||
| @@ -210,19 +210,46 @@ static struct page *dio_get_page(struct dio *dio) | |||
| 210 | return dio->pages[dio->head++]; | 210 | return dio->pages[dio->head++]; |
| 211 | } | 211 | } |
| 212 | 212 | ||
| 213 | /* | 213 | /** |
| 214 | * Called when all DIO BIO I/O has been completed - let the filesystem | 214 | * dio_complete() - called when all DIO BIO I/O has been completed |
| 215 | * know, if it registered an interest earlier via get_block. Pass the | 215 | * @offset: the byte offset in the file of the completed operation |
| 216 | * private field of the map buffer_head so that filesystems can use it | 216 | * |
| 217 | * to hold additional state between get_block calls and dio_complete. | 217 | * This releases locks as dictated by the locking type, lets interested parties |
| 218 | * know that a DIO operation has completed, and calculates the resulting return | ||
| 219 | * code for the operation. | ||
| 220 | * | ||
| 221 | * It lets the filesystem know if it registered an interest earlier via | ||
| 222 | * get_block. Pass the private field of the map buffer_head so that | ||
| 223 | * filesystems can use it to hold additional state between get_block calls and | ||
| 224 | * dio_complete. | ||
| 218 | */ | 225 | */ |
| 219 | static void dio_complete(struct dio *dio, loff_t offset, ssize_t bytes) | 226 | static int dio_complete(struct dio *dio, loff_t offset, int ret) |
| 220 | { | 227 | { |
| 228 | ssize_t transferred = 0; | ||
| 229 | |||
| 230 | if (dio->result) { | ||
| 231 | transferred = dio->result; | ||
| 232 | |||
| 233 | /* Check for short read case */ | ||
| 234 | if ((dio->rw == READ) && ((offset + transferred) > dio->i_size)) | ||
| 235 | transferred = dio->i_size - offset; | ||
| 236 | } | ||
| 237 | |||
| 221 | if (dio->end_io && dio->result) | 238 | if (dio->end_io && dio->result) |
| 222 | dio->end_io(dio->iocb, offset, bytes, dio->map_bh.b_private); | 239 | dio->end_io(dio->iocb, offset, transferred, |
| 240 | dio->map_bh.b_private); | ||
| 223 | if (dio->lock_type == DIO_LOCKING) | 241 | if (dio->lock_type == DIO_LOCKING) |
| 224 | /* lockdep: non-owner release */ | 242 | /* lockdep: non-owner release */ |
| 225 | up_read_non_owner(&dio->inode->i_alloc_sem); | 243 | up_read_non_owner(&dio->inode->i_alloc_sem); |
| 244 | |||
| 245 | if (ret == 0) | ||
| 246 | ret = dio->page_errors; | ||
| 247 | if (ret == 0) | ||
| 248 | ret = dio->io_error; | ||
| 249 | if (ret == 0) | ||
| 250 | ret = transferred; | ||
| 251 | |||
| 252 | return ret; | ||
| 226 | } | 253 | } |
| 227 | 254 | ||
| 228 | /* | 255 | /* |
| @@ -236,8 +263,7 @@ static void finished_one_bio(struct dio *dio) | |||
| 236 | spin_lock_irqsave(&dio->bio_lock, flags); | 263 | spin_lock_irqsave(&dio->bio_lock, flags); |
| 237 | if (dio->bio_count == 1) { | 264 | if (dio->bio_count == 1) { |
| 238 | if (dio->is_async) { | 265 | if (dio->is_async) { |
| 239 | ssize_t transferred; | 266 | int ret; |
| 240 | loff_t offset; | ||
| 241 | 267 | ||
| 242 | /* | 268 | /* |
| 243 | * Last reference to the dio is going away. | 269 | * Last reference to the dio is going away. |
| @@ -245,24 +271,12 @@ static void finished_one_bio(struct dio *dio) | |||
| 245 | */ | 271 | */ |
| 246 | spin_unlock_irqrestore(&dio->bio_lock, flags); | 272 | spin_unlock_irqrestore(&dio->bio_lock, flags); |
| 247 | 273 | ||
| 248 | /* Check for short read case */ | 274 | ret = dio_complete(dio, dio->iocb->ki_pos, 0); |
| 249 | transferred = dio->result; | ||
| 250 | offset = dio->iocb->ki_pos; | ||
| 251 | |||
| 252 | if ((dio->rw == READ) && | ||
| 253 | ((offset + transferred) > dio->i_size)) | ||
| 254 | transferred = dio->i_size - offset; | ||
| 255 | |||
| 256 | /* check for error in completion path */ | ||
| 257 | if (dio->io_error) | ||
| 258 | transferred = dio->io_error; | ||
| 259 | |||
| 260 | dio_complete(dio, offset, transferred); | ||
| 261 | 275 | ||
| 262 | /* Complete AIO later if falling back to buffered i/o */ | 276 | /* Complete AIO later if falling back to buffered i/o */ |
| 263 | if (dio->result == dio->size || | 277 | if (dio->result == dio->size || |
| 264 | ((dio->rw == READ) && dio->result)) { | 278 | ((dio->rw == READ) && dio->result)) { |
| 265 | aio_complete(dio->iocb, transferred, 0); | 279 | aio_complete(dio->iocb, ret, 0); |
| 266 | kfree(dio); | 280 | kfree(dio); |
| 267 | return; | 281 | return; |
| 268 | } else { | 282 | } else { |
| @@ -434,10 +448,8 @@ static int dio_bio_complete(struct dio *dio, struct bio *bio) | |||
| 434 | /* | 448 | /* |
| 435 | * Wait on and process all in-flight BIOs. | 449 | * Wait on and process all in-flight BIOs. |
| 436 | */ | 450 | */ |
| 437 | static int dio_await_completion(struct dio *dio) | 451 | static void dio_await_completion(struct dio *dio) |
| 438 | { | 452 | { |
| 439 | int ret = 0; | ||
| 440 | |||
| 441 | if (dio->bio) | 453 | if (dio->bio) |
| 442 | dio_bio_submit(dio); | 454 | dio_bio_submit(dio); |
| 443 | 455 | ||
| @@ -448,13 +460,9 @@ static int dio_await_completion(struct dio *dio) | |||
| 448 | */ | 460 | */ |
| 449 | while (dio->bio_count) { | 461 | while (dio->bio_count) { |
| 450 | struct bio *bio = dio_await_one(dio); | 462 | struct bio *bio = dio_await_one(dio); |
| 451 | int ret2; | 463 | /* io errors are propogated through dio->io_error */ |
| 452 | 464 | dio_bio_complete(dio, bio); | |
| 453 | ret2 = dio_bio_complete(dio, bio); | ||
| 454 | if (ret == 0) | ||
| 455 | ret = ret2; | ||
| 456 | } | 465 | } |
| 457 | return ret; | ||
| 458 | } | 466 | } |
| 459 | 467 | ||
| 460 | /* | 468 | /* |
| @@ -1127,28 +1135,10 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode, | |||
| 1127 | kfree(dio); | 1135 | kfree(dio); |
| 1128 | } | 1136 | } |
| 1129 | } else { | 1137 | } else { |
| 1130 | ssize_t transferred = 0; | ||
| 1131 | |||
| 1132 | finished_one_bio(dio); | 1138 | finished_one_bio(dio); |
| 1133 | ret2 = dio_await_completion(dio); | 1139 | dio_await_completion(dio); |
| 1134 | if (ret == 0) | ||
| 1135 | ret = ret2; | ||
| 1136 | if (ret == 0) | ||
| 1137 | ret = dio->page_errors; | ||
| 1138 | if (dio->result) { | ||
| 1139 | loff_t i_size = i_size_read(inode); | ||
| 1140 | 1140 | ||
| 1141 | transferred = dio->result; | 1141 | ret = dio_complete(dio, offset, ret); |
| 1142 | /* | ||
| 1143 | * Adjust the return value if the read crossed a | ||
| 1144 | * non-block-aligned EOF. | ||
| 1145 | */ | ||
| 1146 | if (rw == READ && (offset + transferred > i_size)) | ||
| 1147 | transferred = i_size - offset; | ||
| 1148 | } | ||
| 1149 | dio_complete(dio, offset, transferred); | ||
| 1150 | if (ret == 0) | ||
| 1151 | ret = transferred; | ||
| 1152 | 1142 | ||
| 1153 | /* We could have also come here on an AIO file extend */ | 1143 | /* We could have also come here on an AIO file extend */ |
| 1154 | if (!is_sync_kiocb(iocb) && (rw & WRITE) && | 1144 | if (!is_sync_kiocb(iocb) && (rw & WRITE) && |
