cluster: RHEL511 - gfs2-utils: check and fix bad dinode pointers in gfs1 sb

Abhijith Das adas at fedoraproject.org
Mon Apr 14 20:00:41 UTC 2014


Gitweb:        http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=b5eb3050608dbf3dae895f9d5ef3bade5669ffb1
Commit:        b5eb3050608dbf3dae895f9d5ef3bade5669ffb1
Parent:        34ec3fa0784072b323aa46e23d1193a90b3cd59d
Author:        Abhi Das <adas at redhat.com>
AuthorDate:    Mon Apr 14 14:59:09 2014 -0500
Committer:     Abhi Das <adas at redhat.com>
CommitterDate: Mon Apr 14 14:59:09 2014 -0500

gfs2-utils: check and fix bad dinode pointers in gfs1 sb

This patch makes gfs2_convert check for bad values of sb_seg_size,
sb_quota_di and sb_license_di.
In fsck.gfs2, attempts are made to correct these erroneous values.

This is a port of the following two upstream patches:
https://git.fedorahosted.org/cgit/gfs2-utils.git/commit/?id=d394637d9c6586d8bb5a872f8763b90720f81500
https://git.fedorahosted.org/cgit/gfs2-utils.git/commit/?id=c6d2155f68d45e603d772884fc75f53e7b651d9f

Resolves: rhbz#1084140
Signed-off-by: Abhi Das <adas at redhat.com>
---
 gfs2/convert/gfs2_convert.c |   30 +++++++++++
 gfs2/fsck/initialize.c      |  114 +++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 140 insertions(+), 4 deletions(-)

diff --git a/gfs2/convert/gfs2_convert.c b/gfs2/convert/gfs2_convert.c
index 1b3f44b..d5e2ec9 100644
--- a/gfs2/convert/gfs2_convert.c
+++ b/gfs2/convert/gfs2_convert.c
@@ -1485,6 +1485,24 @@ static int read_gfs1_jiindex(struct gfs2_sbd *sdp)
 	return -1;
 }
 
+static int sanity_check(struct gfs2_sbd *sdp)
+{
+	int error = 0;
+	if (!raw_gfs1_ondisk_sb.sb_quota_di.no_addr) {
+		log_crit("Error: Superblock Quota inode address is NULL\n");
+		error = 1;
+	}
+	if (!raw_gfs1_ondisk_sb.sb_license_di.no_addr) {
+		log_crit("Error: Superblock Statfs inode address is NULL\n");
+		error = 1;
+	}
+	if (!raw_gfs1_ondisk_sb.sb_seg_size) {
+		log_crit("Error: Superblock segment size is zero\n");
+		error = 1;
+	}
+	return error;
+}
+
 /* ------------------------------------------------------------------------- */
 /* init - initialization code                                                */
 /* Returns: 0 on success, -1 on failure                                      */
@@ -2067,6 +2085,18 @@ int main(int argc, char **argv)
 	process_parameters(argc, argv, &opts);
 	error = init(&sb2);
 
+	/*
+	 * Check for some common fs errors
+	 */
+	if (!error) {
+		if (sanity_check(&sb2)) {
+			log_crit("%s is not a clean gfs filesytem. Please use the"
+				 " fsck.gfs2 utility to correct these errors and"
+				 " try again.\n", device);
+			exit(0);
+		}
+	}
+
 	/* ---------------------------------------------- */
 	/* Make them seal their fate.                     */
 	/* ---------------------------------------------- */
diff --git a/gfs2/fsck/initialize.c b/gfs2/fsck/initialize.c
index 789af2c..2842a18 100644
--- a/gfs2/fsck/initialize.c
+++ b/gfs2/fsck/initialize.c
@@ -718,9 +718,26 @@ static int init_system_inodes(struct gfs2_sbd *sdp)
 		sdp->md.next_inum = be64_to_cpu(inumbuf);
 	}
 
