diff mbox

[4/4] ext4: fix end of region partial cluster handling

Message ID 20141121145904.GE30246@wallace
State Accepted, archived
Headers show

Commit Message

Eric Whitney Nov. 21, 2014, 2:59 p.m. UTC
ext4_ext_remove_space() can incorrectly free a partial_cluster if
EAGAIN is encountered while truncating or punching.  Extent removal
should be retried in this case.

It also fails to free a partial cluster when the punched region begins
at the start of a file on that unaligned cluster and where the entire
file has not been punched.  Remove the requirement that all blocks in
the file must have been freed in order to free the partial cluster.

Signed-off-by: Eric Whitney <enwlinux@gmail.com>
---
 fs/ext4/extents.c | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

Comments

Theodore Ts'o Nov. 23, 2014, 6:05 a.m. UTC | #1
On Fri, Nov 21, 2014 at 09:59:04AM -0500, Eric Whitney wrote:
> ext4_ext_remove_space() can incorrectly free a partial_cluster if
> EAGAIN is encountered while truncating or punching.  Extent removal
> should be retried in this case.

I don't see anything in the patch below which retries the extent
removal; am I missing something?

Thanks,

						- Ted
--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Eric Whitney Nov. 23, 2014, 5:05 p.m. UTC | #2
The retry occurs at the end of ext4_ext_remove_space where the code loops
back to the top of the function if err == -EAGAIN, leading to another call
to ext4_ext_rm_leaf.  Nothing new needs to be added - we simply want to
avoid using invalid state to decide whether to free a partial cluster (on
occurrence of -EAGAIN), and the existing retry loop will eventually get us
valid state.

(I actually saw this in testing, but it takes a lot of runs to get there.)

Sorry if I edited down my comment a little too far - I'd be happy to beef
that up if desired.

Thanks,
Eric


* Theodore Ts'o <tytso@mit.edu>:
> On Fri, Nov 21, 2014 at 09:59:04AM -0500, Eric Whitney wrote:
> > ext4_ext_remove_space() can incorrectly free a partial_cluster if
> > EAGAIN is encountered while truncating or punching.  Extent removal
> > should be retried in this case.
> 
> I don't see anything in the patch below which retries the extent
> removal; am I missing something?
> 
> Thanks,
> 
> 						- Ted
--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 841adf0..9eae2f4 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -3009,16 +3009,18 @@  again:
 	trace_ext4_ext_remove_space_done(inode, start, end, depth,
 			partial_cluster, path->p_hdr->eh_entries);
 
-	/* If we still have something in the partial cluster and we have removed
+	/*
+	 * If we still have something in the partial cluster and we have removed
 	 * even the first extent, then we should free the blocks in the partial
-	 * cluster as well. */
-	if (partial_cluster > 0 && path->p_hdr->eh_entries == 0) {
-		int flags = get_default_free_blocks_flags(inode);
-
+	 * cluster as well.  (This code will only run when there are no leaves
+	 * to the immediate left of the truncated/punched region.)
+	 */
+	if (partial_cluster > 0 && err == 0) {
+		/* don't zero partial_cluster since it's not used afterwards */
 		ext4_free_blocks(handle, inode, NULL,
 				 EXT4_C2B(sbi, partial_cluster),
-				 sbi->s_cluster_ratio, flags);
-		partial_cluster = 0;
+				 sbi->s_cluster_ratio,
+				 get_default_free_blocks_flags(inode));
 	}
 
 	/* TODO: flexible tree reduction should be here */