diff options
Diffstat (limited to 'fs/ext4/move_extent.c')
-rw-r--r-- | fs/ext4/move_extent.c | 282 |
1 files changed, 133 insertions, 149 deletions
diff --git a/fs/ext4/move_extent.c b/fs/ext4/move_extent.c index 25b6b1457360..82c415be87a4 100644 --- a/fs/ext4/move_extent.c +++ b/fs/ext4/move_extent.c | |||
@@ -77,12 +77,14 @@ static int | |||
77 | mext_next_extent(struct inode *inode, struct ext4_ext_path *path, | 77 | mext_next_extent(struct inode *inode, struct ext4_ext_path *path, |
78 | struct ext4_extent **extent) | 78 | struct ext4_extent **extent) |
79 | { | 79 | { |
80 | struct ext4_extent_header *eh; | ||
80 | int ppos, leaf_ppos = path->p_depth; | 81 | int ppos, leaf_ppos = path->p_depth; |
81 | 82 | ||
82 | ppos = leaf_ppos; | 83 | ppos = leaf_ppos; |
83 | if (EXT_LAST_EXTENT(path[ppos].p_hdr) > path[ppos].p_ext) { | 84 | if (EXT_LAST_EXTENT(path[ppos].p_hdr) > path[ppos].p_ext) { |
84 | /* leaf block */ | 85 | /* leaf block */ |
85 | *extent = ++path[ppos].p_ext; | 86 | *extent = ++path[ppos].p_ext; |
87 | path[ppos].p_block = ext_pblock(path[ppos].p_ext); | ||
86 | return 0; | 88 | return 0; |
87 | } | 89 | } |
88 | 90 | ||
@@ -119,9 +121,18 @@ mext_next_extent(struct inode *inode, struct ext4_ext_path *path, | |||
119 | ext_block_hdr(path[cur_ppos+1].p_bh); | 121 | ext_block_hdr(path[cur_ppos+1].p_bh); |
120 | } | 122 | } |
121 | 123 | ||
124 | path[leaf_ppos].p_ext = *extent = NULL; | ||
125 | |||
126 | eh = path[leaf_ppos].p_hdr; | ||
127 | if (le16_to_cpu(eh->eh_entries) == 0) | ||
128 | /* empty leaf is found */ | ||
129 | return -ENODATA; | ||
130 | |||
122 | /* leaf block */ | 131 | /* leaf block */ |
123 | path[leaf_ppos].p_ext = *extent = | 132 | path[leaf_ppos].p_ext = *extent = |
124 | EXT_FIRST_EXTENT(path[leaf_ppos].p_hdr); | 133 | EXT_FIRST_EXTENT(path[leaf_ppos].p_hdr); |
134 | path[leaf_ppos].p_block = | ||
135 | ext_pblock(path[leaf_ppos].p_ext); | ||
125 | return 0; | 136 | return 0; |
126 | } | 137 | } |
127 | } | 138 | } |
@@ -155,40 +166,15 @@ mext_check_null_inode(struct inode *inode1, struct inode *inode2, | |||
155 | } | 166 | } |
156 | 167 | ||
157 | /** | 168 | /** |
158 | * mext_double_down_read - Acquire two inodes' read semaphore | 169 | * double_down_write_data_sem - Acquire two inodes' write lock of i_data_sem |
159 | * | ||
160 | * @orig_inode: original inode structure | ||
161 | * @donor_inode: donor inode structure | ||
162 | * Acquire read semaphore of the two inodes (orig and donor) by i_ino order. | ||
163 | */ | ||
164 | static void | ||
165 | mext_double_down_read(struct inode *orig_inode, struct inode *donor_inode) | ||
166 | { | ||
167 | struct inode *first = orig_inode, *second = donor_inode; | ||
168 | |||
169 | /* | ||
170 | * Use the inode number to provide the stable locking order instead | ||
171 | * of its address, because the C language doesn't guarantee you can | ||
172 | * compare pointers that don't come from the same array. | ||
173 | */ | ||
174 | if (donor_inode->i_ino < orig_inode->i_ino) { | ||
175 | first = donor_inode; | ||
176 | second = orig_inode; | ||
177 | } | ||
178 | |||
179 | down_read(&EXT4_I(first)->i_data_sem); | ||
180 | down_read(&EXT4_I(second)->i_data_sem); | ||
181 | } | ||
182 | |||
183 | /** | ||
184 | * mext_double_down_write - Acquire two inodes' write semaphore | ||
185 | * | 170 | * |
186 | * @orig_inode: original inode structure | 171 | * @orig_inode: original inode structure |
187 | * @donor_inode: donor inode structure | 172 | * @donor_inode: donor inode structure |
188 | * Acquire write semaphore of the two inodes (orig and donor) by i_ino order. | 173 | * Acquire write lock of i_data_sem of the two inodes (orig and donor) by |
174 | * i_ino order. | ||
189 | */ | 175 | */ |
190 | static void | 176 | static void |
191 | mext_double_down_write(struct inode *orig_inode, struct inode *donor_inode) | 177 | double_down_write_data_sem(struct inode *orig_inode, struct inode *donor_inode) |
192 | { | 178 | { |
193 | struct inode *first = orig_inode, *second = donor_inode; | 179 | struct inode *first = orig_inode, *second = donor_inode; |
194 | 180 | ||
@@ -203,32 +189,18 @@ mext_double_down_write(struct inode *orig_inode, struct inode *donor_inode) | |||
203 | } | 189 | } |
204 | 190 | ||
205 | down_write(&EXT4_I(first)->i_data_sem); | 191 | down_write(&EXT4_I(first)->i_data_sem); |
206 | down_write(&EXT4_I(second)->i_data_sem); | 192 | down_write_nested(&EXT4_I(second)->i_data_sem, SINGLE_DEPTH_NESTING); |
207 | } | 193 | } |
208 | 194 | ||
209 | /** | 195 | /** |
210 | * mext_double_up_read - Release two inodes' read semaphore | 196 | * double_up_write_data_sem - Release two inodes' write lock of i_data_sem |
211 | * | 197 | * |
212 | * @orig_inode: original inode structure to be released its lock first | 198 | * @orig_inode: original inode structure to be released its lock first |
213 | * @donor_inode: donor inode structure to be released its lock second | 199 | * @donor_inode: donor inode structure to be released its lock second |
214 | * Release read semaphore of two inodes (orig and donor). | 200 | * Release write lock of i_data_sem of two inodes (orig and donor). |
215 | */ | 201 | */ |
216 | static void | 202 | static void |
217 | mext_double_up_read(struct inode *orig_inode, struct inode *donor_inode) | 203 | double_up_write_data_sem(struct inode *orig_inode, struct inode *donor_inode) |
218 | { | ||
219 | up_read(&EXT4_I(orig_inode)->i_data_sem); | ||
220 | up_read(&EXT4_I(donor_inode)->i_data_sem); | ||
221 | } | ||
222 | |||
223 | /** | ||
224 | * mext_double_up_write - Release two inodes' write semaphore | ||
225 | * | ||
226 | * @orig_inode: original inode structure to be released its lock first | ||
227 | * @donor_inode: donor inode structure to be released its lock second | ||
228 | * Release write semaphore of two inodes (orig and donor). | ||
229 | */ | ||
230 | static void | ||
231 | mext_double_up_write(struct inode *orig_inode, struct inode *donor_inode) | ||
232 | { | 204 | { |
233 | up_write(&EXT4_I(orig_inode)->i_data_sem); | 205 | up_write(&EXT4_I(orig_inode)->i_data_sem); |
234 | up_write(&EXT4_I(donor_inode)->i_data_sem); | 206 | up_write(&EXT4_I(donor_inode)->i_data_sem); |
@@ -596,7 +568,7 @@ out: | |||
596 | * @tmp_oext: the extent that will belong to the donor inode | 568 | * @tmp_oext: the extent that will belong to the donor inode |
597 | * @orig_off: block offset of original inode | 569 | * @orig_off: block offset of original inode |
598 | * @donor_off: block offset of donor inode | 570 | * @donor_off: block offset of donor inode |
599 | * @max_count: the maximun length of extents | 571 | * @max_count: the maximum length of extents |
600 | * | 572 | * |
601 | * Return 0 on success, or a negative error value on failure. | 573 | * Return 0 on success, or a negative error value on failure. |
602 | */ | 574 | */ |
@@ -661,6 +633,7 @@ mext_calc_swap_extents(struct ext4_extent *tmp_dext, | |||
661 | * @donor_inode: donor inode | 633 | * @donor_inode: donor inode |
662 | * @from: block offset of orig_inode | 634 | * @from: block offset of orig_inode |
663 | * @count: block count to be replaced | 635 | * @count: block count to be replaced |
636 | * @err: pointer to save return value | ||
664 | * | 637 | * |
665 | * Replace original inode extents and donor inode extents page by page. | 638 | * Replace original inode extents and donor inode extents page by page. |
666 | * We implement this replacement in the following three steps: | 639 | * We implement this replacement in the following three steps: |
@@ -671,33 +644,33 @@ mext_calc_swap_extents(struct ext4_extent *tmp_dext, | |||
671 | * 3. Change the block information of donor inode to point at the saved | 644 | * 3. Change the block information of donor inode to point at the saved |
672 | * original inode blocks in the dummy extents. | 645 | * original inode blocks in the dummy extents. |
673 | * | 646 | * |
674 | * Return 0 on success, or a negative error value on failure. | 647 | * Return replaced block count. |
675 | */ | 648 | */ |
676 | static int | 649 | static int |
677 | mext_replace_branches(handle_t *handle, struct inode *orig_inode, | 650 | mext_replace_branches(handle_t *handle, struct inode *orig_inode, |
678 | struct inode *donor_inode, ext4_lblk_t from, | 651 | struct inode *donor_inode, ext4_lblk_t from, |
679 | ext4_lblk_t count) | 652 | ext4_lblk_t count, int *err) |
680 | { | 653 | { |
681 | struct ext4_ext_path *orig_path = NULL; | 654 | struct ext4_ext_path *orig_path = NULL; |
682 | struct ext4_ext_path *donor_path = NULL; | 655 | struct ext4_ext_path *donor_path = NULL; |
683 | struct ext4_extent *oext, *dext; | 656 | struct ext4_extent *oext, *dext; |
684 | struct ext4_extent tmp_dext, tmp_oext; | 657 | struct ext4_extent tmp_dext, tmp_oext; |
685 | ext4_lblk_t orig_off = from, donor_off = from; | 658 | ext4_lblk_t orig_off = from, donor_off = from; |
686 | int err = 0; | ||
687 | int depth; | 659 | int depth; |
688 | int replaced_count = 0; | 660 | int replaced_count = 0; |
689 | int dext_alen; | 661 | int dext_alen; |
690 | 662 | ||
691 | mext_double_down_write(orig_inode, donor_inode); | 663 | /* Protect extent trees against block allocations via delalloc */ |
664 | double_down_write_data_sem(orig_inode, donor_inode); | ||
692 | 665 | ||
693 | /* Get the original extent for the block "orig_off" */ | 666 | /* Get the original extent for the block "orig_off" */ |
694 | err = get_ext_path(orig_inode, orig_off, &orig_path); | 667 | *err = get_ext_path(orig_inode, orig_off, &orig_path); |
695 | if (err) | 668 | if (*err) |
696 | goto out; | 669 | goto out; |
697 | 670 | ||
698 | /* Get the donor extent for the head */ | 671 | /* Get the donor extent for the head */ |
699 | err = get_ext_path(donor_inode, donor_off, &donor_path); | 672 | *err = get_ext_path(donor_inode, donor_off, &donor_path); |
700 | if (err) | 673 | if (*err) |
701 | goto out; | 674 | goto out; |
702 | depth = ext_depth(orig_inode); | 675 | depth = ext_depth(orig_inode); |
703 | oext = orig_path[depth].p_ext; | 676 | oext = orig_path[depth].p_ext; |
@@ -707,9 +680,9 @@ mext_replace_branches(handle_t *handle, struct inode *orig_inode, | |||
707 | dext = donor_path[depth].p_ext; | 680 | dext = donor_path[depth].p_ext; |
708 | tmp_dext = *dext; | 681 | tmp_dext = *dext; |
709 | 682 | ||
710 | err = mext_calc_swap_extents(&tmp_dext, &tmp_oext, orig_off, | 683 | *err = mext_calc_swap_extents(&tmp_dext, &tmp_oext, orig_off, |
711 | donor_off, count); | 684 | donor_off, count); |
712 | if (err) | 685 | if (*err) |
713 | goto out; | 686 | goto out; |
714 | 687 | ||
715 | /* Loop for the donor extents */ | 688 | /* Loop for the donor extents */ |
@@ -718,7 +691,7 @@ mext_replace_branches(handle_t *handle, struct inode *orig_inode, | |||
718 | if (!dext) { | 691 | if (!dext) { |
719 | ext4_error(donor_inode->i_sb, __func__, | 692 | ext4_error(donor_inode->i_sb, __func__, |
720 | "The extent for donor must be found"); | 693 | "The extent for donor must be found"); |
721 | err = -EIO; | 694 | *err = -EIO; |
722 | goto out; | 695 | goto out; |
723 | } else if (donor_off != le32_to_cpu(tmp_dext.ee_block)) { | 696 | } else if (donor_off != le32_to_cpu(tmp_dext.ee_block)) { |
724 | ext4_error(donor_inode->i_sb, __func__, | 697 | ext4_error(donor_inode->i_sb, __func__, |
@@ -726,20 +699,20 @@ mext_replace_branches(handle_t *handle, struct inode *orig_inode, | |||
726 | "extent(%u) should be equal", | 699 | "extent(%u) should be equal", |
727 | donor_off, | 700 | donor_off, |
728 | le32_to_cpu(tmp_dext.ee_block)); | 701 | le32_to_cpu(tmp_dext.ee_block)); |
729 | err = -EIO; | 702 | *err = -EIO; |
730 | goto out; | 703 | goto out; |
731 | } | 704 | } |
732 | 705 | ||
733 | /* Set donor extent to orig extent */ | 706 | /* Set donor extent to orig extent */ |
734 | err = mext_leaf_block(handle, orig_inode, | 707 | *err = mext_leaf_block(handle, orig_inode, |
735 | orig_path, &tmp_dext, &orig_off); | 708 | orig_path, &tmp_dext, &orig_off); |
736 | if (err < 0) | 709 | if (*err) |
737 | goto out; | 710 | goto out; |
738 | 711 | ||
739 | /* Set orig extent to donor extent */ | 712 | /* Set orig extent to donor extent */ |
740 | err = mext_leaf_block(handle, donor_inode, | 713 | *err = mext_leaf_block(handle, donor_inode, |
741 | donor_path, &tmp_oext, &donor_off); | 714 | donor_path, &tmp_oext, &donor_off); |
742 | if (err < 0) | 715 | if (*err) |
743 | goto out; | 716 | goto out; |
744 | 717 | ||
745 | dext_alen = ext4_ext_get_actual_len(&tmp_dext); | 718 | dext_alen = ext4_ext_get_actual_len(&tmp_dext); |
@@ -753,35 +726,25 @@ mext_replace_branches(handle_t *handle, struct inode *orig_inode, | |||
753 | 726 | ||
754 | if (orig_path) | 727 | if (orig_path) |
755 | ext4_ext_drop_refs(orig_path); | 728 | ext4_ext_drop_refs(orig_path); |
756 | err = get_ext_path(orig_inode, orig_off, &orig_path); | 729 | *err = get_ext_path(orig_inode, orig_off, &orig_path); |
757 | if (err) | 730 | if (*err) |
758 | goto out; | 731 | goto out; |
759 | depth = ext_depth(orig_inode); | 732 | depth = ext_depth(orig_inode); |
760 | oext = orig_path[depth].p_ext; | 733 | oext = orig_path[depth].p_ext; |
761 | if (le32_to_cpu(oext->ee_block) + | ||
762 | ext4_ext_get_actual_len(oext) <= orig_off) { | ||
763 | err = 0; | ||
764 | goto out; | ||
765 | } | ||
766 | tmp_oext = *oext; | 734 | tmp_oext = *oext; |
767 | 735 | ||
768 | if (donor_path) | 736 | if (donor_path) |
769 | ext4_ext_drop_refs(donor_path); | 737 | ext4_ext_drop_refs(donor_path); |
770 | err = get_ext_path(donor_inode, donor_off, &donor_path); | 738 | *err = get_ext_path(donor_inode, donor_off, &donor_path); |
771 | if (err) | 739 | if (*err) |
772 | goto out; | 740 | goto out; |
773 | depth = ext_depth(donor_inode); | 741 | depth = ext_depth(donor_inode); |
774 | dext = donor_path[depth].p_ext; | 742 | dext = donor_path[depth].p_ext; |
775 | if (le32_to_cpu(dext->ee_block) + | ||
776 | ext4_ext_get_actual_len(dext) <= donor_off) { | ||
777 | err = 0; | ||
778 | goto out; | ||
779 | } | ||
780 | tmp_dext = *dext; | 743 | tmp_dext = *dext; |
781 | 744 | ||
782 | err = mext_calc_swap_extents(&tmp_dext, &tmp_oext, orig_off, | 745 | *err = mext_calc_swap_extents(&tmp_dext, &tmp_oext, orig_off, |
783 | donor_off, count - replaced_count); | 746 | donor_off, count - replaced_count); |
784 | if (err) | 747 | if (*err) |
785 | goto out; | 748 | goto out; |
786 | } | 749 | } |
787 | 750 | ||
@@ -795,8 +758,12 @@ out: | |||
795 | kfree(donor_path); | 758 | kfree(donor_path); |
796 | } | 759 | } |
797 | 760 | ||
798 | mext_double_up_write(orig_inode, donor_inode); | 761 | ext4_ext_invalidate_cache(orig_inode); |
799 | return err; | 762 | ext4_ext_invalidate_cache(donor_inode); |
763 | |||
764 | double_up_write_data_sem(orig_inode, donor_inode); | ||
765 | |||
766 | return replaced_count; | ||
800 | } | 767 | } |
801 | 768 | ||
802 | /** | 769 | /** |
@@ -808,16 +775,17 @@ out: | |||
808 | * @data_offset_in_page: block index where data swapping starts | 775 | * @data_offset_in_page: block index where data swapping starts |
809 | * @block_len_in_page: the number of blocks to be swapped | 776 | * @block_len_in_page: the number of blocks to be swapped |
810 | * @uninit: orig extent is uninitialized or not | 777 | * @uninit: orig extent is uninitialized or not |
778 | * @err: pointer to save return value | ||
811 | * | 779 | * |
812 | * Save the data in original inode blocks and replace original inode extents | 780 | * Save the data in original inode blocks and replace original inode extents |
813 | * with donor inode extents by calling mext_replace_branches(). | 781 | * with donor inode extents by calling mext_replace_branches(). |
814 | * Finally, write out the saved data in new original inode blocks. Return 0 | 782 | * Finally, write out the saved data in new original inode blocks. Return |
815 | * on success, or a negative error value on failure. | 783 | * replaced block count. |
816 | */ | 784 | */ |
817 | static int | 785 | static int |
818 | move_extent_per_page(struct file *o_filp, struct inode *donor_inode, | 786 | move_extent_per_page(struct file *o_filp, struct inode *donor_inode, |
819 | pgoff_t orig_page_offset, int data_offset_in_page, | 787 | pgoff_t orig_page_offset, int data_offset_in_page, |
820 | int block_len_in_page, int uninit) | 788 | int block_len_in_page, int uninit, int *err) |
821 | { | 789 | { |
822 | struct inode *orig_inode = o_filp->f_dentry->d_inode; | 790 | struct inode *orig_inode = o_filp->f_dentry->d_inode; |
823 | struct address_space *mapping = orig_inode->i_mapping; | 791 | struct address_space *mapping = orig_inode->i_mapping; |
@@ -829,9 +797,11 @@ move_extent_per_page(struct file *o_filp, struct inode *donor_inode, | |||
829 | long long offs = orig_page_offset << PAGE_CACHE_SHIFT; | 797 | long long offs = orig_page_offset << PAGE_CACHE_SHIFT; |
830 | unsigned long blocksize = orig_inode->i_sb->s_blocksize; | 798 | unsigned long blocksize = orig_inode->i_sb->s_blocksize; |
831 | unsigned int w_flags = 0; | 799 | unsigned int w_flags = 0; |
832 | unsigned int tmp_data_len, data_len; | 800 | unsigned int tmp_data_size, data_size, replaced_size; |
833 | void *fsdata; | 801 | void *fsdata; |
834 | int ret, i, jblocks; | 802 | int i, jblocks; |
803 | int err2 = 0; | ||
804 | int replaced_count = 0; | ||
835 | int blocks_per_page = PAGE_CACHE_SIZE >> orig_inode->i_blkbits; | 805 | int blocks_per_page = PAGE_CACHE_SIZE >> orig_inode->i_blkbits; |
836 | 806 | ||
837 | /* | 807 | /* |
@@ -841,8 +811,8 @@ move_extent_per_page(struct file *o_filp, struct inode *donor_inode, | |||
841 | jblocks = ext4_writepage_trans_blocks(orig_inode) * 2; | 811 | jblocks = ext4_writepage_trans_blocks(orig_inode) * 2; |
842 | handle = ext4_journal_start(orig_inode, jblocks); | 812 | handle = ext4_journal_start(orig_inode, jblocks); |
843 | if (IS_ERR(handle)) { | 813 | if (IS_ERR(handle)) { |
844 | ret = PTR_ERR(handle); | 814 | *err = PTR_ERR(handle); |
845 | return ret; | 815 | return 0; |
846 | } | 816 | } |
847 | 817 | ||
848 | if (segment_eq(get_fs(), KERNEL_DS)) | 818 | if (segment_eq(get_fs(), KERNEL_DS)) |
@@ -858,39 +828,36 @@ move_extent_per_page(struct file *o_filp, struct inode *donor_inode, | |||
858 | * Just swap data blocks between orig and donor. | 828 | * Just swap data blocks between orig and donor. |
859 | */ | 829 | */ |
860 | if (uninit) { | 830 | if (uninit) { |
861 | ret = mext_replace_branches(handle, orig_inode, | 831 | replaced_count = mext_replace_branches(handle, orig_inode, |
862 | donor_inode, orig_blk_offset, | 832 | donor_inode, orig_blk_offset, |
863 | block_len_in_page); | 833 | block_len_in_page, err); |
864 | |||
865 | /* Clear the inode cache not to refer to the old data */ | ||
866 | ext4_ext_invalidate_cache(orig_inode); | ||
867 | ext4_ext_invalidate_cache(donor_inode); | ||
868 | goto out2; | 834 | goto out2; |
869 | } | 835 | } |
870 | 836 | ||
871 | offs = (long long)orig_blk_offset << orig_inode->i_blkbits; | 837 | offs = (long long)orig_blk_offset << orig_inode->i_blkbits; |
872 | 838 | ||
873 | /* Calculate data_len */ | 839 | /* Calculate data_size */ |
874 | if ((orig_blk_offset + block_len_in_page - 1) == | 840 | if ((orig_blk_offset + block_len_in_page - 1) == |
875 | ((orig_inode->i_size - 1) >> orig_inode->i_blkbits)) { | 841 | ((orig_inode->i_size - 1) >> orig_inode->i_blkbits)) { |
876 | /* Replace the last block */ | 842 | /* Replace the last block */ |
877 | tmp_data_len = orig_inode->i_size & (blocksize - 1); | 843 | tmp_data_size = orig_inode->i_size & (blocksize - 1); |
878 | /* | 844 | /* |
879 | * If data_len equal zero, it shows data_len is multiples of | 845 | * If data_size equal zero, it shows data_size is multiples of |
880 | * blocksize. So we set appropriate value. | 846 | * blocksize. So we set appropriate value. |
881 | */ | 847 | */ |
882 | if (tmp_data_len == 0) | 848 | if (tmp_data_size == 0) |
883 | tmp_data_len = blocksize; | 849 | tmp_data_size = blocksize; |
884 | 850 | ||
885 | data_len = tmp_data_len + | 851 | data_size = tmp_data_size + |
886 | ((block_len_in_page - 1) << orig_inode->i_blkbits); | 852 | ((block_len_in_page - 1) << orig_inode->i_blkbits); |
887 | } else { | 853 | } else |
888 | data_len = block_len_in_page << orig_inode->i_blkbits; | 854 | data_size = block_len_in_page << orig_inode->i_blkbits; |
889 | } | 855 | |
856 | replaced_size = data_size; | ||
890 | 857 | ||
891 | ret = a_ops->write_begin(o_filp, mapping, offs, data_len, w_flags, | 858 | *err = a_ops->write_begin(o_filp, mapping, offs, data_size, w_flags, |
892 | &page, &fsdata); | 859 | &page, &fsdata); |
893 | if (unlikely(ret < 0)) | 860 | if (unlikely(*err < 0)) |
894 | goto out; | 861 | goto out; |
895 | 862 | ||
896 | if (!PageUptodate(page)) { | 863 | if (!PageUptodate(page)) { |
@@ -911,14 +878,17 @@ move_extent_per_page(struct file *o_filp, struct inode *donor_inode, | |||
911 | /* Release old bh and drop refs */ | 878 | /* Release old bh and drop refs */ |
912 | try_to_release_page(page, 0); | 879 | try_to_release_page(page, 0); |
913 | 880 | ||
914 | ret = mext_replace_branches(handle, orig_inode, donor_inode, | 881 | replaced_count = mext_replace_branches(handle, orig_inode, donor_inode, |
915 | orig_blk_offset, block_len_in_page); | 882 | orig_blk_offset, block_len_in_page, |
916 | if (ret < 0) | 883 | &err2); |
917 | goto out; | 884 | if (err2) { |
918 | 885 | if (replaced_count) { | |
919 | /* Clear the inode cache not to refer to the old data */ | 886 | block_len_in_page = replaced_count; |
920 | ext4_ext_invalidate_cache(orig_inode); | 887 | replaced_size = |
921 | ext4_ext_invalidate_cache(donor_inode); | 888 | block_len_in_page << orig_inode->i_blkbits; |
889 | } else | ||
890 | goto out; | ||
891 | } | ||
922 | 892 | ||
923 | if (!page_has_buffers(page)) | 893 | if (!page_has_buffers(page)) |
924 | create_empty_buffers(page, 1 << orig_inode->i_blkbits, 0); | 894 | create_empty_buffers(page, 1 << orig_inode->i_blkbits, 0); |
@@ -928,16 +898,16 @@ move_extent_per_page(struct file *o_filp, struct inode *donor_inode, | |||
928 | bh = bh->b_this_page; | 898 | bh = bh->b_this_page; |
929 | 899 | ||
930 | for (i = 0; i < block_len_in_page; i++) { | 900 | for (i = 0; i < block_len_in_page; i++) { |
931 | ret = ext4_get_block(orig_inode, | 901 | *err = ext4_get_block(orig_inode, |
932 | (sector_t)(orig_blk_offset + i), bh, 0); | 902 | (sector_t)(orig_blk_offset + i), bh, 0); |
933 | if (ret < 0) | 903 | if (*err < 0) |
934 | goto out; | 904 | goto out; |
935 | 905 | ||
936 | if (bh->b_this_page != NULL) | 906 | if (bh->b_this_page != NULL) |
937 | bh = bh->b_this_page; | 907 | bh = bh->b_this_page; |
938 | } | 908 | } |
939 | 909 | ||
940 | ret = a_ops->write_end(o_filp, mapping, offs, data_len, data_len, | 910 | *err = a_ops->write_end(o_filp, mapping, offs, data_size, replaced_size, |
941 | page, fsdata); | 911 | page, fsdata); |
942 | page = NULL; | 912 | page = NULL; |
943 | 913 | ||
@@ -951,7 +921,10 @@ out: | |||
951 | out2: | 921 | out2: |
952 | ext4_journal_stop(handle); | 922 | ext4_journal_stop(handle); |
953 | 923 | ||
954 | return ret < 0 ? ret : 0; | 924 | if (err2) |
925 | *err = err2; | ||
926 | |||
927 | return replaced_count; | ||
955 | } | 928 | } |
956 | 929 | ||
957 | /** | 930 | /** |
@@ -962,7 +935,6 @@ out2: | |||
962 | * @orig_start: logical start offset in block for orig | 935 | * @orig_start: logical start offset in block for orig |
963 | * @donor_start: logical start offset in block for donor | 936 | * @donor_start: logical start offset in block for donor |
964 | * @len: the number of blocks to be moved | 937 | * @len: the number of blocks to be moved |
965 | * @moved_len: moved block length | ||
966 | * | 938 | * |
967 | * Check the arguments of ext4_move_extents() whether the files can be | 939 | * Check the arguments of ext4_move_extents() whether the files can be |
968 | * exchanged with each other. | 940 | * exchanged with each other. |
@@ -970,8 +942,8 @@ out2: | |||
970 | */ | 942 | */ |
971 | static int | 943 | static int |
972 | mext_check_arguments(struct inode *orig_inode, | 944 | mext_check_arguments(struct inode *orig_inode, |
973 | struct inode *donor_inode, __u64 orig_start, | 945 | struct inode *donor_inode, __u64 orig_start, |
974 | __u64 donor_start, __u64 *len, __u64 moved_len) | 946 | __u64 donor_start, __u64 *len) |
975 | { | 947 | { |
976 | ext4_lblk_t orig_blocks, donor_blocks; | 948 | ext4_lblk_t orig_blocks, donor_blocks; |
977 | unsigned int blkbits = orig_inode->i_blkbits; | 949 | unsigned int blkbits = orig_inode->i_blkbits; |
@@ -985,6 +957,13 @@ mext_check_arguments(struct inode *orig_inode, | |||
985 | return -EINVAL; | 957 | return -EINVAL; |
986 | } | 958 | } |
987 | 959 | ||
960 | if (donor_inode->i_mode & (S_ISUID|S_ISGID)) { | ||
961 | ext4_debug("ext4 move extent: suid or sgid is set" | ||
962 | " to donor file [ino:orig %lu, donor %lu]\n", | ||
963 | orig_inode->i_ino, donor_inode->i_ino); | ||
964 | return -EINVAL; | ||
965 | } | ||
966 | |||
988 | /* Ext4 move extent does not support swapfile */ | 967 | /* Ext4 move extent does not support swapfile */ |
989 | if (IS_SWAPFILE(orig_inode) || IS_SWAPFILE(donor_inode)) { | 968 | if (IS_SWAPFILE(orig_inode) || IS_SWAPFILE(donor_inode)) { |
990 | ext4_debug("ext4 move extent: The argument files should " | 969 | ext4_debug("ext4 move extent: The argument files should " |
@@ -1025,13 +1004,6 @@ mext_check_arguments(struct inode *orig_inode, | |||
1025 | return -EINVAL; | 1004 | return -EINVAL; |
1026 | } | 1005 | } |
1027 | 1006 | ||
1028 | if (moved_len) { | ||
1029 | ext4_debug("ext4 move extent: moved_len should be 0 " | ||
1030 | "[ino:orig %lu, donor %lu]\n", orig_inode->i_ino, | ||
1031 | donor_inode->i_ino); | ||
1032 | return -EINVAL; | ||
1033 | } | ||
1034 | |||
1035 | if ((orig_start > EXT_MAX_BLOCK) || | 1007 | if ((orig_start > EXT_MAX_BLOCK) || |
1036 | (donor_start > EXT_MAX_BLOCK) || | 1008 | (donor_start > EXT_MAX_BLOCK) || |
1037 | (*len > EXT_MAX_BLOCK) || | 1009 | (*len > EXT_MAX_BLOCK) || |
@@ -1088,7 +1060,7 @@ mext_check_arguments(struct inode *orig_inode, | |||
1088 | } | 1060 | } |
1089 | 1061 | ||
1090 | if (!*len) { | 1062 | if (!*len) { |
1091 | ext4_debug("ext4 move extent: len shoudld not be 0 " | 1063 | ext4_debug("ext4 move extent: len should not be 0 " |
1092 | "[ino:orig %lu, donor %lu]\n", orig_inode->i_ino, | 1064 | "[ino:orig %lu, donor %lu]\n", orig_inode->i_ino, |
1093 | donor_inode->i_ino); | 1065 | donor_inode->i_ino); |
1094 | return -EINVAL; | 1066 | return -EINVAL; |
@@ -1232,16 +1204,16 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, | |||
1232 | return -EINVAL; | 1204 | return -EINVAL; |
1233 | } | 1205 | } |
1234 | 1206 | ||
1235 | /* protect orig and donor against a truncate */ | 1207 | /* Protect orig and donor inodes against a truncate */ |
1236 | ret1 = mext_inode_double_lock(orig_inode, donor_inode); | 1208 | ret1 = mext_inode_double_lock(orig_inode, donor_inode); |
1237 | if (ret1 < 0) | 1209 | if (ret1 < 0) |
1238 | return ret1; | 1210 | return ret1; |
1239 | 1211 | ||
1240 | mext_double_down_read(orig_inode, donor_inode); | 1212 | /* Protect extent tree against block allocations via delalloc */ |
1213 | double_down_write_data_sem(orig_inode, donor_inode); | ||
1241 | /* Check the filesystem environment whether move_extent can be done */ | 1214 | /* Check the filesystem environment whether move_extent can be done */ |
1242 | ret1 = mext_check_arguments(orig_inode, donor_inode, orig_start, | 1215 | ret1 = mext_check_arguments(orig_inode, donor_inode, orig_start, |
1243 | donor_start, &len, *moved_len); | 1216 | donor_start, &len); |
1244 | mext_double_up_read(orig_inode, donor_inode); | ||
1245 | if (ret1) | 1217 | if (ret1) |
1246 | goto out; | 1218 | goto out; |
1247 | 1219 | ||
@@ -1355,36 +1327,39 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, | |||
1355 | seq_start = le32_to_cpu(ext_cur->ee_block); | 1327 | seq_start = le32_to_cpu(ext_cur->ee_block); |
1356 | rest_blocks = seq_blocks; | 1328 | rest_blocks = seq_blocks; |
1357 | 1329 | ||
1358 | /* Discard preallocations of two inodes */ | 1330 | /* |
1359 | down_write(&EXT4_I(orig_inode)->i_data_sem); | 1331 | * Up semaphore to avoid following problems: |
1360 | ext4_discard_preallocations(orig_inode); | 1332 | * a. transaction deadlock among ext4_journal_start, |
1361 | up_write(&EXT4_I(orig_inode)->i_data_sem); | 1333 | * ->write_begin via pagefault, and jbd2_journal_commit |
1362 | 1334 | * b. racing with ->readpage, ->write_begin, and ext4_get_block | |
1363 | down_write(&EXT4_I(donor_inode)->i_data_sem); | 1335 | * in move_extent_per_page |
1364 | ext4_discard_preallocations(donor_inode); | 1336 | */ |
1365 | up_write(&EXT4_I(donor_inode)->i_data_sem); | 1337 | double_up_write_data_sem(orig_inode, donor_inode); |
1366 | 1338 | ||
1367 | while (orig_page_offset <= seq_end_page) { | 1339 | while (orig_page_offset <= seq_end_page) { |
1368 | 1340 | ||
1369 | /* Swap original branches with new branches */ | 1341 | /* Swap original branches with new branches */ |
1370 | ret1 = move_extent_per_page(o_filp, donor_inode, | 1342 | block_len_in_page = move_extent_per_page( |
1343 | o_filp, donor_inode, | ||
1371 | orig_page_offset, | 1344 | orig_page_offset, |
1372 | data_offset_in_page, | 1345 | data_offset_in_page, |
1373 | block_len_in_page, uninit); | 1346 | block_len_in_page, uninit, |
1374 | if (ret1 < 0) | 1347 | &ret1); |
1375 | goto out; | 1348 | |
1376 | orig_page_offset++; | ||
1377 | /* Count how many blocks we have exchanged */ | 1349 | /* Count how many blocks we have exchanged */ |
1378 | *moved_len += block_len_in_page; | 1350 | *moved_len += block_len_in_page; |
1351 | if (ret1 < 0) | ||
1352 | break; | ||
1379 | if (*moved_len > len) { | 1353 | if (*moved_len > len) { |
1380 | ext4_error(orig_inode->i_sb, __func__, | 1354 | ext4_error(orig_inode->i_sb, __func__, |
1381 | "We replaced blocks too much! " | 1355 | "We replaced blocks too much! " |
1382 | "sum of replaced: %llu requested: %llu", | 1356 | "sum of replaced: %llu requested: %llu", |
1383 | *moved_len, len); | 1357 | *moved_len, len); |
1384 | ret1 = -EIO; | 1358 | ret1 = -EIO; |
1385 | goto out; | 1359 | break; |
1386 | } | 1360 | } |
1387 | 1361 | ||
1362 | orig_page_offset++; | ||
1388 | data_offset_in_page = 0; | 1363 | data_offset_in_page = 0; |
1389 | rest_blocks -= block_len_in_page; | 1364 | rest_blocks -= block_len_in_page; |
1390 | if (rest_blocks > blocks_per_page) | 1365 | if (rest_blocks > blocks_per_page) |
@@ -1393,6 +1368,10 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, | |||
1393 | block_len_in_page = rest_blocks; | 1368 | block_len_in_page = rest_blocks; |
1394 | } | 1369 | } |
1395 | 1370 | ||
1371 | double_down_write_data_sem(orig_inode, donor_inode); | ||
1372 | if (ret1 < 0) | ||
1373 | break; | ||
1374 | |||
1396 | /* Decrease buffer counter */ | 1375 | /* Decrease buffer counter */ |
1397 | if (holecheck_path) | 1376 | if (holecheck_path) |
1398 | ext4_ext_drop_refs(holecheck_path); | 1377 | ext4_ext_drop_refs(holecheck_path); |
@@ -1414,6 +1393,11 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, | |||
1414 | 1393 | ||
1415 | } | 1394 | } |
1416 | out: | 1395 | out: |
1396 | if (*moved_len) { | ||
1397 | ext4_discard_preallocations(orig_inode); | ||
1398 | ext4_discard_preallocations(donor_inode); | ||
1399 | } | ||
1400 | |||
1417 | if (orig_path) { | 1401 | if (orig_path) { |
1418 | ext4_ext_drop_refs(orig_path); | 1402 | ext4_ext_drop_refs(orig_path); |
1419 | kfree(orig_path); | 1403 | kfree(orig_path); |
@@ -1422,7 +1406,7 @@ out: | |||
1422 | ext4_ext_drop_refs(holecheck_path); | 1406 | ext4_ext_drop_refs(holecheck_path); |
1423 | kfree(holecheck_path); | 1407 | kfree(holecheck_path); |
1424 | } | 1408 | } |
1425 | 1409 | double_up_write_data_sem(orig_inode, donor_inode); | |
1426 | ret2 = mext_inode_double_unlock(orig_inode, donor_inode); | 1410 | ret2 = mext_inode_double_unlock(orig_inode, donor_inode); |
1427 | 1411 | ||
1428 | if (ret1) | 1412 | if (ret1) |