cluster: RHEL6 - fsck.gfs2: Check and repair per_node contents such as quota_changeX
Bob Peterson
rpeterso at fedoraproject.org
Mon Feb 10 18:34:02 UTC 2014
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=bcd9f9378cbc41afbfd82ce84febbaa91f29e7af
Commit: bcd9f9378cbc41afbfd82ce84febbaa91f29e7af
Parent: dc5096d7d567a4ff36888ba43695d7fb24511aa4
Author: Bob Peterson <rpeterso at redhat.com>
AuthorDate: Fri Feb 7 15:30:05 2014 -0600
Committer: Bob Peterson <rpeterso at redhat.com>
CommitterDate: Fri Feb 7 15:46:24 2014 -0600
fsck.gfs2: Check and repair per_node contents such as quota_changeX
This patch gives fsck.gfs2 the ability to check the system files that
are in the per_node directory: All the inum_rangeX, statfs_changeX
and quota_changeX files. If they're found to be corrupt, they are
deleted and rebuilt.
rhbz#1062742
---
gfs2/fsck/pass2.c | 131 ++++++++++++++++++++++++++++++++++++++++++++-
gfs2/libgfs2/libgfs2.h | 3 +
gfs2/libgfs2/structures.c | 7 ++-
gfs2/libgfs2/super.c | 1 +
4 files changed, 138 insertions(+), 4 deletions(-)
diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
index ba5a71d..2125233 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -1593,6 +1593,116 @@ struct metawalk_fxns pass2_fxns = {
.repair_leaf = pass2_repair_leaf,
};
+static int check_metalist_qc(struct gfs2_inode *ip, uint64_t block,
+ struct gfs2_buffer_head **bh, int h,
+ int *is_valid, int *was_duplicate, void *private)
+{
+ *was_duplicate = 0;
+ *is_valid = 1;
+ *bh = bread(ip->i_sbd, block);
+ return meta_is_good;
+}
+
+static int check_data_qc(struct gfs2_inode *ip, uint64_t metablock,
+ uint64_t block, void *private)
+{
+ struct gfs2_buffer_head *bh;
+
+ /* At this point, basic data block checks have already been done,
+ so we only need to make sure they're QC blocks. */
+ if (!valid_block(ip->i_sbd, block))
+ return -1;
+
+ bh = bread(ip->i_sbd, block);
+ if (gfs2_check_meta(bh, GFS2_METATYPE_QC) != 0) {
+ log_crit(_("Error: quota_change block at %lld (0x%llx) is "
+ "the wrong metadata type.\n"),
+ (unsigned long long)block, (unsigned long long)block);
+ brelse(bh);
+ return -1;
+ }
+ brelse(bh);
+ return 0;
+}
+
+struct metawalk_fxns quota_change_fxns = {
+ .check_metalist = check_metalist_qc,
+ .check_data = check_data_qc,
+};
+
+/* check_pernode_for - verify a file within the system per_node directory
+ * @x - index number X
+ * @per_node - pointer to the per_node inode
+ * @fn - system file name
+ * @filelen - the file length the system file needs to be
+ * @multiple - the file length must be a multiple (versus the exact value)
+ * @pass - a metawalk function for checking the data blocks (if any)
+ * @builder - a rebuild function for the file
+ *
+ * Returns: 0 if all went well, else error. */
+static int check_pernode_for(int x, struct gfs2_inode *pernode, const char *fn,
+ unsigned long long filelen, int multiple,
+ struct metawalk_fxns *pass,
+ int builder(struct gfs2_inode *per_node,
+ unsigned int j))
+{
+ struct gfs2_inode *ip;
+ int error, valid_size = 1;
+
+ log_debug(_("Checking system file %s\n"), fn);
+ error = gfs2_lookupi(pernode, fn, strlen(fn), &ip);
+ if (error) {
+ log_err(_("System file %s is missing.\n"), fn);
+ if (!query( _("Rebuild the system file? (y/n) ")))
+ return 0;
+ goto build_it;
+ }
+ if (!ip->i_di.di_size)
+ valid_size = 0;
+ else if (!multiple && ip->i_di.di_size != filelen)
+ valid_size = 0;
+ else if (multiple && (ip->i_di.di_size % filelen))
+ valid_size = 0;
+ if (!valid_size) {
+ log_err(_("System file %s has an invalid size. Is %llu, "
+ "should be %llu.\n"), fn, ip->i_di.di_size, filelen);
+ if (!query( _("Rebuild the system file? (y/n) ")))
+ goto out_good;
+ fsck_inode_put(&ip);
+ goto build_it;
+ }
+ if (pass) {
+ error = check_metatree(ip, pass);
+ if (!error)
+ goto out_good;
+ log_err(_("System file %s has bad contents.\n"), fn);
+ if (!query( _("Delete and rebuild the system file? (y/n) ")))
+ goto out_good;
+ check_metatree(ip, &pass2_fxns_delete);
+ fsck_inode_put(&ip);
+ gfs2_dirent_del(pernode, fn, strlen(fn));
+ goto build_it;
+ }
+out_good:
+ fsck_inode_put(&ip);
+ return 0;
+
+build_it:
+ if (builder(pernode, x)) {
+ log_err(_("Error building %s\n"), fn);
+ return -1;
+ }
+ error = gfs2_lookupi(pernode, fn, strlen(fn), &ip);
+ if (error) {
+ log_err(_("Error rebuilding %s.\n"), fn);
+ return -1;
+ }
+ fsck_blockmap_set(ip, ip->i_di.di_num.no_addr, fn, gfs2_inode_file);
+ reprocess_inode(ip, fn);
+ log_err(_("System file %s rebuilt.\n"), fn);
+ goto out_good;
+}
+
/* Check system directory inode */
/* Should work for all system directories: root, master, jindex, per_node */
static int check_system_dir(struct gfs2_inode *sysinode, const char *dirname,
@@ -1700,7 +1810,26 @@ static int check_system_dir(struct gfs2_inode *sysinode, const char *dirname,
sysinode->i_di.di_num.no_addr);
}
}
- return 0;
+ error = 0;
+ if (sysinode == sysinode->i_sbd->md.pinode) {
+ int j;
+ char fn[64];
+
+ /* Make sure all the per_node files are there, and valid */
+ for (j = 0; j < sysinode->i_sbd->md.journals; j++) {
+ sprintf(fn, "inum_range%d", j);
+ error += check_pernode_for(j, sysinode, fn, 16, 0,
+ NULL, build_inum_range);
+ sprintf(fn, "statfs_change%d", j);
+ error += check_pernode_for(j, sysinode, fn, 24, 0,
+ NULL, build_statfs_change);
+ sprintf(fn, "quota_change%d", j);
+ error += check_pernode_for(j, sysinode, fn, 1048576, 1,
+ "a_change_fxns,
+ build_quota_change);
+ }
+ }
+ return error;
}
/**
diff --git a/gfs2/libgfs2/libgfs2.h b/gfs2/libgfs2/libgfs2.h
index 375327f..9985c97 100644
--- a/gfs2/libgfs2/libgfs2.h
+++ b/gfs2/libgfs2/libgfs2.h
@@ -744,6 +744,9 @@ extern int gfs2_next_rg_metatype(struct gfs2_sbd *sdp, struct rgrp_tree *rgd,
uint64_t *block, uint32_t type, int first);
extern int gfs2_next_rg_freemeta(struct rgrp_tree *rgd, uint64_t *block,
int first);
+extern int build_inum_range(struct gfs2_inode *per_node, unsigned int j);
+extern int build_statfs_change(struct gfs2_inode *per_node, unsigned int j);
+extern int build_quota_change(struct gfs2_inode *per_node, unsigned int j);
/* super.c */
extern int check_sb(struct gfs2_sb *sb, int allow_gfs);
diff --git a/gfs2/libgfs2/structures.c b/gfs2/libgfs2/structures.c
index 9024353..f2d3bdb 100644
--- a/gfs2/libgfs2/structures.c
+++ b/gfs2/libgfs2/structures.c
@@ -167,7 +167,7 @@ int build_jindex(struct gfs2_sbd *sdp)
return 0;
}
-static int build_inum_range(struct gfs2_inode *per_node, unsigned int j)
+int build_inum_range(struct gfs2_inode *per_node, unsigned int j)
{
struct gfs2_sbd *sdp = per_node->i_sbd;
char name[256];
@@ -188,7 +188,7 @@ static int build_inum_range(struct gfs2_inode *per_node, unsigned int j)
return 0;
}
-static void build_statfs_change(struct gfs2_inode *per_node, unsigned int j)
+int build_statfs_change(struct gfs2_inode *per_node, unsigned int j)
{
struct gfs2_sbd *sdp = per_node->i_sbd;
char name[256];
@@ -206,9 +206,10 @@ static void build_statfs_change(struct gfs2_inode *per_node, unsigned int j)
}
inode_put(&ip);
+ return 0;
}
-static int build_quota_change(struct gfs2_inode *per_node, unsigned int j)
+int build_quota_change(struct gfs2_inode *per_node, unsigned int j)
{
struct gfs2_sbd *sdp = per_node->i_sbd;
struct gfs2_meta_header mh;
diff --git a/gfs2/libgfs2/super.c b/gfs2/libgfs2/super.c
index 8f49dff..fafbea6 100644
--- a/gfs2/libgfs2/super.c
+++ b/gfs2/libgfs2/super.c
@@ -126,6 +126,7 @@ int read_sb(struct gfs2_sbd *sdp, int allow_gfs)
}
sdp->fssize = lseek(sdp->device_fd, 0, SEEK_END) / sdp->sd_sb.sb_bsize;
sdp->sb_addr = GFS2_SB_ADDR * GFS2_BASIC_BLOCK / sdp->bsize;
+ sdp->qcsize = GFS2_DEFAULT_QCSIZE;
return 0;
}
More information about the cluster-commits
mailing list