diff options
Diffstat (limited to 'fs/ext4/file.c')
-rw-r--r-- | fs/ext4/file.c | 129 |
1 files changed, 49 insertions, 80 deletions
diff --git a/fs/ext4/file.c b/fs/ext4/file.c index 4cd318f31cbe..6659e216385e 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c | |||
@@ -93,31 +93,29 @@ ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from) | |||
93 | { | 93 | { |
94 | struct file *file = iocb->ki_filp; | 94 | struct file *file = iocb->ki_filp; |
95 | struct inode *inode = file_inode(iocb->ki_filp); | 95 | struct inode *inode = file_inode(iocb->ki_filp); |
96 | struct mutex *aio_mutex = NULL; | ||
97 | struct blk_plug plug; | 96 | struct blk_plug plug; |
98 | int o_direct = iocb->ki_flags & IOCB_DIRECT; | 97 | int o_direct = iocb->ki_flags & IOCB_DIRECT; |
98 | int unaligned_aio = 0; | ||
99 | int overwrite = 0; | 99 | int overwrite = 0; |
100 | ssize_t ret; | 100 | ssize_t ret; |
101 | 101 | ||
102 | inode_lock(inode); | ||
103 | ret = generic_write_checks(iocb, from); | ||
104 | if (ret <= 0) | ||
105 | goto out; | ||
106 | |||
102 | /* | 107 | /* |
103 | * Unaligned direct AIO must be serialized; see comment above | 108 | * Unaligned direct AIO must be serialized among each other as zeroing |
104 | * In the case of O_APPEND, assume that we must always serialize | 109 | * of partial blocks of two competing unaligned AIOs can result in data |
110 | * corruption. | ||
105 | */ | 111 | */ |
106 | if (o_direct && | 112 | if (o_direct && ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS) && |
107 | ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS) && | ||
108 | !is_sync_kiocb(iocb) && | 113 | !is_sync_kiocb(iocb) && |
109 | (iocb->ki_flags & IOCB_APPEND || | 114 | ext4_unaligned_aio(inode, from, iocb->ki_pos)) { |
110 | ext4_unaligned_aio(inode, from, iocb->ki_pos))) { | 115 | unaligned_aio = 1; |
111 | aio_mutex = ext4_aio_mutex(inode); | ||
112 | mutex_lock(aio_mutex); | ||
113 | ext4_unwritten_wait(inode); | 116 | ext4_unwritten_wait(inode); |
114 | } | 117 | } |
115 | 118 | ||
116 | inode_lock(inode); | ||
117 | ret = generic_write_checks(iocb, from); | ||
118 | if (ret <= 0) | ||
119 | goto out; | ||
120 | |||
121 | /* | 119 | /* |
122 | * If we have encountered a bitmap-format file, the size limit | 120 | * If we have encountered a bitmap-format file, the size limit |
123 | * is smaller than s_maxbytes, which is for extent-mapped files. | 121 | * is smaller than s_maxbytes, which is for extent-mapped files. |
@@ -139,7 +137,7 @@ ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from) | |||
139 | blk_start_plug(&plug); | 137 | blk_start_plug(&plug); |
140 | 138 | ||
141 | /* check whether we do a DIO overwrite or not */ | 139 | /* check whether we do a DIO overwrite or not */ |
142 | if (ext4_should_dioread_nolock(inode) && !aio_mutex && | 140 | if (ext4_should_dioread_nolock(inode) && !unaligned_aio && |
143 | !file->f_mapping->nrpages && pos + length <= i_size_read(inode)) { | 141 | !file->f_mapping->nrpages && pos + length <= i_size_read(inode)) { |
144 | struct ext4_map_blocks map; | 142 | struct ext4_map_blocks map; |
145 | unsigned int blkbits = inode->i_blkbits; | 143 | unsigned int blkbits = inode->i_blkbits; |
@@ -181,14 +179,10 @@ ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from) | |||
181 | if (o_direct) | 179 | if (o_direct) |
182 | blk_finish_plug(&plug); | 180 | blk_finish_plug(&plug); |
183 | 181 | ||
184 | if (aio_mutex) | ||
185 | mutex_unlock(aio_mutex); | ||
186 | return ret; | 182 | return ret; |
187 | 183 | ||
188 | out: | 184 | out: |
189 | inode_unlock(inode); | 185 | inode_unlock(inode); |
190 | if (aio_mutex) | ||
191 | mutex_unlock(aio_mutex); | ||
192 | return ret; | 186 | return ret; |
193 | } | 187 | } |
194 | 188 | ||
@@ -417,7 +411,7 @@ static int ext4_file_open(struct inode * inode, struct file * filp) | |||
417 | */ | 411 | */ |
418 | static int ext4_find_unwritten_pgoff(struct inode *inode, | 412 | static int ext4_find_unwritten_pgoff(struct inode *inode, |
419 | int whence, | 413 | int whence, |
420 | struct ext4_map_blocks *map, | 414 | ext4_lblk_t end_blk, |
421 | loff_t *offset) | 415 | loff_t *offset) |
422 | { | 416 | { |
423 | struct pagevec pvec; | 417 | struct pagevec pvec; |
@@ -432,7 +426,7 @@ static int ext4_find_unwritten_pgoff(struct inode *inode, | |||
432 | blkbits = inode->i_sb->s_blocksize_bits; | 426 | blkbits = inode->i_sb->s_blocksize_bits; |
433 | startoff = *offset; | 427 | startoff = *offset; |
434 | lastoff = startoff; | 428 | lastoff = startoff; |
435 | endoff = (loff_t)(map->m_lblk + map->m_len) << blkbits; | 429 | endoff = (loff_t)end_blk << blkbits; |
436 | 430 | ||
437 | index = startoff >> PAGE_CACHE_SHIFT; | 431 | index = startoff >> PAGE_CACHE_SHIFT; |
438 | end = endoff >> PAGE_CACHE_SHIFT; | 432 | end = endoff >> PAGE_CACHE_SHIFT; |
@@ -550,12 +544,11 @@ out: | |||
550 | static loff_t ext4_seek_data(struct file *file, loff_t offset, loff_t maxsize) | 544 | static loff_t ext4_seek_data(struct file *file, loff_t offset, loff_t maxsize) |
551 | { | 545 | { |
552 | struct inode *inode = file->f_mapping->host; | 546 | struct inode *inode = file->f_mapping->host; |
553 | struct ext4_map_blocks map; | ||
554 | struct extent_status es; | 547 | struct extent_status es; |
555 | ext4_lblk_t start, last, end; | 548 | ext4_lblk_t start, last, end; |
556 | loff_t dataoff, isize; | 549 | loff_t dataoff, isize; |
557 | int blkbits; | 550 | int blkbits; |
558 | int ret = 0; | 551 | int ret; |
559 | 552 | ||
560 | inode_lock(inode); | 553 | inode_lock(inode); |
561 | 554 | ||
@@ -572,41 +565,32 @@ static loff_t ext4_seek_data(struct file *file, loff_t offset, loff_t maxsize) | |||
572 | dataoff = offset; | 565 | dataoff = offset; |
573 | 566 | ||
574 | do { | 567 | do { |
575 | map.m_lblk = last; | 568 | ret = ext4_get_next_extent(inode, last, end - last + 1, &es); |
576 | map.m_len = end - last + 1; | 569 | if (ret <= 0) { |
577 | ret = ext4_map_blocks(NULL, inode, &map, 0); | 570 | /* No extent found -> no data */ |
578 | if (ret > 0 && !(map.m_flags & EXT4_MAP_UNWRITTEN)) { | 571 | if (ret == 0) |
579 | if (last != start) | 572 | ret = -ENXIO; |
580 | dataoff = (loff_t)last << blkbits; | 573 | inode_unlock(inode); |
581 | break; | 574 | return ret; |
582 | } | 575 | } |
583 | 576 | ||
584 | /* | 577 | last = es.es_lblk; |
585 | * If there is a delay extent at this offset, | 578 | if (last != start) |
586 | * it will be as a data. | 579 | dataoff = (loff_t)last << blkbits; |
587 | */ | 580 | if (!ext4_es_is_unwritten(&es)) |
588 | ext4_es_find_delayed_extent_range(inode, last, last, &es); | ||
589 | if (es.es_len != 0 && in_range(last, es.es_lblk, es.es_len)) { | ||
590 | if (last != start) | ||
591 | dataoff = (loff_t)last << blkbits; | ||
592 | break; | 581 | break; |
593 | } | ||
594 | 582 | ||
595 | /* | 583 | /* |
596 | * If there is a unwritten extent at this offset, | 584 | * If there is a unwritten extent at this offset, |
597 | * it will be as a data or a hole according to page | 585 | * it will be as a data or a hole according to page |
598 | * cache that has data or not. | 586 | * cache that has data or not. |
599 | */ | 587 | */ |
600 | if (map.m_flags & EXT4_MAP_UNWRITTEN) { | 588 | if (ext4_find_unwritten_pgoff(inode, SEEK_DATA, |
601 | int unwritten; | 589 | es.es_lblk + es.es_len, &dataoff)) |
602 | unwritten = ext4_find_unwritten_pgoff(inode, SEEK_DATA, | 590 | break; |
603 | &map, &dataoff); | 591 | last += es.es_len; |
604 | if (unwritten) | ||
605 | break; | ||
606 | } | ||
607 | |||
608 | last++; | ||
609 | dataoff = (loff_t)last << blkbits; | 592 | dataoff = (loff_t)last << blkbits; |
593 | cond_resched(); | ||
610 | } while (last <= end); | 594 | } while (last <= end); |
611 | 595 | ||
612 | inode_unlock(inode); | 596 | inode_unlock(inode); |
@@ -623,12 +607,11 @@ static loff_t ext4_seek_data(struct file *file, loff_t offset, loff_t maxsize) | |||
623 | static loff_t ext4_seek_hole(struct file *file, loff_t offset, loff_t maxsize) | 607 | static loff_t ext4_seek_hole(struct file *file, loff_t offset, loff_t maxsize) |
624 | { | 608 | { |
625 | struct inode *inode = file->f_mapping->host; | 609 | struct inode *inode = file->f_mapping->host; |
626 | struct ext4_map_blocks map; | ||
627 | struct extent_status es; | 610 | struct extent_status es; |
628 | ext4_lblk_t start, last, end; | 611 | ext4_lblk_t start, last, end; |
629 | loff_t holeoff, isize; | 612 | loff_t holeoff, isize; |
630 | int blkbits; | 613 | int blkbits; |
631 | int ret = 0; | 614 | int ret; |
632 | 615 | ||
633 | inode_lock(inode); | 616 | inode_lock(inode); |
634 | 617 | ||
@@ -645,44 +628,30 @@ static loff_t ext4_seek_hole(struct file *file, loff_t offset, loff_t maxsize) | |||
645 | holeoff = offset; | 628 | holeoff = offset; |
646 | 629 | ||
647 | do { | 630 | do { |
648 | map.m_lblk = last; | 631 | ret = ext4_get_next_extent(inode, last, end - last + 1, &es); |
649 | map.m_len = end - last + 1; | 632 | if (ret < 0) { |
650 | ret = ext4_map_blocks(NULL, inode, &map, 0); | 633 | inode_unlock(inode); |
651 | if (ret > 0 && !(map.m_flags & EXT4_MAP_UNWRITTEN)) { | 634 | return ret; |
652 | last += ret; | ||
653 | holeoff = (loff_t)last << blkbits; | ||
654 | continue; | ||
655 | } | 635 | } |
656 | 636 | /* Found a hole? */ | |
657 | /* | 637 | if (ret == 0 || es.es_lblk > last) { |
658 | * If there is a delay extent at this offset, | 638 | if (last != start) |
659 | * we will skip this extent. | 639 | holeoff = (loff_t)last << blkbits; |
660 | */ | 640 | break; |
661 | ext4_es_find_delayed_extent_range(inode, last, last, &es); | ||
662 | if (es.es_len != 0 && in_range(last, es.es_lblk, es.es_len)) { | ||
663 | last = es.es_lblk + es.es_len; | ||
664 | holeoff = (loff_t)last << blkbits; | ||
665 | continue; | ||
666 | } | 641 | } |
667 | |||
668 | /* | 642 | /* |
669 | * If there is a unwritten extent at this offset, | 643 | * If there is a unwritten extent at this offset, |
670 | * it will be as a data or a hole according to page | 644 | * it will be as a data or a hole according to page |
671 | * cache that has data or not. | 645 | * cache that has data or not. |
672 | */ | 646 | */ |
673 | if (map.m_flags & EXT4_MAP_UNWRITTEN) { | 647 | if (ext4_es_is_unwritten(&es) && |
674 | int unwritten; | 648 | ext4_find_unwritten_pgoff(inode, SEEK_HOLE, |
675 | unwritten = ext4_find_unwritten_pgoff(inode, SEEK_HOLE, | 649 | last + es.es_len, &holeoff)) |
676 | &map, &holeoff); | 650 | break; |
677 | if (!unwritten) { | ||
678 | last += ret; | ||
679 | holeoff = (loff_t)last << blkbits; | ||
680 | continue; | ||
681 | } | ||
682 | } | ||
683 | 651 | ||
684 | /* find a hole */ | 652 | last += es.es_len; |
685 | break; | 653 | holeoff = (loff_t)last << blkbits; |
654 | cond_resched(); | ||
686 | } while (last <= end); | 655 | } while (last <= end); |
687 | 656 | ||
688 | inode_unlock(inode); | 657 | inode_unlock(inode); |