From: Bob Peterson <rpeterso@redhat.com>
To: cluster-devel.redhat.com
Subject: [Cluster-devel] [gfs2-utils patch] fsck.gfs2: Add ability to detect journal inode indirect block corruption
Date: Wed, 31 Jul 2013 10:05:20 -0400 (EDT) [thread overview]
Message-ID: <1025566429.1893055.1375279520919.JavaMail.root@redhat.com> (raw)
In-Reply-To: <1260058444.1878852.1375279288709.JavaMail.root@redhat.com>
Hi,
This patch gives the journal replay portion of fsck.gfs2 the ability to
do basic sanity checks on the indirect blocks associated with journals.
If corrupt indirect blocks are found, the journal is considered damaged,
and should be rebuilt by pass1.
Regards,
Bob Peterson
Red Hat File Systems
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
---
diff --git a/gfs2/fsck/fs_recovery.c b/gfs2/fsck/fs_recovery.c
index d07a515..8b82695 100644
--- a/gfs2/fsck/fs_recovery.c
+++ b/gfs2/fsck/fs_recovery.c
@@ -10,6 +10,7 @@
#include "fsck.h"
#include "fs_recovery.h"
#include "libgfs2.h"
+#include "metawalk.h"
#include "util.h"
#define JOURNAL_NAME_SIZE 16
@@ -559,6 +560,63 @@ reinit:
return error;
}
+/* We can't use the rangecheck function from pass1 because we haven't gone
+ * through initialization properly yet. */
+static int rangecheck_jblock(struct gfs2_inode *ip, uint64_t block)
+{
+ if((block > ip->i_sbd->fssize) || (block <= ip->i_sbd->sb_addr)) {
+ log_info( _("Bad block pointer (out of range) found in "
+ "journal inode %lld (0x%llx).\n"),
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr);
+ return meta_error; /* Exits check_metatree quicker */
+ }
+ return meta_is_good;
+}
+
+static int rangecheck_jmeta(struct gfs2_inode *ip, uint64_t block,
+ struct gfs2_buffer_head **bh, int h,
+ int *is_valid, int *was_duplicate,
+ void *private)
+{
+ int rc;
+
+ *bh = NULL;
+ *was_duplicate = 0;
+ *is_valid = 0;
+ rc = rangecheck_jblock(ip, block);
+ if (rc == meta_is_good) {
+ *bh = bread(ip->i_sbd, block);
+ *is_valid = (gfs2_check_meta(*bh, GFS2_METATYPE_IN) == 0);
+ if (!(*is_valid)) {
+ log_err( _("Journal at block %lld (0x%llx) has a bad "
+ "indirect block pointer %lld (0x%llx) "
+ "(points to something that is not an "
+ "indirect block).\n"),
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)block,
+ (unsigned long long)block);
+ brelse(*bh);
+ return meta_skip_further;
+ }
+ }
+ return rc;
+}
+
+static int rangecheck_jdata(struct gfs2_inode *ip, uint64_t metablock,
+ uint64_t block, void *private)
+{
+ return rangecheck_jblock(ip, block);
+}
+
+struct metawalk_fxns rangecheck_journal = {
+ .private = NULL,
+ .invalid_meta_is_fatal = 1,
+ .check_metalist = rangecheck_jmeta,
+ .check_data = rangecheck_jdata,
+};
+
/*
* replay_journals - replay the journals
* sdp: the super block
@@ -583,9 +641,33 @@ int replay_journals(struct gfs2_sbd *sdp, int preen, int force_check,
sdp->jsize = GFS2_DEFAULT_JSIZE;
for(i = 0; i < sdp->md.journals; i++) {
+ if (sdp->md.journal[i]) {
+ struct rgrp_tree rgd;
+
+ /* The real rgrp tree hasn't been built at this point,
+ * so we need to dummy one up that covers the whole
+ * file system so basic functions in check_metatree
+ * don't segfault. */
+ rgd.start = sdp->sb_addr + 1;
+ rgd.length = 1;
+ rgd.bh = NULL;
+ rgd.ri.ri_addr = sdp->sb_addr + 1;
+ rgd.ri.ri_data0 = sdp->sb_addr + 2;
+ rgd.ri.ri_data = sdp->fssize - (sdp->sb_addr + 2);
+
+ sdp->rgtree.osi_node = (struct osi_node *)&rgd;
+ error = check_metatree(sdp->md.journal[i],
+ &rangecheck_journal);
+ sdp->rgtree.osi_node = NULL;
+ if (error)
+ /* Don't use fsck_inode_put here because it's a
+ system file and we need to dismantle it. */
+ inode_put(&sdp->md.journal[i]);
+ }
if (!sdp->md.journal[i]) {
log_err(_("File system journal \"journal%d\" is "
- "missing: pass1 will try to recreate it.\n"),
+ "missing or corrupt: pass1 will try to "
+ "recreate it.\n"),
i);
continue;
}
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 84366a2..79ee241 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -1236,9 +1236,12 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
for (tmp = prev_list->next; tmp != prev_list; tmp = tmp->next){
bh = osi_list_entry(tmp, struct gfs2_buffer_head,
b_altlist);
+ if (gfs2_check_meta(bh, iblk_type)) {
+ if (pass->invalid_meta_is_fatal)
+ return meta_error;
- if (gfs2_check_meta(bh, iblk_type))
continue;
+ }
/* Now check the metadata itself */
for (ptr = (uint64_t *)(bh->b_data + head_size);
@@ -1284,6 +1287,9 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
"%llu (0x%llx)\n"),
(unsigned long long)block,
(unsigned long long)block);
+ if (pass->invalid_meta_is_fatal)
+ return meta_error;
+
continue;
}
if (was_duplicate) {
@@ -1298,6 +1304,9 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
"%lld (0x%llx)\n"),
(unsigned long long)block,
(unsigned long long)block);
+ if (pass->invalid_meta_is_fatal)
+ return meta_error;
+
continue;
}
if (!nbh)
diff --git a/gfs2/fsck/metawalk.h b/gfs2/fsck/metawalk.h
index a5a51c2..5e30bfe 100644
--- a/gfs2/fsck/metawalk.h
+++ b/gfs2/fsck/metawalk.h
@@ -93,6 +93,7 @@ enum meta_check_rc {
*/
struct metawalk_fxns {
void *private;
+ int invalid_meta_is_fatal;
int (*check_leaf_depth) (struct gfs2_inode *ip, uint64_t leaf_no,
int ref_count, struct gfs2_buffer_head *lbh);
int (*check_leaf) (struct gfs2_inode *ip, uint64_t block,
diff --git a/gfs2/fsck/util.c b/gfs2/fsck/util.c
index 7ee49be..05989fe 100644
--- a/gfs2/fsck/util.c
+++ b/gfs2/fsck/util.c
@@ -499,6 +499,8 @@ int gfs2_blockmap_set(struct gfs2_bmap *bmap, uint64_t bblock,
static unsigned char *byte;
static uint64_t b;
+ if (!bmap)
+ return 0;
if (bblock > bmap->size)
return -1;
parent reply other threads:[~2013-07-31 14:05 UTC|newest]
Thread overview: expand[flat|nested] mbox.gz Atom feed
[parent not found: <1260058444.1878852.1375279288709.JavaMail.root@redhat.com>]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1025566429.1893055.1375279520919.JavaMail.root@redhat.com \
--to=rpeterso@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).