Commit bb491ce6 authored by Andreas Gruenbacher's avatar Andreas Gruenbacher Committed by Bob Peterson

gfs2: Check for the end of metadata in punch_hole

When punching a hole or truncating an inode down to a given size, also
check if the truncate point / start of the hole is within the range we
have metadata for.  Otherwise, we can end up freeing blocks that
shouldn't be freed, corrupting the inode, or crashing the machine when
trying to punch a hole into the void.

When growing an inode via truncate, we set the new size but we don't
allocate additional levels of indirect blocks and grow the inode height.
When shrinking that inode again, the new size may still point beyond the
end of the inode's metadata.

Fixes xfstest generic/476.
Debugged-by: default avatarBob Peterson <rpeterso@redhat.com>
Signed-off-by: default avatarAndreas Gruenbacher <agruenba@redhat.com>
Signed-off-by: default avatarBob Peterson <rpeterso@redhat.com>
parent ee6ed857
...@@ -1351,6 +1351,7 @@ static inline bool walk_done(struct gfs2_sbd *sdp, ...@@ -1351,6 +1351,7 @@ static inline bool walk_done(struct gfs2_sbd *sdp,
static int punch_hole(struct gfs2_inode *ip, u64 offset, u64 length) static int punch_hole(struct gfs2_inode *ip, u64 offset, u64 length)
{ {
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
u64 maxsize = sdp->sd_heightsize[ip->i_height];
struct metapath mp = {}; struct metapath mp = {};
struct buffer_head *dibh, *bh; struct buffer_head *dibh, *bh;
struct gfs2_holder rd_gh; struct gfs2_holder rd_gh;
...@@ -1366,6 +1367,14 @@ static int punch_hole(struct gfs2_inode *ip, u64 offset, u64 length) ...@@ -1366,6 +1367,14 @@ static int punch_hole(struct gfs2_inode *ip, u64 offset, u64 length)
u64 prev_bnr = 0; u64 prev_bnr = 0;
__be64 *start, *end; __be64 *start, *end;
if (offset >= maxsize) {
/*
* The starting point lies beyond the allocated meta-data;
* there are no blocks do deallocate.
*/
return 0;
}
/* /*
* The start position of the hole is defined by lblock, start_list, and * The start position of the hole is defined by lblock, start_list, and
* start_aligned. The end position of the hole is defined by lend, * start_aligned. The end position of the hole is defined by lend,
...@@ -1379,7 +1388,6 @@ static int punch_hole(struct gfs2_inode *ip, u64 offset, u64 length) ...@@ -1379,7 +1388,6 @@ static int punch_hole(struct gfs2_inode *ip, u64 offset, u64 length)
*/ */
if (length) { if (length) {
u64 maxsize = sdp->sd_heightsize[ip->i_height];
u64 end_offset = offset + length; u64 end_offset = offset + length;
u64 lend; u64 lend;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment