aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Whitney <enwlinux@gmail.com>2014-11-23 00:58:11 -0500
committerTheodore Ts'o <tytso@mit.edu>2014-11-23 00:58:11 -0500
commit5bf43760654fa618fb8bb1612ee2d7ae164f7f94 (patch)
tree6d54071f41a3980e45a2eda128deb1b42f5cb1b4
parentf4226d9ea400e7124120571b1e89504c79f2e953 (diff)
ext4: fix end of leaf partial cluster handling
The fix in commit ad6599ab3ac9 ("ext4: fix premature freeing of partial clusters split across leaf blocks"), intended to avoid dereferencing an invalid extent pointer when determining whether a partial cluster should be freed, wasn't quite good enough. Assure that at least one extent remains at the start of the leaf once the hole has been punched. Otherwise, the pointer to the extent to the right of the hole will be invalid and a partial cluster will be incorrectly freed. Set partial_cluster to 0 when we can tell we've hit the left edge of the punched region within the leaf. This prevents incorrect freeing of a partial cluster when ext4_ext_rm_leaf is called one last time during extent tree traversal after the punched region has been removed. Adjust comments to reflect code changes and a correction. Remove a bit of dead code. Signed-off-by: Eric Whitney <enwlinux@gmail.com> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
-rw-r--r--fs/ext4/extents.c36
1 files changed, 17 insertions, 19 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 57794a7a435c..859ab37efa6f 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -2574,15 +2574,16 @@ static int ext4_remove_blocks(handle_t *handle, struct inode *inode,
2574 2574
2575/* 2575/*
2576 * ext4_ext_rm_leaf() Removes the extents associated with the 2576 * ext4_ext_rm_leaf() Removes the extents associated with the
2577 * blocks appearing between "start" and "end", and splits the extents 2577 * blocks appearing between "start" and "end". Both "start"
2578 * if "start" and "end" appear in the same extent 2578 * and "end" must appear in the same extent or EIO is returned.
2579 * 2579 *
2580 * @handle: The journal handle 2580 * @handle: The journal handle
2581 * @inode: The files inode 2581 * @inode: The files inode
2582 * @path: The path to the leaf 2582 * @path: The path to the leaf
2583 * @partial_cluster: The cluster which we'll have to free if all extents 2583 * @partial_cluster: The cluster which we'll have to free if all extents
2584 * has been released from it. It gets negative in case 2584 * has been released from it. However, if this value is
2585 * that the cluster is still used. 2585 * negative, it's a cluster just to the right of the
2586 * punched region and it must not be freed.
2586 * @start: The first block to remove 2587 * @start: The first block to remove
2587 * @end: The last block to remove 2588 * @end: The last block to remove
2588 */ 2589 */
@@ -2730,8 +2731,7 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
2730 sizeof(struct ext4_extent)); 2731 sizeof(struct ext4_extent));
2731 } 2732 }
2732 le16_add_cpu(&eh->eh_entries, -1); 2733 le16_add_cpu(&eh->eh_entries, -1);
2733 } else if (*partial_cluster > 0) 2734 }
2734 *partial_cluster = 0;
2735 2735
2736 err = ext4_ext_dirty(handle, inode, path + depth); 2736 err = ext4_ext_dirty(handle, inode, path + depth);
2737 if (err) 2737 if (err)
@@ -2750,20 +2750,18 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
2750 /* 2750 /*
2751 * If there's a partial cluster and at least one extent remains in 2751 * If there's a partial cluster and at least one extent remains in
2752 * the leaf, free the partial cluster if it isn't shared with the 2752 * the leaf, free the partial cluster if it isn't shared with the
2753 * current extent. If there's a partial cluster and no extents 2753 * current extent. If it is shared with the current extent
2754 * remain in the leaf, it can't be freed here. It can only be 2754 * we zero partial_cluster because we've reached the start of the
2755 * freed when it's possible to determine if it's not shared with 2755 * truncated/punched region and we're done removing blocks.
2756 * any other extent - when the next leaf is processed or when space
2757 * removal is complete.
2758 */ 2756 */
2759 if (*partial_cluster > 0 && eh->eh_entries && 2757 if (*partial_cluster > 0 && ex >= EXT_FIRST_EXTENT(eh)) {
2760 (EXT4_B2C(sbi, ext4_ext_pblock(ex) + ex_ee_len - 1) != 2758 pblk = ext4_ext_pblock(ex) + ex_ee_len - 1;
2761 *partial_cluster)) { 2759 if (*partial_cluster != (long long) EXT4_B2C(sbi, pblk)) {
2762 int flags = get_default_free_blocks_flags(inode); 2760 ext4_free_blocks(handle, inode, NULL,
2763 2761 EXT4_C2B(sbi, *partial_cluster),
2764 ext4_free_blocks(handle, inode, NULL, 2762 sbi->s_cluster_ratio,
2765 EXT4_C2B(sbi, *partial_cluster), 2763 get_default_free_blocks_flags(inode));
2766 sbi->s_cluster_ratio, flags); 2764 }
2767 *partial_cluster = 0; 2765 *partial_cluster = 0;
2768 } 2766 }
2769 2767