[Cluster-devel] [PATCH 2/2] gfs2-utils: check and fix bad dinode pointers in gfs1 sb
Abhi Das
adas at redhat.com
Wed Mar 12 04:14:33 UTC 2014
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 <adas at redhat.com>
---
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
More information about the Cluster-devel
mailing list