aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Whitney <enwlinux@gmail.com>2014-11-23 00:55:42 -0500
committerTheodore Ts'o <tytso@mit.edu>2014-11-23 00:55:42 -0500
commitf4226d9ea400e7124120571b1e89504c79f2e953 (patch)
treec3c53be4a83b3293f0baf269737622c4ded94058
parentb93b41d4c7338dda9304eaac9d3b40da43198806 (diff)
ext4: fix partial cluster initialization
The partial_cluster variable is not always initialized correctly when hole punching on bigalloc file systems. Although commit c06344939422 ("ext4: fix partial cluster handling for bigalloc file systems") addressed the case where the right edge of the punched region and the next extent to its right were within the same leaf, it didn't handle the case where the next extent to its right is in the next leaf. This causes xfstest generic/300 to fail. Fix this by replacing the code in c0634493922 with a more general solution that can continue the search for the first cluster to the right of the punched region into the next leaf if present. If found, partial_cluster is initialized to this cluster's negative value. There's no need to determine if that cluster is actually shared; we simply record it so its blocks won't be freed in the event it does happen to be shared. Also, minimize the burden on non-bigalloc file systems with some minor code simplification. Signed-off-by: Eric Whitney <enwlinux@gmail.com> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
-rw-r--r--fs/ext4/extents.c80
1 files changed, 46 insertions, 34 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 0b16fb4c06d3..57794a7a435c 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -2621,27 +2621,6 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
2621 ex_ee_block = le32_to_cpu(ex->ee_block); 2621 ex_ee_block = le32_to_cpu(ex->ee_block);
2622 ex_ee_len = ext4_ext_get_actual_len(ex); 2622 ex_ee_len = ext4_ext_get_actual_len(ex);
2623 2623
2624 /*
2625 * If we're starting with an extent other than the last one in the
2626 * node, we need to see if it shares a cluster with the extent to
2627 * the right (towards the end of the file). If its leftmost cluster
2628 * is this extent's rightmost cluster and it is not cluster aligned,
2629 * we'll mark it as a partial that is not to be deallocated.
2630 */
2631
2632 if (ex != EXT_LAST_EXTENT(eh)) {
2633 ext4_fsblk_t current_pblk, right_pblk;
2634 long long current_cluster, right_cluster;
2635
2636 current_pblk = ext4_ext_pblock(ex) + ex_ee_len - 1;
2637 current_cluster = (long long)EXT4_B2C(sbi, current_pblk);
2638 right_pblk = ext4_ext_pblock(ex + 1);
2639 right_cluster = (long long)EXT4_B2C(sbi, right_pblk);
2640 if (current_cluster == right_cluster &&
2641 EXT4_PBLK_COFF(sbi, right_pblk))
2642 *partial_cluster = -right_cluster;
2643 }
2644
2645 trace_ext4_ext_rm_leaf(inode, start, ex, *partial_cluster); 2624 trace_ext4_ext_rm_leaf(inode, start, ex, *partial_cluster);
2646 2625
2647 while (ex >= EXT_FIRST_EXTENT(eh) && 2626 while (ex >= EXT_FIRST_EXTENT(eh) &&
@@ -2666,14 +2645,16 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
2666 if (end < ex_ee_block) { 2645 if (end < ex_ee_block) {
2667 /* 2646 /*
2668 * We're going to skip this extent and move to another, 2647 * We're going to skip this extent and move to another,
2669 * so if this extent is not cluster aligned we have 2648 * so note that its first cluster is in use to avoid
2670 * to mark the current cluster as used to avoid 2649 * freeing it when removing blocks. Eventually, the
2671 * accidentally freeing it later on 2650 * right edge of the truncated/punched region will
2651 * be just to the left.
2672 */ 2652 */
2673 pblk = ext4_ext_pblock(ex); 2653 if (sbi->s_cluster_ratio > 1) {
2674 if (EXT4_PBLK_COFF(sbi, pblk)) 2654 pblk = ext4_ext_pblock(ex);
2675 *partial_cluster = 2655 *partial_cluster =
2676 -((long long)EXT4_B2C(sbi, pblk)); 2656 -(long long) EXT4_B2C(sbi, pblk);
2657 }
2677 ex--; 2658 ex--;
2678 ex_ee_block = le32_to_cpu(ex->ee_block); 2659 ex_ee_block = le32_to_cpu(ex->ee_block);
2679 ex_ee_len = ext4_ext_get_actual_len(ex); 2660 ex_ee_len = ext4_ext_get_actual_len(ex);
@@ -2819,7 +2800,7 @@ ext4_ext_more_to_rm(struct ext4_ext_path *path)
2819int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start, 2800int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start,
2820 ext4_lblk_t end) 2801 ext4_lblk_t end)
2821{ 2802{
2822 struct super_block *sb = inode->i_sb; 2803 struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
2823 int depth = ext_depth(inode); 2804 int depth = ext_depth(inode);
2824 struct ext4_ext_path *path = NULL; 2805 struct ext4_ext_path *path = NULL;
2825 long long partial_cluster = 0; 2806 long long partial_cluster = 0;
@@ -2845,9 +2826,10 @@ again:
2845 */ 2826 */
2846 if (end < EXT_MAX_BLOCKS - 1) { 2827 if (end < EXT_MAX_BLOCKS - 1) {
2847 struct ext4_extent *ex; 2828 struct ext4_extent *ex;
2848 ext4_lblk_t ee_block; 2829 ext4_lblk_t ee_block, ex_end, lblk;
2830 ext4_fsblk_t pblk;
2849 2831
2850 /* find extent for this block */ 2832 /* find extent for or closest extent to this block */
2851 path = ext4_find_extent(inode, end, NULL, EXT4_EX_NOCACHE); 2833 path = ext4_find_extent(inode, end, NULL, EXT4_EX_NOCACHE);
2852 if (IS_ERR(path)) { 2834 if (IS_ERR(path)) {
2853 ext4_journal_stop(handle); 2835 ext4_journal_stop(handle);
@@ -2867,6 +2849,7 @@ again:
2867 } 2849 }
2868 2850
2869 ee_block = le32_to_cpu(ex->ee_block); 2851 ee_block = le32_to_cpu(ex->ee_block);
2852 ex_end = ee_block + ext4_ext_get_actual_len(ex) - 1;
2870 2853
2871 /* 2854 /*
2872 * See if the last block is inside the extent, if so split 2855 * See if the last block is inside the extent, if so split
@@ -2874,8 +2857,19 @@ again:
2874 * tail of the first part of the split extent in 2857 * tail of the first part of the split extent in
2875 * ext4_ext_rm_leaf(). 2858 * ext4_ext_rm_leaf().
2876 */ 2859 */
2877 if (end >= ee_block && 2860 if (end >= ee_block && end < ex_end) {
2878 end < ee_block + ext4_ext_get_actual_len(ex) - 1) { 2861
2862 /*
2863 * If we're going to split the extent, note that
2864 * the cluster containing the block after 'end' is
2865 * in use to avoid freeing it when removing blocks.
2866 */
2867 if (sbi->s_cluster_ratio > 1) {
2868 pblk = ext4_ext_pblock(ex) + end - ee_block + 2;
2869 partial_cluster =
2870 -(long long) EXT4_B2C(sbi, pblk);
2871 }
2872
2879 /* 2873 /*
2880 * Split the extent in two so that 'end' is the last 2874 * Split the extent in two so that 'end' is the last
2881 * block in the first new extent. Also we should not 2875 * block in the first new extent. Also we should not
@@ -2886,6 +2880,24 @@ again:
2886 end + 1, 1); 2880 end + 1, 1);
2887 if (err < 0) 2881 if (err < 0)
2888 goto out; 2882 goto out;
2883
2884 } else if (sbi->s_cluster_ratio > 1 && end >= ex_end) {
2885 /*
2886 * If there's an extent to the right its first cluster
2887 * contains the immediate right boundary of the
2888 * truncated/punched region. Set partial_cluster to
2889 * its negative value so it won't be freed if shared
2890 * with the current extent. The end < ee_block case
2891 * is handled in ext4_ext_rm_leaf().
2892 */
2893 lblk = ex_end + 1;
2894 err = ext4_ext_search_right(inode, path, &lblk, &pblk,
2895 &ex);
2896 if (err)
2897 goto out;
2898 if (pblk)
2899 partial_cluster =
2900 -(long long) EXT4_B2C(sbi, pblk);
2889 } 2901 }
2890 } 2902 }
2891 /* 2903 /*
@@ -3003,8 +3015,8 @@ again:
3003 int flags = get_default_free_blocks_flags(inode); 3015 int flags = get_default_free_blocks_flags(inode);
3004 3016
3005 ext4_free_blocks(handle, inode, NULL, 3017 ext4_free_blocks(handle, inode, NULL,
3006 EXT4_C2B(EXT4_SB(sb), partial_cluster), 3018 EXT4_C2B(sbi, partial_cluster),
3007 EXT4_SB(sb)->s_cluster_ratio, flags); 3019 sbi->s_cluster_ratio, flags);
3008 partial_cluster = 0; 3020 partial_cluster = 0;
3009 } 3021 }
3010 3022