gfs2-utils: master - gfs2_edit savemeta: Factor out the bh saving code
by Andrew Price
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=4e60fdf1...
Commit: 4e60fdf18f5ece9e439ae66fef966eec1f38812a
Parent: 1e878368293eb55ce56f1a21730b87e608a9c5d4
Author: Andrew Price <anprice(a)redhat.com>
AuthorDate: Fri Feb 12 15:16:36 2016 +0000
Committer: Andrew Price <anprice(a)redhat.com>
CommitterDate: Thu Jan 12 16:20:33 2017 +0000
gfs2_edit savemeta: Factor out the bh saving code
save_block() accepts a block number, reads it and saves it, which makes
it tricky to save an already-read block without reading it a second
time. Split out the bh saving part of save_block() into save_bh() to
make things more flexible.
Also switch the return value of save_block to only convey error/success
and return the block type through an optional pointer argument instead.
Signed-off-by: Andrew Price <anprice(a)redhat.com>
---
gfs2/edit/savemeta.c | 74 +++++++++++++++++++++++++++----------------------
1 files changed, 41 insertions(+), 33 deletions(-)
diff --git a/gfs2/edit/savemeta.c b/gfs2/edit/savemeta.c
index db9a947..3e8dae0 100644
--- a/gfs2/edit/savemeta.c
+++ b/gfs2/edit/savemeta.c
@@ -208,14 +208,16 @@ static int get_gfs_struct_info(struct gfs2_buffer_head *lbh, uint64_t owner,
struct gfs2_meta_header mh;
struct gfs2_inode *inode;
- *block_type = 0;
+ if (block_type != NULL)
+ *block_type = 0;
*gstruct_len = sbd.bsize;
gfs2_meta_header_in(&mh, lbh);
if (mh.mh_magic != GFS2_MAGIC)
return -1;
- *block_type = mh.mh_type;
+ if (block_type != NULL)
+ *block_type = mh.mh_type;
switch (mh.mh_type) {
case GFS2_METATYPE_SB: /* 1 (superblock) */
@@ -405,32 +407,19 @@ static int savemetaclose(struct metafd *mfd)
return close(mfd->fd);
}
-static int save_block(int fd, struct metafd *mfd, uint64_t blk, uint64_t owner)
+static int save_bh(struct metafd *mfd, struct gfs2_buffer_head *savebh, uint64_t owner, int *blktype)
{
- int blktype, blklen;
- size_t outsz;
- struct gfs2_buffer_head *savebh;
struct saved_metablock *savedata;
-
- if (gfs2_check_range(&sbd, blk) && blk != sbd.sb_addr) {
- fprintf(stderr, "\nWarning: bad block pointer '0x%llx' "
- "ignored in block (block %llu (0x%llx))",
- (unsigned long long)blk,
- (unsigned long long)owner, (unsigned long long)owner);
- return 0;
- }
- savebh = bread(&sbd, blk);
+ size_t outsz;
+ int blklen;
/* If this isn't metadata and isn't a system file, we don't want it.
Note that we're checking "owner" here rather than blk. That's
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)) {
- brelse(savebh);
+ if (get_gfs_struct_info(savebh, owner, blktype, &blklen) && !block_is_systemfile(owner))
return 0; /* Not metadata, and not system file, so skip it */
- }
/* No need to save trailing zeroes */
for (; blklen > 0 && savebh->b_data[blklen - 1] == '\0'; blklen--);
@@ -444,7 +433,7 @@ static int save_block(int fd, struct metafd *mfd, uint64_t blk, uint64_t owner)
perror("Failed to save block");
exit(1);
}
- savedata->blk = cpu_to_be64(blk);
+ savedata->blk = cpu_to_be64(savebh->b_blocknr);
savedata->siglen = cpu_to_be16(blklen);
memcpy(savedata->buf, savebh->b_data, blklen);
@@ -459,8 +448,27 @@ static int save_block(int fd, struct metafd *mfd, uint64_t blk, uint64_t owner)
blks_saved++;
free(savedata);
+ return 0;
+}
+
+static int save_block(int fd, struct metafd *mfd, uint64_t blk, uint64_t owner, int *blktype)
+{
+ struct gfs2_buffer_head *savebh;
+ int err;
+
+ if (gfs2_check_range(&sbd, blk) && blk != sbd.sb_addr) {
+ fprintf(stderr, "\nWarning: bad block pointer '0x%llx' "
+ "ignored in block (block %llu (0x%llx))",
+ (unsigned long long)blk,
+ (unsigned long long)owner, (unsigned long long)owner);
+ return 0;
+ }
+ savebh = bread(&sbd, blk);
+ if (savebh == NULL)
+ return 1;
+ err = save_bh(mfd, savebh, owner, blktype);
brelse(savebh);
- return blktype;
+ return err;
}
/*
@@ -484,7 +492,7 @@ static void save_ea_block(struct metafd *mfd, struct gfs2_buffer_head *metabh, u
b = (uint64_t *)(metabh->b_data);
b += charoff + i;
blk = be64_to_cpu(*b);
- save_block(sbd.device_fd, mfd, blk, owner);
+ save_block(sbd.device_fd, mfd, blk, owner, NULL);
}
if (!ea.ea_rec_len)
break;
@@ -514,7 +522,7 @@ static void save_indirect_blocks(struct metafd *mfd, osi_list_t *cur_list,
if (indir_block == old_block)
continue;
old_block = indir_block;
- blktype = save_block(sbd.device_fd, mfd, indir_block, owner);
+ save_block(sbd.device_fd, mfd, indir_block, owner, &blktype);
if (blktype == GFS2_METATYPE_EA) {
nbh = bread(&sbd, indir_block);
save_ea_block(mfd, nbh, owner);
@@ -625,7 +633,7 @@ static void save_inode_data(struct metafd *mfd, uint64_t iblk)
mybh = bread(&sbd, leaf_no);
warm_fuzzy_stuff(iblk, FALSE);
if (gfs2_check_meta(mybh, GFS2_METATYPE_LF) == 0)
- save_block(sbd.device_fd, mfd, leaf_no, iblk);
+ save_block(sbd.device_fd, mfd, leaf_no, iblk, NULL);
brelse(mybh);
}
}
@@ -634,7 +642,7 @@ static void save_inode_data(struct metafd *mfd, uint64_t iblk)
struct gfs2_buffer_head *lbh;
lbh = bread(&sbd, inode->i_di.di_eattr);
- save_block(sbd.device_fd, mfd, inode->i_di.di_eattr, iblk);
+ save_block(sbd.device_fd, mfd, inode->i_di.di_eattr, iblk, NULL);
gfs2_meta_header_in(&mh, lbh);
if (mh.mh_magic == GFS2_MAGIC &&
mh.mh_type == GFS2_METATYPE_EA)
@@ -644,8 +652,8 @@ static void save_inode_data(struct metafd *mfd, uint64_t iblk)
save_indirect_blocks(mfd, cur_list, lbh, iblk, 2, 2);
else {
if (mh.mh_magic == GFS2_MAGIC) /* if it's metadata */
- save_block(sbd.device_fd, mfd,
- inode->i_di.di_eattr, iblk);
+ save_block(sbd.device_fd, mfd, inode->i_di.di_eattr,
+ iblk, NULL);
fprintf(stderr,
"\nWarning: corrupt extended "
"attribute at block %llu (0x%llx) "
@@ -722,7 +730,7 @@ static void save_allocated(struct rgrp_tree *rgd, struct metafd *mfd)
for (j = 0; j < m; j++) {
blk = ibuf[j];
warm_fuzzy_stuff(blk, FALSE);
- blktype = save_block(sbd.device_fd, mfd, blk, blk);
+ save_block(sbd.device_fd, mfd, blk, blk, &blktype);
if (blktype == GFS2_METATYPE_DI)
save_inode_data(mfd, blk);
}
@@ -734,7 +742,7 @@ static void save_allocated(struct rgrp_tree *rgd, struct metafd *mfd)
* If we don't, we may run into metadata allocation issues. */
m = lgfs2_bm_scan(rgd, i, ibuf, GFS2_BLKST_UNLINKED);
for (j = 0; j < m; j++) {
- save_block(sbd.device_fd, mfd, blk, blk);
+ save_block(sbd.device_fd, mfd, blk, blk, NULL);
}
}
free(ibuf);
@@ -826,7 +834,7 @@ void savemeta(char *out_fn, int saveoption, int gziplevel)
exit(1);
}
/* Save off the superblock */
- save_block(sbd.device_fd, &mfd, GFS2_SB_ADDR * GFS2_BASIC_BLOCK / sbd.bsize, 0);
+ save_block(sbd.device_fd, &mfd, GFS2_SB_ADDR * GFS2_BASIC_BLOCK / sbd.bsize, 0, NULL);
/* If this is gfs1, save off the rindex because it's not
part of the file system as it is in gfs2. */
if (sbd.gfs1) {
@@ -834,7 +842,7 @@ void savemeta(char *out_fn, int saveoption, int gziplevel)
int j;
blk = sbd1->sb_rindex_di.no_addr;
- save_block(sbd.device_fd, &mfd, blk, blk);
+ save_block(sbd.device_fd, &mfd, blk, blk, NULL);
save_inode_data(&mfd, blk);
/* In GFS1, journals aren't part of the RG space */
for (j = 0; j < journals_found; j++) {
@@ -842,7 +850,7 @@ void savemeta(char *out_fn, int saveoption, int gziplevel)
for (blk = journal_blocks[j];
blk < journal_blocks[j] + gfs1_journal_size;
blk++)
- save_block(sbd.device_fd, &mfd, blk, blk);
+ save_block(sbd.device_fd, &mfd, blk, blk, NULL);
}
}
/* Walk through the resource groups saving everything within */
@@ -861,7 +869,7 @@ void savemeta(char *out_fn, int saveoption, int gziplevel)
for (blk = rgd->ri.ri_addr;
blk < rgd->ri.ri_data0; blk++) {
warm_fuzzy_stuff(blk, FALSE);
- save_block(sbd.device_fd, &mfd, blk, blk);
+ save_block(sbd.device_fd, &mfd, blk, blk, NULL);
}
/* Save off the other metadata: inodes, etc. if mode is not 'savergs' */
if (saveoption != 2) {
7 years, 3 months
gfs2-utils: master - gfs2_edit: Add rgrepair option
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=1e878368...
Commit: 1e878368293eb55ce56f1a21730b87e608a9c5d4
Parent: dcbde3c14ae223e36daca420bb3a8f3a269a9398
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Fri Dec 16 17:11:36 2016 -0600
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Mon Dec 19 07:34:53 2016 -0600
gfs2_edit: Add rgrepair option
This patch adds a new option, rgrepair, to gfs2_edit. Its purpose
is to traverse all the resource groups in the rindex (assuming that
the rindex is valid), and for each entry, verify it's really an rgrp,
and that its bitmaps are bitmaps. If it finds an rgrp or bitmap block
that's corrupt, it overwrites it with data that looks like a valid
rgrp and/or bitmap. Then it looks for dinodes in that range of
blocks. Any dinodes are marked as dinodes in the newly rewritten
bitmap. Everything else is marked as a data block. That will allow
fsck.gfs2 to try to straighten out the data from the free blocks.
Signed-off-by: Bob Peterson <rpeterso(a)redhat.com>
---
gfs2/edit/hexedit.c | 134 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 134 insertions(+), 0 deletions(-)
diff --git a/gfs2/edit/hexedit.c b/gfs2/edit/hexedit.c
index 40a719e..cd3f084 100644
--- a/gfs2/edit/hexedit.c
+++ b/gfs2/edit/hexedit.c
@@ -2167,6 +2167,7 @@ static void usage(void)
fprintf(stderr,"rgflags rgnum [new flags] - print or modify flags for rg #rgnum (0 - X)\n");
fprintf(stderr,"rgbitmaps <rgnum> - print out the bitmaps for rgrp "
"rgnum.\n");
+ fprintf(stderr,"rgrepair - find and repair damaged rgrp.\n");
fprintf(stderr,"-V prints version number.\n");
fprintf(stderr,"-c 1 selects alternate color scheme 1\n");
fprintf(stderr,"-d prints details (for printing journals)\n");
@@ -2259,6 +2260,135 @@ static void getgziplevel(char *argv[], int *i)
(*i)++;
}
+static int count_dinode_blks(struct rgrp_tree *rgd, int bitmap,
+ struct gfs2_buffer_head *rbh)
+{
+ struct gfs2_buffer_head *tbh;
+ uint64_t b;
+ int dinodes = 0;
+ char *byte, cur_state, new_state;
+ int bit, off;
+
+ if (bitmap)
+ off = sizeof(struct gfs2_meta_header);
+ else
+ off = sizeof(struct gfs2_rgrp);
+
+ for (b = 0; b < rgd->bits[bitmap].bi_len << GFS2_BIT_SIZE; b++) {
+ tbh = bread(&sbd, rgd->ri.ri_data0 +
+ rgd->bits[bitmap].bi_start + b);
+ byte = rbh->b_data + off + (b / GFS2_NBBY);
+ bit = (b % GFS2_NBBY) * GFS2_BIT_SIZE;
+ if (gfs2_check_meta(tbh, GFS2_METATYPE_DI) == 0) {
+ dinodes++;
+ new_state = GFS2_BLKST_DINODE;
+ } else {
+ new_state = GFS2_BLKST_USED;
+ }
+ cur_state = (*byte >> bit) & GFS2_BIT_MASK;
+ *byte ^= cur_state << bit;
+ *byte |= new_state << bit;
+ brelse(tbh);
+ }
+ bmodified(rbh);
+ return dinodes;
+}
+
+static int count_dinode_bits(struct gfs2_buffer_head *rbh)
+{
+ uint64_t blk;
+ struct gfs2_meta_header *mh = (struct gfs2_meta_header *)rbh->b_data;
+ char *byte;
+ int bit;
+ int dinodes = 0;
+
+ if (be32_to_cpu(mh->mh_type) == GFS2_METATYPE_RG)
+ blk = sizeof(struct gfs2_rgrp);
+ else
+ blk = sizeof(struct gfs2_meta_header);
+
+ for (; blk < sbd.bsize; blk++) {
+ byte = rbh->b_data + (blk / GFS2_NBBY);
+ bit = (blk % GFS2_NBBY) * GFS2_BIT_SIZE;
+ if (((*byte >> bit) & GFS2_BIT_MASK) == GFS2_BLKST_DINODE)
+ dinodes++;
+ }
+ return dinodes;
+}
+
+static void rg_repair(void)
+{
+ struct gfs2_buffer_head *rbh;
+ struct rgrp_tree *rgd;
+ struct osi_node *n;
+ int b;
+ int rgs_fixed = 0;
+ int dinodes_found = 0, dinodes_total = 0;
+
+ /* Walk through the resource groups saving everything within */
+ for (n = osi_first(&sbd.rgtree); n; n = osi_next(n)) {
+ rgd = (struct rgrp_tree *)n;
+ if (gfs2_rgrp_read(&sbd, rgd) == 0) { /* was read in okay */
+ gfs2_rgrp_relse(rgd);
+ continue; /* ignore it */
+ }
+ /* If we get here, it's because we have an rgrp in the rindex
+ file that can't be read in. So attempt to repair it.
+ If we find a damaged rgrp or bitmap, fix the metadata.
+ Then scan all its blocks: if we find a dinode, set the
+ repaired bitmap to GFS2_BLKST_DINODE. Set all others to
+ GFS2_BLKST_USED so fsck can sort it out. If we set them
+ to FREE, fsck would just nuke it all. */
+ printf("Resource group at block %llu (0x%llx) appears to be "
+ "damaged. Attempting to fix it (in reverse order).\n",
+ (unsigned long long)rgd->ri.ri_addr,
+ (unsigned long long)rgd->ri.ri_addr);
+
+ for (b = rgd->ri.ri_length - 1; b >= 0; b--) {
+ int mtype = (b ? GFS2_METATYPE_RB : GFS2_METATYPE_RG);
+ struct gfs2_meta_header *mh;
+
+ printf("Bitmap #%d:", b);
+ rbh = bread(&sbd, rgd->ri.ri_addr + b);
+ if (gfs2_check_meta(rbh, mtype)) { /* wrong type */
+ printf("Damaged. Repairing...");
+ /* Fix the meta header */
+ memset(rbh->b_data, 0, sbd.bsize);
+ mh = (struct gfs2_meta_header *)rbh->b_data;
+ mh->mh_magic = cpu_to_be32(GFS2_MAGIC);
+ mh->mh_type = cpu_to_be32(mtype);
+ if (b)
+ mh->mh_format =
+ cpu_to_be32(GFS2_FORMAT_RB);
+ else
+ mh->mh_format =
+ cpu_to_be32(GFS2_FORMAT_RG);
+ bmodified(rbh);
+ /* Count the dinode blocks */
+ dinodes_found = count_dinode_blks(rgd, b, rbh);
+ } else { /* bitmap info is okay: tally it. */
+ printf("Undamaged. Analyzing...");
+ dinodes_found = count_dinode_bits(rbh);
+ }
+ printf("Dinodes found: %d\n", dinodes_found);
+ dinodes_total += dinodes_found;
+ if (b == 0) { /* rgrp itself was damaged */
+ rgd->rg.rg_dinodes = dinodes_total;
+ rgd->rg.rg_free = 0;
+ }
+ brelse(rbh);
+ }
+ rgs_fixed++;
+ }
+ if (rgs_fixed)
+ printf("%d resource groups fixed.\n"
+ "You should run fsck.gfs2 to reconcile the bitmaps.\n",
+ rgs_fixed);
+ else
+ printf("All resource groups are okay. No repairs needed.\n");
+ exit(0);
+}
+
/* ------------------------------------------------------------------------ */
/* parameterpass1 - pre-processing for command-line parameters */
/* ------------------------------------------------------------------------ */
@@ -2307,6 +2437,8 @@ static void parameterpass1(int argc, char *argv[], int i)
termlines = 0;
else if (!strcmp(argv[i], "rgflags"))
termlines = 0;
+ else if (!strcmp(argv[i], "rgrepair"))
+ termlines = 0;
else if (!strcmp(argv[i], "rg"))
termlines = 0;
else if (!strcasecmp(argv[i], "-x"))
@@ -2483,6 +2615,8 @@ static void process_parameters(int argc, char *argv[], int pass)
for (bmap = 0; bmap < rgd->ri.ri_length; bmap++)
push_block(rgblk + bmap);
}
+ else if (!strcmp(argv[i], "rgrepair"))
+ rg_repair();
else if (!strcasecmp(argv[i], "savemeta")) {
getgziplevel(argv, &i);
savemeta(argv[i+2], 0, gziplevel);
7 years, 3 months