diff options
Diffstat (limited to 'fs/direct-io.c')
| -rw-r--r-- | fs/direct-io.c | 62 |
1 files changed, 55 insertions, 7 deletions
diff --git a/fs/direct-io.c b/fs/direct-io.c index e82adc2debb7..da111aacb46e 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c | |||
| @@ -82,6 +82,8 @@ struct dio { | |||
| 82 | int reap_counter; /* rate limit reaping */ | 82 | int reap_counter; /* rate limit reaping */ |
| 83 | get_block_t *get_block; /* block mapping function */ | 83 | get_block_t *get_block; /* block mapping function */ |
| 84 | dio_iodone_t *end_io; /* IO completion function */ | 84 | dio_iodone_t *end_io; /* IO completion function */ |
| 85 | dio_submit_t *submit_io; /* IO submition function */ | ||
| 86 | loff_t logical_offset_in_bio; /* current first logical block in bio */ | ||
| 85 | sector_t final_block_in_bio; /* current final block in bio + 1 */ | 87 | sector_t final_block_in_bio; /* current final block in bio + 1 */ |
| 86 | sector_t next_block_for_io; /* next block to be put under IO, | 88 | sector_t next_block_for_io; /* next block to be put under IO, |
| 87 | in dio_blocks units */ | 89 | in dio_blocks units */ |
| @@ -96,6 +98,7 @@ struct dio { | |||
| 96 | unsigned cur_page_offset; /* Offset into it, in bytes */ | 98 | unsigned cur_page_offset; /* Offset into it, in bytes */ |
| 97 | unsigned cur_page_len; /* Nr of bytes at cur_page_offset */ | 99 | unsigned cur_page_len; /* Nr of bytes at cur_page_offset */ |
| 98 | sector_t cur_page_block; /* Where it starts */ | 100 | sector_t cur_page_block; /* Where it starts */ |
| 101 | loff_t cur_page_fs_offset; /* Offset in file */ | ||
| 99 | 102 | ||
| 100 | /* BIO completion state */ | 103 | /* BIO completion state */ |
| 101 | spinlock_t bio_lock; /* protects BIO fields below */ | 104 | spinlock_t bio_lock; /* protects BIO fields below */ |
| @@ -300,6 +303,26 @@ static void dio_bio_end_io(struct bio *bio, int error) | |||
| 300 | spin_unlock_irqrestore(&dio->bio_lock, flags); | 303 | spin_unlock_irqrestore(&dio->bio_lock, flags); |
| 301 | } | 304 | } |
| 302 | 305 | ||
| 306 | /** | ||
| 307 | * dio_end_io - handle the end io action for the given bio | ||
| 308 | * @bio: The direct io bio thats being completed | ||
| 309 | * @error: Error if there was one | ||
| 310 | * | ||
| 311 | * This is meant to be called by any filesystem that uses their own dio_submit_t | ||
| 312 | * so that the DIO specific endio actions are dealt with after the filesystem | ||
| 313 | * has done it's completion work. | ||
| 314 | */ | ||
| 315 | void dio_end_io(struct bio *bio, int error) | ||
| 316 | { | ||
| 317 | struct dio *dio = bio->bi_private; | ||
| 318 | |||
| 319 | if (dio->is_async) | ||
| 320 | dio_bio_end_aio(bio, error); | ||
| 321 | else | ||
| 322 | dio_bio_end_io(bio, error); | ||
| 323 | } | ||
| 324 | EXPORT_SYMBOL_GPL(dio_end_io); | ||
| 325 | |||
| 303 | static int | 326 | static int |
| 304 | dio_bio_alloc(struct dio *dio, struct block_device *bdev, | 327 | dio_bio_alloc(struct dio *dio, struct block_device *bdev, |
| 305 | sector_t first_sector, int nr_vecs) | 328 | sector_t first_sector, int nr_vecs) |
| @@ -316,6 +339,7 @@ dio_bio_alloc(struct dio *dio, struct block_device *bdev, | |||
| 316 | bio->bi_end_io = dio_bio_end_io; | 339 | bio->bi_end_io = dio_bio_end_io; |
| 317 | 340 | ||
| 318 | dio->bio = bio; | 341 | dio->bio = bio; |
| 342 | dio->logical_offset_in_bio = dio->cur_page_fs_offset; | ||
| 319 | return 0; | 343 | return 0; |
| 320 | } | 344 | } |
| 321 | 345 | ||
| @@ -340,10 +364,15 @@ static void dio_bio_submit(struct dio *dio) | |||
| 340 | if (dio->is_async && dio->rw == READ) | 364 | if (dio->is_async && dio->rw == READ) |
| 341 | bio_set_pages_dirty(bio); | 365 | bio_set_pages_dirty(bio); |
| 342 | 366 | ||
| 343 | submit_bio(dio->rw, bio); | 367 | if (dio->submit_io) |
| 368 | dio->submit_io(dio->rw, bio, dio->inode, | ||
| 369 | dio->logical_offset_in_bio); | ||
| 370 | else | ||
| 371 | submit_bio(dio->rw, bio); | ||
| 344 | 372 | ||
| 345 | dio->bio = NULL; | 373 | dio->bio = NULL; |
| 346 | dio->boundary = 0; | 374 | dio->boundary = 0; |
| 375 | dio->logical_offset_in_bio = 0; | ||
| 347 | } | 376 | } |
| 348 | 377 | ||
| 349 | /* | 378 | /* |
| @@ -603,10 +632,26 @@ static int dio_send_cur_page(struct dio *dio) | |||
| 603 | int ret = 0; | 632 | int ret = 0; |
| 604 | 633 | ||
| 605 | if (dio->bio) { | 634 | if (dio->bio) { |
| 635 | loff_t cur_offset = dio->block_in_file << dio->blkbits; | ||
| 636 | loff_t bio_next_offset = dio->logical_offset_in_bio + | ||
| 637 | dio->bio->bi_size; | ||
| 638 | |||
| 606 | /* | 639 | /* |
| 607 | * See whether this new request is contiguous with the old | 640 | * See whether this new request is contiguous with the old. |
| 641 | * | ||
| 642 | * Btrfs cannot handl having logically non-contiguous requests | ||
| 643 | * submitted. For exmple if you have | ||
| 644 | * | ||
| 645 | * Logical: [0-4095][HOLE][8192-12287] | ||
| 646 | * Phyiscal: [0-4095] [4096-8181] | ||
| 647 | * | ||
| 648 | * We cannot submit those pages together as one BIO. So if our | ||
| 649 | * current logical offset in the file does not equal what would | ||
| 650 | * be the next logical offset in the bio, submit the bio we | ||
| 651 | * have. | ||
| 608 | */ | 652 | */ |
| 609 | if (dio->final_block_in_bio != dio->cur_page_block) | 653 | if (dio->final_block_in_bio != dio->cur_page_block || |
| 654 | cur_offset != bio_next_offset) | ||
| 610 | dio_bio_submit(dio); | 655 | dio_bio_submit(dio); |
| 611 | /* | 656 | /* |
| 612 | * Submit now if the underlying fs is about to perform a | 657 | * Submit now if the underlying fs is about to perform a |
| @@ -701,6 +746,7 @@ submit_page_section(struct dio *dio, struct page *page, | |||
| 701 | dio->cur_page_offset = offset; | 746 | dio->cur_page_offset = offset; |
| 702 | dio->cur_page_len = len; | 747 | dio->cur_page_len = len; |
| 703 | dio->cur_page_block = blocknr; | 748 | dio->cur_page_block = blocknr; |
| 749 | dio->cur_page_fs_offset = dio->block_in_file << dio->blkbits; | ||
| 704 | out: | 750 | out: |
| 705 | return ret; | 751 | return ret; |
| 706 | } | 752 | } |
| @@ -935,7 +981,7 @@ static ssize_t | |||
| 935 | direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode, | 981 | direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode, |
| 936 | const struct iovec *iov, loff_t offset, unsigned long nr_segs, | 982 | const struct iovec *iov, loff_t offset, unsigned long nr_segs, |
| 937 | unsigned blkbits, get_block_t get_block, dio_iodone_t end_io, | 983 | unsigned blkbits, get_block_t get_block, dio_iodone_t end_io, |
| 938 | struct dio *dio) | 984 | dio_submit_t submit_io, struct dio *dio) |
| 939 | { | 985 | { |
| 940 | unsigned long user_addr; | 986 | unsigned long user_addr; |
| 941 | unsigned long flags; | 987 | unsigned long flags; |
| @@ -952,6 +998,7 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode, | |||
| 952 | 998 | ||
| 953 | dio->get_block = get_block; | 999 | dio->get_block = get_block; |
| 954 | dio->end_io = end_io; | 1000 | dio->end_io = end_io; |
| 1001 | dio->submit_io = submit_io; | ||
| 955 | dio->final_block_in_bio = -1; | 1002 | dio->final_block_in_bio = -1; |
| 956 | dio->next_block_for_io = -1; | 1003 | dio->next_block_for_io = -1; |
| 957 | 1004 | ||
| @@ -1008,7 +1055,7 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode, | |||
| 1008 | } | 1055 | } |
| 1009 | } /* end iovec loop */ | 1056 | } /* end iovec loop */ |
| 1010 | 1057 | ||
| 1011 | if (ret == -ENOTBLK && (rw & WRITE)) { | 1058 | if (ret == -ENOTBLK) { |
| 1012 | /* | 1059 | /* |
| 1013 | * The remaining part of the request will be | 1060 | * The remaining part of the request will be |
| 1014 | * be handled by buffered I/O when we return | 1061 | * be handled by buffered I/O when we return |
| @@ -1110,7 +1157,7 @@ ssize_t | |||
| 1110 | __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, | 1157 | __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, |
| 1111 | struct block_device *bdev, const struct iovec *iov, loff_t offset, | 1158 | struct block_device *bdev, const struct iovec *iov, loff_t offset, |
| 1112 | unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io, | 1159 | unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io, |
| 1113 | int flags) | 1160 | dio_submit_t submit_io, int flags) |
| 1114 | { | 1161 | { |
| 1115 | int seg; | 1162 | int seg; |
| 1116 | size_t size; | 1163 | size_t size; |
| @@ -1197,7 +1244,8 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, | |||
| 1197 | (end > i_size_read(inode))); | 1244 | (end > i_size_read(inode))); |
| 1198 | 1245 | ||
| 1199 | retval = direct_io_worker(rw, iocb, inode, iov, offset, | 1246 | retval = direct_io_worker(rw, iocb, inode, iov, offset, |
| 1200 | nr_segs, blkbits, get_block, end_io, dio); | 1247 | nr_segs, blkbits, get_block, end_io, |
| 1248 | submit_io, dio); | ||
| 1201 | 1249 | ||
| 1202 | /* | 1250 | /* |
| 1203 | * In case of error extending write may have instantiated a few | 1251 | * In case of error extending write may have instantiated a few |
