Gitweb:
http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=e6bb3d27...
Commit: e6bb3d27cd08c50f04825f5873023d19534c5fe6
Parent: 803f914e2d9a6397bf09dabede18590b0a0fb29a
Author: Andrew Price <anprice(a)redhat.com>
AuthorDate: Wed Jan 18 15:14:57 2017 +0000
Committer: Andrew Price <anprice(a)redhat.com>
CommitterDate: Wed Jan 18 16:21:54 2017 +0000
gfs2_edit savemeta: Save corrupt rgrp headers
Previously, savemeta used gfs2_rgrp_read() to read resource groups. This
includes a metadata check which fails the read if the resource groups
are corrupt. Since we want to save corruption in order to analyze it, we
need to read the rgrp headers without checking them. Use a new,
simplified rgrp_read() function for that.
Also avoid the effect of a similar metadata check in
get_gfs_struct_info() when saving rgrps.
Signed-off-by: Andrew Price <anprice(a)redhat.com>
---
gfs2/edit/savemeta.c | 34 ++++++++++++++++++++++++++++++++--
1 files changed, 32 insertions(+), 2 deletions(-)
diff --git a/gfs2/edit/savemeta.c b/gfs2/edit/savemeta.c
index da24645..dee405b 100644
--- a/gfs2/edit/savemeta.c
+++ b/gfs2/edit/savemeta.c
@@ -417,7 +417,8 @@ static int save_bh(struct metafd *mfd, struct gfs2_buffer_head
*savebh, uint64_t
because we want to know if the source inode is a system inode
not the block within the inode "blk". They may or may not
be the same thing. */
- if (get_gfs_struct_info(savebh, owner, blktype, &blklen) &&
!block_is_systemfile(owner))
+ if (get_gfs_struct_info(savebh, owner, blktype, &blklen) &&
+ !block_is_systemfile(owner) && owner != 0)
return 0; /* Not metadata, and not system file, so skip it */
/* No need to save trailing zeroes */
@@ -770,12 +771,41 @@ static void save_allocated(struct rgrp_tree *rgd, struct metafd
*mfd)
free(ibuf);
}
+/* We don't use gfs2_rgrp_read() here as it checks for metadata sanity and we
+ want to save rgrp headers even if they're corrupt. */
+static int rgrp_read(struct gfs2_sbd *sdp, struct rgrp_tree *rgd)
+{
+ unsigned x, length = rgd->ri.ri_length;
+ struct gfs2_buffer_head **bhs;
+
+ if (length == 0 || gfs2_check_range(sdp, rgd->ri.ri_addr))
+ return -1;
+
+ bhs = calloc(length, sizeof(struct gfs2_buffer_head *));
+ if (bhs == NULL)
+ return -1;
+
+ if (breadm(sdp, bhs, length, rgd->ri.ri_addr)) {
+ free(bhs);
+ return -1;
+ }
+ for (x = 0; x < length; x++)
+ rgd->bits[x].bi_bh = bhs[x];
+
+ if (sdp->gfs1)
+ gfs_rgrp_in((struct gfs_rgrp *)&rgd->rg, rgd->bits[0].bi_bh);
+ else
+ gfs2_rgrp_in(&rgd->rg, rgd->bits[0].bi_bh);
+ free(bhs);
+ return 0;
+}
+
static void save_rgrp(struct metafd *mfd, struct rgrp_tree *rgd, int withcontents)
{
uint64_t addr = rgd->ri.ri_addr;
uint32_t i;
- if (gfs2_rgrp_read(&sbd, rgd))
+ if (rgrp_read(&sbd, rgd))
return;
log_debug("RG at %"PRIu64" (0x%"PRIx64") is %u long\n",
addr, addr, rgd->ri.ri_length);