gfs2-utils: master - fsck.gfs2: Check and repair per_node contents such as quota_changeX

Bob Peterson rpeterso at fedoraproject.org
Fri Sep 6 15:03:24 UTC 2013


Gitweb:        http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=fa32906a9869d3a78a450a724376e919bbc29dd5
Commit:        fa32906a9869d3a78a450a724376e919bbc29dd5
Parent:        97fbdb22e1ddfc313bf3266eb4a02769e2eb2190
Author:        Bob Peterson <rpeterso at redhat.com>
AuthorDate:    Tue Sep 3 11:21:00 2013 -0500
Committer:     Bob Peterson <rpeterso at redhat.com>
CommitterDate: Thu Sep 5 10:18:12 2013 -0500

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.
---
 gfs2/fsck/pass2.c         |  131 ++++++++++++++++++++++++++++++++++++++++++++-
 gfs2/libgfs2/libgfs2.h    |    4 ++
 gfs2/libgfs2/structures.c |    6 +-
 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 727cc18..26f7d48 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -1595,6 +1595,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,
@@ -1707,7 +1817,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,
+						   &quota_change_fxns,
+						   build_quota_change);
+		}
+	}
+	return error;
 }
 
 /**
diff --git a/gfs2/libgfs2/libgfs2.h b/gfs2/libgfs2/libgfs2.h
index 1548cf3..f864a08 100644
--- a/gfs2/libgfs2/libgfs2.h
+++ b/gfs2/libgfs2/libgfs2.h
@@ -770,6 +770,10 @@ extern int do_init_statfs(struct gfs2_sbd *sdp);
 extern int gfs2_check_meta(struct gfs2_buffer_head *bh, int type);
 extern unsigned lgfs2_bm_scan(struct rgrp_tree *rgd, unsigned idx,
 			      uint64_t *buf, uint8_t state);
+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);
 extern int read_sb(struct gfs2_sbd *sdp);
diff --git a/gfs2/libgfs2/structures.c b/gfs2/libgfs2/structures.c
index 2a8c6f7..e888f1e 100644
--- a/gfs2/libgfs2/structures.c
+++ b/gfs2/libgfs2/structures.c
@@ -180,7 +180,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];
@@ -204,7 +204,7 @@ static int build_inum_range(struct gfs2_inode *per_node, unsigned int j)
 	return 0;
 }
 
-static int 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];
@@ -228,7 +228,7 @@ static int build_statfs_change(struct gfs2_inode *per_node, unsigned int j)
 	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 eb97c40..f87734a 100644
--- a/gfs2/libgfs2/super.c
+++ b/gfs2/libgfs2/super.c
@@ -119,6 +119,7 @@ int read_sb(struct gfs2_sbd *sdp)
 	sdp->sb_addr = GFS2_SB_ADDR * GFS2_BASIC_BLOCK / sdp->bsize;
 	sdp->sd_blocks_per_bitmap = (sdp->sd_sb.sb_bsize - sizeof(struct gfs2_meta_header))
 	                             * GFS2_NBBY;
+	sdp->qcsize = GFS2_DEFAULT_QCSIZE;
 
 	return 0;
 }


More information about the cluster-commits mailing list