-	if (sdp->gfs1)
+	if (sdp->gfs1) {
+		/* In gfs1, the license_di is always 3 blocks after the jindex_di */
+		if ((sbd1->sb_license_di.no_addr != sbd1->sb_jindex_di.no_addr + 3) ||
+		    (sbd1->sb_license_di.no_formal_ino != sbd1->sb_jindex_di.no_addr + 3)) {
+			if (!query( _("The gfs system statfs inode pointer is incorrect. "
+				      "Okay to correct? (y/n) "))) {
+				log_err( _("fsck.gfs2 cannot continue without a valid "
+					   "statfs file; aborting.\n"));
+				goto fail;
+			}
+			sbd1->sb_license_di.no_addr = sbd1->sb_license_di.no_formal_ino
+				= sbd1->sb_jindex_di.no_addr + 3;
+		}
+
 		sdp->md.statfs = inode_read(sdp, sbd1->sb_license_di.no_addr);
-	else
+		if (sdp->md.statfs == NULL) {
+			log_crit(_("Error reading statfs inode: %s\n"), strerror(errno));
+			goto fail;
+		}
+	} else
 		gfs2_lookupi(sdp->master_dir, "statfs", 6, &sdp->md.statfs);
 	if (!sdp->gfs1 && !sdp->md.statfs) {
 		if (!query( _("The gfs2 system statfs inode is missing. "
@@ -760,9 +777,27 @@ static int init_system_inodes(struct gfs2_sbd *sdp)
 		}
 	}
 
-	if (sdp->gfs1)
+	if (sdp->gfs1) {
+		/* In gfs1, the quota_di is always 2 blocks after the jindex_di */
+		if ((sbd1->sb_quota_di.no_addr != sbd1->sb_jindex_di.no_addr + 2) ||
+		    (sbd1->sb_quota_di.no_formal_ino != sbd1->sb_jindex_di.no_addr + 2)) {
+			if (!query( _("The gfs system quota inode pointer is incorrect. "
+				      " Okay to correct? (y/n) "))) {
+				log_err( _("fsck.gfs2 cannot continue without a valid "
+					   "quota file; aborting.\n"));
+				goto fail;
+			}
+			sbd1->sb_quota_di.no_addr = sbd1->sb_quota_di.no_formal_ino
+				= sbd1->sb_jindex_di.no_addr + 2;
+		}
+
 		sdp->md.qinode = inode_read(sdp, sbd1->sb_quota_di.no_addr);
-	else
+		if (sdp->md.qinode == NULL) {
+			log_crit(_("Error reading quota inode: %s\n"), strerror(errno));
+			goto fail;
+		}
+
+	} else
 		gfs2_lookupi(sdp->master_dir, "quota", 5, &sdp->md.qinode);
 	if (!sdp->gfs1 && !sdp->md.qinode) {
 		if (!query( _("The gfs2 system quota inode is missing. "
@@ -1322,6 +1357,71 @@ static int reconstruct_single_journal(struct gfs2_sbd *sdp, int jnum,
 	return 0;
 }
 
+static int reset_journal_seg_size(unsigned int jsize, unsigned int nsegs,
+				  unsigned int bsize)
+{
+	unsigned int seg_size = jsize / (nsegs * bsize);
+	if (!seg_size)
+		seg_size = 16; /* The default with 128MB journal and 4K bsize */
+	if (seg_size != sbd1->sb_seg_size) {
+		sbd1->sb_seg_size = seg_size;
+		if (!query(_("Computed correct journal segment size to %u."
+			     " Reset it? (y/n) "), seg_size)) {
+			log_crit(_("Error: Cannot proceed without a valid journal"
+				   " segment size value.\n"));
+			return -1;
+		}
+		log_err(_("Resetting journal segment size to %u\n"), sbd1->sb_seg_size);
+	}
+	return 0;
+}
+
+static int correct_journal_seg_size(struct gfs2_sbd *sdp)
+{
+	int count;
+	struct gfs_jindex ji_0, ji_1;
+	char buf[sizeof(struct gfs_jindex)];
+	unsigned int jsize = GFS2_DEFAULT_JSIZE * 1024 * 1024;
+
+	count = gfs2_readi(sdp->md.jiinode, buf, 0, sizeof(struct gfs_jindex));
+	if (count != sizeof(struct gfs_jindex)) {
+		log_crit(_("Error %d reading system journal index inode. "
+			   "Aborting\n"), count);
+		return -1;
+	}
+	gfs_jindex_in(&ji_0, buf);
+       
+	if (sdp->md.journals == 1) {
+		if (sbd1->sb_seg_size == 0) {
+			if (!query(_("The gfs2 journal segment size is 0 and a"
+				     " correct value cannot be determined in a"
+				     " single-journal filesystem.\n"
+				     "Continue with default? (y/n) "))) {
+				log_crit(_("Error: Cannot proceed without a valid"
+					   "sb_seg_size value.\n"));
+				return -1;
+			}
+			goto out;
+		}
+		/* Don't mess with sb_seg_size because we don't know what
+		 * it needs to be
+		 */
+		return 0;
+	}
+
+	count = gfs2_readi(sdp->md.jiinode, buf, sizeof(struct gfs_jindex),
+			   sizeof(struct gfs_jindex));
+	if (count != sizeof(struct gfs_jindex)) {
+		log_crit(_("Error %d reading system journal index inode. "
+			   "Aborting\n"), count);
+		return -1;
+	}
+	gfs_jindex_in(&ji_1, buf);
+ 
+	jsize = (ji_1.ji_addr - ji_0.ji_addr) * sbd1->sb_bsize;
+out:
+	return reset_journal_seg_size(jsize, ji_0.ji_nsegment, sbd1->sb_bsize);
+}
 
 /*
  * reconstruct_journals - write fresh journals for GFS1 only
@@ -1335,6 +1435,12 @@ static int reconstruct_journals(struct gfs2_sbd *sdp)
 	struct gfs_jindex ji;
 	char buf[sizeof(struct gfs_jindex)];
 
+	/* Ensure that sb_seg_size is valid */
+	if (correct_journal_seg_size(sdp)) {
+		log_crit(_("Failed to set correct journal segment size. Cannot continue\n"));
+		return -1;
+	}
+
 	log_err("Clearing GFS journals (this may take a while)\n");
 	for (i = 0; i < sdp->md.journals; i++) {
 		count = gfs2_readi(sdp->md.jiinode, buf,


More information about the cluster-commits mailing list