diff options
| -rw-r--r-- | fs/ext4/move_extent.c | 46 |
1 files changed, 37 insertions, 9 deletions
diff --git a/fs/ext4/move_extent.c b/fs/ext4/move_extent.c index 1c509d549137..1f027b1ec430 100644 --- a/fs/ext4/move_extent.c +++ b/fs/ext4/move_extent.c | |||
| @@ -597,8 +597,10 @@ out: | |||
| 597 | * @orig_off: block offset of original inode | 597 | * @orig_off: block offset of original inode |
| 598 | * @donor_off: block offset of donor inode | 598 | * @donor_off: block offset of donor inode |
| 599 | * @max_count: the maximun length of extents | 599 | * @max_count: the maximun length of extents |
| 600 | * | ||
| 601 | * Return 0 on success, or a negative error value on failure. | ||
| 600 | */ | 602 | */ |
| 601 | static void | 603 | static int |
| 602 | mext_calc_swap_extents(struct ext4_extent *tmp_dext, | 604 | mext_calc_swap_extents(struct ext4_extent *tmp_dext, |
| 603 | struct ext4_extent *tmp_oext, | 605 | struct ext4_extent *tmp_oext, |
| 604 | ext4_lblk_t orig_off, ext4_lblk_t donor_off, | 606 | ext4_lblk_t orig_off, ext4_lblk_t donor_off, |
| @@ -607,6 +609,19 @@ mext_calc_swap_extents(struct ext4_extent *tmp_dext, | |||
| 607 | ext4_lblk_t diff, orig_diff; | 609 | ext4_lblk_t diff, orig_diff; |
| 608 | struct ext4_extent dext_old, oext_old; | 610 | struct ext4_extent dext_old, oext_old; |
| 609 | 611 | ||
| 612 | BUG_ON(orig_off != donor_off); | ||
| 613 | |||
| 614 | /* original and donor extents have to cover the same block offset */ | ||
| 615 | if (orig_off < le32_to_cpu(tmp_oext->ee_block) || | ||
| 616 | le32_to_cpu(tmp_oext->ee_block) + | ||
| 617 | ext4_ext_get_actual_len(tmp_oext) - 1 < orig_off) | ||
| 618 | return -ENODATA; | ||
| 619 | |||
| 620 | if (orig_off < le32_to_cpu(tmp_dext->ee_block) || | ||
| 621 | le32_to_cpu(tmp_dext->ee_block) + | ||
| 622 | ext4_ext_get_actual_len(tmp_dext) - 1 < orig_off) | ||
| 623 | return -ENODATA; | ||
| 624 | |||
| 610 | dext_old = *tmp_dext; | 625 | dext_old = *tmp_dext; |
| 611 | oext_old = *tmp_oext; | 626 | oext_old = *tmp_oext; |
| 612 | 627 | ||
| @@ -634,6 +649,8 @@ mext_calc_swap_extents(struct ext4_extent *tmp_dext, | |||
| 634 | 649 | ||
| 635 | copy_extent_status(&oext_old, tmp_dext); | 650 | copy_extent_status(&oext_old, tmp_dext); |
| 636 | copy_extent_status(&dext_old, tmp_oext); | 651 | copy_extent_status(&dext_old, tmp_oext); |
| 652 | |||
| 653 | return 0; | ||
| 637 | } | 654 | } |
| 638 | 655 | ||
| 639 | /** | 656 | /** |
| @@ -690,8 +707,10 @@ mext_replace_branches(handle_t *handle, struct inode *orig_inode, | |||
| 690 | dext = donor_path[depth].p_ext; | 707 | dext = donor_path[depth].p_ext; |
| 691 | tmp_dext = *dext; | 708 | tmp_dext = *dext; |
| 692 | 709 | ||
| 693 | mext_calc_swap_extents(&tmp_dext, &tmp_oext, orig_off, | 710 | err = mext_calc_swap_extents(&tmp_dext, &tmp_oext, orig_off, |
| 694 | donor_off, count); | 711 | donor_off, count); |
| 712 | if (err) | ||
| 713 | goto out; | ||
| 695 | 714 | ||
| 696 | /* Loop for the donor extents */ | 715 | /* Loop for the donor extents */ |
| 697 | while (1) { | 716 | while (1) { |
| @@ -760,9 +779,10 @@ mext_replace_branches(handle_t *handle, struct inode *orig_inode, | |||
| 760 | } | 779 | } |
| 761 | tmp_dext = *dext; | 780 | tmp_dext = *dext; |
| 762 | 781 | ||
| 763 | mext_calc_swap_extents(&tmp_dext, &tmp_oext, orig_off, | 782 | err = mext_calc_swap_extents(&tmp_dext, &tmp_oext, orig_off, |
| 764 | donor_off, | 783 | donor_off, count - replaced_count); |
| 765 | count - replaced_count); | 784 | if (err) |
| 785 | goto out; | ||
| 766 | } | 786 | } |
| 767 | 787 | ||
| 768 | out: | 788 | out: |
| @@ -1243,11 +1263,15 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, | |||
| 1243 | ext_cur = holecheck_path[depth].p_ext; | 1263 | ext_cur = holecheck_path[depth].p_ext; |
| 1244 | 1264 | ||
| 1245 | /* | 1265 | /* |
| 1246 | * Get proper extent whose ee_block is beyond block_start | 1266 | * Get proper starting location of block replacement if block_start was |
| 1247 | * if block_start was within the hole. | 1267 | * within the hole. |
| 1248 | */ | 1268 | */ |
| 1249 | if (le32_to_cpu(ext_cur->ee_block) + | 1269 | if (le32_to_cpu(ext_cur->ee_block) + |
| 1250 | ext4_ext_get_actual_len(ext_cur) - 1 < block_start) { | 1270 | ext4_ext_get_actual_len(ext_cur) - 1 < block_start) { |
| 1271 | /* | ||
| 1272 | * The hole exists between extents or the tail of | ||
| 1273 | * original file. | ||
| 1274 | */ | ||
| 1251 | last_extent = mext_next_extent(orig_inode, | 1275 | last_extent = mext_next_extent(orig_inode, |
| 1252 | holecheck_path, &ext_cur); | 1276 | holecheck_path, &ext_cur); |
| 1253 | if (last_extent < 0) { | 1277 | if (last_extent < 0) { |
| @@ -1260,8 +1284,12 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, | |||
| 1260 | ret1 = last_extent; | 1284 | ret1 = last_extent; |
| 1261 | goto out; | 1285 | goto out; |
| 1262 | } | 1286 | } |
| 1263 | } | 1287 | seq_start = le32_to_cpu(ext_cur->ee_block); |
| 1264 | seq_start = block_start; | 1288 | } else if (le32_to_cpu(ext_cur->ee_block) > block_start) |
| 1289 | /* The hole exists at the beginning of original file. */ | ||
| 1290 | seq_start = le32_to_cpu(ext_cur->ee_block); | ||
| 1291 | else | ||
| 1292 | seq_start = block_start; | ||
| 1265 | 1293 | ||
| 1266 | /* No blocks within the specified range. */ | 1294 | /* No blocks within the specified range. */ |
| 1267 | if (le32_to_cpu(ext_cur->ee_block) > block_end) { | 1295 | if (le32_to_cpu(ext_cur->ee_block) > block_end) { |
