From mboxrd@z Thu Jan 1 00:00:00 1970 From: Abhi Das Date: Tue, 11 Mar 2014 23:14:33 -0500 Subject: [Cluster-devel] [PATCH 2/2] gfs2-utils: check and fix bad dinode pointers in gfs1 sb In-Reply-To: <1394597673-27787-1-git-send-email-adas@redhat.com> References: <1394597673-27787-1-git-send-email-adas@redhat.com> Message-ID: <1394597673-27787-3-git-send-email-adas@redhat.com> List-Id: To: cluster-devel.redhat.com MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit 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. Resolves: rhbz#1053668 Signed-off-by: Abhi Das --- gfs2/convert/gfs2_convert.c | 29 ++++++++++++++++++ gfs2/fsck/initialize.c | 72 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+) diff --git a/gfs2/convert/gfs2_convert.c b/gfs2/convert/gfs2_convert.c index 7a7d4df..9f7fa17 100644 --- a/gfs2/convert/gfs2_convert.c +++ b/gfs2/convert/gfs2_convert.c @@ -1502,6 +1502,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 */ @@ -2152,6 +2170,17 @@ 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 0f33aa6..24e5de2 100644 --- a/gfs2/fsck/initialize.c +++ b/gfs2/fsck/initialize.c @@ -727,6 +727,13 @@ static int init_system_inodes(struct gfs2_sbd *sdp) } 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_addr = sbd1->sb_license_di.no_formal_ino + = sbd1->sb_jindex_di.no_addr + 3; + log_err(_("Reset statfs inode block address to: %llu\n"), + sbd1->sb_license_di.no_addr); + } sdp->md.statfs = lgfs2_inode_read(sdp, sbd1->sb_license_di.no_addr); if (sdp->md.statfs == NULL) { log_crit(_("Error reading statfs inode: %s\n"), strerror(errno)); @@ -773,6 +780,14 @@ static int init_system_inodes(struct gfs2_sbd *sdp) } 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_addr = sbd1->sb_quota_di.no_formal_ino + = sbd1->sb_jindex_di.no_addr + 2; + log_err(_("Reset quota inode block address to: %llu\n"), + sbd1->sb_quota_di.no_addr); + } + sdp->md.qinode = lgfs2_inode_read(sdp, sbd1->sb_quota_di.no_addr); if (sdp->md.qinode == NULL) { log_crit(_("Error reading quota inode: %s\n"), strerror(errno)); @@ -1354,6 +1369,57 @@ 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)) + return -1; + gfs_jindex_in(&ji_0, buf); + + if (sdp->md.journals == 1 && sbd1->sb_seg_size == 0) { + if (!query(_("The gfs2 journal segment size is 0 and a correct value\n" + "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; + } + + count = gfs2_readi(sdp->md.jiinode, buf, sizeof(struct gfs_jindex), + sizeof(struct gfs_jindex)); + if (count != sizeof(struct gfs_jindex)) + 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 @@ -1367,6 +1433,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, -- 1.8.1.4