121 lines
3.2 KiB
Diff
121 lines
3.2 KiB
Diff
From: Ashish Sangwan <ashishsangwan2@gmail.com>
|
|
Date: Sun, 22 Jul 2012 22:49:08 -0400
|
|
Subject: [PATCH 2/3] ext4: fix hole punch failure when depth is greater than 0
|
|
|
|
commit 968dee77220768a5f52cf8b21d0bdb73486febef upstream.
|
|
|
|
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>
|
|
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
|
---
|
|
fs/ext4/extents.c | 46 +++++++++++++++++++++++++++++-----------------
|
|
1 file changed, 29 insertions(+), 17 deletions(-)
|
|
|
|
--- a/fs/ext4/extents.c
|
|
+++ b/fs/ext4/extents.c
|
|
@@ -2518,10 +2518,10 @@ static int ext4_ext_remove_space(struct
|
|
{
|
|
struct super_block *sb = inode->i_sb;
|
|
int depth = ext_depth(inode);
|
|
- struct ext4_ext_path *path;
|
|
+ struct ext4_ext_path *path = NULL;
|
|
ext4_fsblk_t partial_cluster = 0;
|
|
handle_t *handle;
|
|
- int i, err;
|
|
+ int i = 0, err;
|
|
|
|
ext_debug("truncate since %u to %u\n", start, end);
|
|
|
|
@@ -2554,8 +2554,12 @@ again:
|
|
}
|
|
depth = ext_depth(inode);
|
|
ex = path[depth].p_ext;
|
|
- if (!ex)
|
|
+ if (!ex) {
|
|
+ ext4_ext_drop_refs(path);
|
|
+ kfree(path);
|
|
+ path = NULL;
|
|
goto cont;
|
|
+ }
|
|
|
|
ee_block = le32_to_cpu(ex->ee_block);
|
|
|
|
@@ -2585,8 +2589,6 @@ again:
|
|
if (err < 0)
|
|
goto out;
|
|
}
|
|
- ext4_ext_drop_refs(path);
|
|
- kfree(path);
|
|
}
|
|
cont:
|
|
|
|
@@ -2595,19 +2597,27 @@ cont:
|
|
* after i_size and walking into the tree depth-wise.
|
|
*/
|
|
depth = ext_depth(inode);
|
|
- path = kzalloc(sizeof(struct ext4_ext_path) * (depth + 1), GFP_NOFS);
|
|
- if (path == NULL) {
|
|
- ext4_journal_stop(handle);
|
|
- return -ENOMEM;
|
|
- }
|
|
- path[0].p_depth = depth;
|
|
- path[0].p_hdr = ext_inode_hdr(inode);
|
|
-
|
|
- if (ext4_ext_check(inode, path[0].p_hdr, depth)) {
|
|
- err = -EIO;
|
|
- goto out;
|
|
+ if (path) {
|
|
+ int k = i = depth;
|
|
+ while (--k > 0)
|
|
+ path[k].p_block =
|
|
+ le16_to_cpu(path[k].p_hdr->eh_entries)+1;
|
|
+ } else {
|
|
+ path = kzalloc(sizeof(struct ext4_ext_path) * (depth + 1),
|
|
+ GFP_NOFS);
|
|
+ if (path == NULL) {
|
|
+ ext4_journal_stop(handle);
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+ path[0].p_depth = depth;
|
|
+ path[0].p_hdr = ext_inode_hdr(inode);
|
|
+
|
|
+ if (ext4_ext_check(inode, path[0].p_hdr, depth)) {
|
|
+ err = -EIO;
|
|
+ goto out;
|
|
+ }
|
|
}
|
|
- i = err = 0;
|
|
+ err = 0;
|
|
|
|
while (i >= 0 && err == 0) {
|
|
if (i == depth) {
|
|
@@ -2721,8 +2731,10 @@ cont:
|
|
out:
|
|
ext4_ext_drop_refs(path);
|
|
kfree(path);
|
|
- if (err == -EAGAIN)
|
|
+ if (err == -EAGAIN) {
|
|
+ path = NULL;
|
|
goto again;
|
|
+ }
|
|
ext4_journal_stop(handle);
|
|
|
|
return err;
|