aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4
diff options
context:
space:
mode:
authorAshish Sangwan <ashishsangwan2@gmail.com>2012-07-22 22:49:08 -0400
committerTheodore Ts'o <tytso@mit.edu>2012-07-22 22:49:08 -0400
commit968dee77220768a5f52cf8b21d0bdb73486febef (patch)
treed9cb2adcb71b5b00fed42dcb6c7fc55f57e0b7ce /fs/ext4
parentb50924c2c606eccfe0caef39beb0929dfa9a1a81 (diff)
ext4: fix hole punch failure when depth is greater than 0
Whether to continue removing extents or not is decided by the return value of function ext4_ext_more_to_rm() which checks 2 conditions: a) if there are no more indexes to process. b) if the number of entries are decreased in the header of "depth -1". In case of hole punch, if the last block to be removed is not part of the last extent index than this index will not be deleted, hence the number of valid entries in the extent header of "depth - 1" will remain as it is and ext4_ext_more_to_rm will return 0 although the required blocks are not yet removed. This patch fixes the above mentioned problem as instead of removing the extents from the end of file, it starts removing the blocks from the particular extent from which removing blocks is actually required and continue backward until done. Signed-off-by: Ashish Sangwan <ashish.sangwan2@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@gmail.com> Reviewed-by: Lukas Czerner <lczerner@redhat.com> Cc: stable@vger.kernel.org
Diffstat (limited to 'fs/ext4')
-rw-r--r--fs/ext4/extents.c46
1 files changed, 29 insertions, 17 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 46b5c9fdc96a..cd0c7ed06772 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -2569,10 +2569,10 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start,
2569{ 2569{
2570 struct super_block *sb = inode->i_sb; 2570 struct super_block *sb = inode->i_sb;
2571 int depth = ext_depth(inode); 2571 int depth = ext_depth(inode);
2572 struct ext4_ext_path *path; 2572 struct ext4_ext_path *path = NULL;
2573 ext4_fsblk_t partial_cluster = 0; 2573 ext4_fsblk_t partial_cluster = 0;
2574 handle_t *handle; 2574 handle_t *handle;
2575 int i, err; 2575 int i = 0, err;
2576 2576
2577 ext_debug("truncate since %u to %u\n", start, end); 2577 ext_debug("truncate since %u to %u\n", start, end);
2578 2578
@@ -2605,8 +2605,12 @@ again:
2605 } 2605 }
2606 depth = ext_depth(inode); 2606 depth = ext_depth(inode);
2607 ex = path[depth].p_ext; 2607 ex = path[depth].p_ext;
2608 if (!ex) 2608 if (!ex) {
2609 ext4_ext_drop_refs(path);
2610 kfree(path);
2611 path = NULL;
2609 goto cont; 2612 goto cont;
2613 }
2610 2614
2611 ee_block = le32_to_cpu(ex->ee_block); 2615 ee_block = le32_to_cpu(ex->ee_block);
2612 2616
@@ -2636,8 +2640,6 @@ again:
2636 if (err < 0) 2640 if (err < 0)
2637 goto out; 2641 goto out;
2638 } 2642 }
2639 ext4_ext_drop_refs(path);
2640 kfree(path);
2641 } 2643 }
2642cont: 2644cont:
2643 2645
@@ -2646,19 +2648,27 @@ cont:
2646 * after i_size and walking into the tree depth-wise. 2648 * after i_size and walking into the tree depth-wise.
2647 */ 2649 */
2648 depth = ext_depth(inode); 2650 depth = ext_depth(inode);
2649 path = kzalloc(sizeof(struct ext4_ext_path) * (depth + 1), GFP_NOFS); 2651 if (path) {
2650 if (path == NULL) { 2652 int k = i = depth;
2651 ext4_journal_stop(handle); 2653 while (--k > 0)
2652 return -ENOMEM; 2654 path[k].p_block =
2653 } 2655 le16_to_cpu(path[k].p_hdr->eh_entries)+1;
2654 path[0].p_depth = depth; 2656 } else {
2655 path[0].p_hdr = ext_inode_hdr(inode); 2657 path = kzalloc(sizeof(struct ext4_ext_path) * (depth + 1),
2658 GFP_NOFS);
2659 if (path == NULL) {
2660 ext4_journal_stop(handle);
2661 return -ENOMEM;
2662 }
2663 path[0].p_depth = depth;
2664 path[0].p_hdr = ext_inode_hdr(inode);
2656 2665
2657 if (ext4_ext_check(inode, path[0].p_hdr, depth)) { 2666 if (ext4_ext_check(inode, path[0].p_hdr, depth)) {
2658 err = -EIO; 2667 err = -EIO;
2659 goto out; 2668 goto out;
2669 }
2660 } 2670 }
2661 i = err = 0; 2671 err = 0;
2662 2672
2663 while (i >= 0 && err == 0) { 2673 while (i >= 0 && err == 0) {
2664 if (i == depth) { 2674 if (i == depth) {
@@ -2772,8 +2782,10 @@ cont:
2772out: 2782out:
2773 ext4_ext_drop_refs(path); 2783 ext4_ext_drop_refs(path);
2774 kfree(path); 2784 kfree(path);
2775 if (err == -EAGAIN) 2785 if (err == -EAGAIN) {
2786 path = NULL;
2776 goto again; 2787 goto again;
2788 }
2777 ext4_journal_stop(handle); 2789 ext4_journal_stop(handle);
2778 2790
2779 return err; 2791 return err;