cluster: STABLE3 - gfs_fsck -n always returns 0 even if error is found

Bob Peterson rpeterso at fedoraproject.org
Thu Oct 8 16:16:17 UTC 2009


Gitweb:        http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=43ee13f381d6b0c7c40c8716c43ceb77ab3e2caf
Commit:        43ee13f381d6b0c7c40c8716c43ceb77ab3e2caf
Parent:        1237d2f7e65c27f791ff0a8e47569bff36a5c667
Author:        Bob Peterson <rpeterso at redhat.com>
AuthorDate:    Thu Oct 8 11:17:36 2009 -0500
Committer:     Bob Peterson <rpeterso at redhat.com>
CommitterDate: Thu Oct 8 11:17:36 2009 -0500

gfs_fsck -n always returns 0 even if error is found

This patch makes gfs_fsck conform to the rules in the fsck(8)
man page regarding the fsck return code: (0=no errors, 1=file
system errors corrected, 4=errors left uncorrected, etc.)

rhbz#508978
---
 gfs/gfs_fsck/file.c       |    2 +-
 gfs/gfs_fsck/fs_bits.c    |    2 +-
 gfs/gfs_fsck/fs_bmap.c    |    2 +-
 gfs/gfs_fsck/fs_dir.c     |   14 +++++-----
 gfs/gfs_fsck/fs_inode.c   |    4 ++-
 gfs/gfs_fsck/fsck.h       |   14 +++++++++
 gfs/gfs_fsck/initialize.c |   25 ++++++-----------
 gfs/gfs_fsck/inode.c      |    2 +-
 gfs/gfs_fsck/main.c       |   67 ++++++++++++++++++++++++++-------------------
 gfs/gfs_fsck/metawalk.c   |   17 +++++++++++-
 gfs/gfs_fsck/pass1.c      |   38 +++++++++++++++++++-------
 gfs/gfs_fsck/pass1b.c     |   12 +++++---
 gfs/gfs_fsck/pass1c.c     |   17 +++++++----
 gfs/gfs_fsck/pass2.c      |   65 +++++++++++++++++++++++++++++++++-----------
 gfs/gfs_fsck/pass3.c      |   16 ++++++++---
 gfs/gfs_fsck/pass4.c      |   31 ++++++++++++++++-----
 gfs/gfs_fsck/pass5.c      |   17 ++++++++---
 gfs/gfs_fsck/rgrp.c       |    4 ++-
 gfs/gfs_fsck/super.c      |    8 +++++-
 gfs/gfs_fsck/util.c       |    8 +++---
 20 files changed, 250 insertions(+), 115 deletions(-)

diff --git a/gfs/gfs_fsck/file.c b/gfs/gfs_fsck/file.c
index 1e6fddf..a76d359 100644
--- a/gfs/gfs_fsck/file.c
+++ b/gfs/gfs_fsck/file.c
@@ -169,7 +169,7 @@ int writei(struct fsck_inode *ip, void *bufin, uint64_t offset, unsigned int siz
 				log_crit("fs_writei:  "
 					"Unable to map logical block to real block.\n");
 				log_crit("Uncircumventable error.\n");
-				exit(EXIT_FAILURE);
+				exit(FSCK_ERROR);
 			}
 		}
 
diff --git a/gfs/gfs_fsck/fs_bits.c b/gfs/gfs_fsck/fs_bits.c
index 1662de4..b0edfe1 100644
--- a/gfs/gfs_fsck/fs_bits.c
+++ b/gfs/gfs_fsck/fs_bits.c
@@ -24,7 +24,7 @@ static void fs_setbit(unsigned char *buffer, unsigned int buflen,
 
 	if(byte >= end){
 		log_err("fs_setbit:  byte >= end\n");
-		exit(1);
+		exit(FSCK_ERROR);
 	}
 	cur_state = (*byte >> bit) & GFS_BIT_MASK;
 
diff --git a/gfs/gfs_fsck/fs_bmap.c b/gfs/gfs_fsck/fs_bmap.c
index 97b2292..ad4f8ac 100644
--- a/gfs/gfs_fsck/fs_bmap.c
+++ b/gfs/gfs_fsck/fs_bmap.c
@@ -223,7 +223,7 @@ static int build_height(struct fsck_inode *ip, int height)
 			  dibh, sizeof(struct gfs_dinode));
 			*/
 			log_err("ATTENTION -- Not doing copy_tail...\n");
-			exit(1);
+			exit(FSCK_ERROR);
 			error = -1;
 			goto fail_drelse;
 			if((error = write_buf(sdp, bh, 0))){
diff --git a/gfs/gfs_fsck/fs_dir.c b/gfs/gfs_fsck/fs_dir.c
index 340becc..c3db529 100644
--- a/gfs/gfs_fsck/fs_dir.c
+++ b/gfs/gfs_fsck/fs_dir.c
@@ -333,7 +333,7 @@ static int leaf_search(osi_buf_t *bh, identifier_t *id,
 		} while (dirent_next(bh, &dent) == 0);
 	} else {
 		log_err("leaf_search:  Invalid type for identifier.\n");
-		exit(1);
+		exit(FSCK_ERROR);
 	}
 
 	return -ENOENT;
@@ -435,7 +435,7 @@ static int linked_leaf_search(struct fsck_inode *dip, identifier_t *id,
 		}
 	} else {
 		log_err("linked_leaf_search:  Invalid type for identifier.\n");
-		exit(1);
+		exit(FSCK_ERROR);
 	}
 	return error;
 }
@@ -463,7 +463,7 @@ static int dir_e_search(struct fsck_inode *dip, identifier_t *id, unsigned int *
 	if(id->type == ID_FILENAME){
 		if(id->inum){
 			log_err("dir_e_search:  Illegal parameter.  inum must be NULL.\n");
-			exit(1);
+			exit(FSCK_ERROR);
 		}
 		if(!(id->inum = (struct gfs_inum *)malloc(sizeof(struct gfs_inum)))) {
 			log_err("Unable to allocate inum structure\n");
@@ -478,7 +478,7 @@ static int dir_e_search(struct fsck_inode *dip, identifier_t *id, unsigned int *
 	} else {
 		if(id->filename){
 			log_err("dir_e_search:  Illegal parameter.  name must be NULL.\n");
-			exit(1);
+			exit(FSCK_ERROR);
 		}
 		if(!(id->filename = (osi_filename_t *)malloc(sizeof(osi_filename_t)))) {
 			log_err("Unable to allocate osi_filename structure\n");
@@ -546,7 +546,7 @@ static int dir_l_search(struct fsck_inode *dip, identifier_t *id, unsigned int *
 	if(id->type == ID_FILENAME){
 		if(id->inum){
 			log_err("dir_l_search:  Illegal parameter.  inum must be NULL.\n");
-			exit(1);
+			exit(FSCK_ERROR);
 		}
 		id->inum = (struct gfs_inum *)malloc(sizeof(struct gfs_inum));
 		// FIXME: don't dereference NULL on failed malloc
@@ -556,7 +556,7 @@ static int dir_l_search(struct fsck_inode *dip, identifier_t *id, unsigned int *
 	} else {
 		if(id->filename){
 			log_err("dir_l_search:  Illegal parameter.  name must be NULL.\n");
-			exit(1);
+			exit(FSCK_ERROR);
 		}
 		id->filename = (osi_filename_t *)malloc(sizeof(osi_filename_t));
 		// FIXME: don't dereference NULL on failed malloc
@@ -1341,7 +1341,7 @@ static int dir_e_add(struct fsck_inode *dip, osi_filename_t *filename,
 
 				if (fs_dirent_alloc(dip, nbh, filename->len, &dent)){
 					log_err("dir_e_add:  Uncircumventible error!\n");
-					exit(EXIT_FAILURE);
+					exit(FSCK_ERROR);
 				}
 
 				dip->i_di.di_blocks++;
diff --git a/gfs/gfs_fsck/fs_inode.c b/gfs/gfs_fsck/fs_inode.c
index 57f3cb9..61529a3 100644
--- a/gfs/gfs_fsck/fs_inode.c
+++ b/gfs/gfs_fsck/fs_inode.c
@@ -153,6 +153,7 @@ static int make_dinode(struct fsck_inode *dip, struct gfs_inum *inum,
 	if(check_meta(dibh, 0)){
 		log_err("make_dinode:  Buffer #%"PRIu64" has no meta header.\n",
 			BH_BLKNO(dibh));
+		errors_found++;
 		if(query(dip->i_sbd, "Add header? (y/n) ")){
 			struct gfs_meta_header mh;
 			memset(&mh, 0, sizeof(struct gfs_meta_header));
@@ -160,6 +161,7 @@ static int make_dinode(struct fsck_inode *dip, struct gfs_inum *inum,
 			mh.mh_type = GFS_METATYPE_NONE;
 			gfs_meta_header_out(&mh, BH_DATA(dibh));
 			log_warn("meta header added.\n");
+			errors_corrected++;
 		} else {
 			log_err("meta header not added.  Failing make_dinode.\n");
 			relse_buf(sdp, dibh);
@@ -200,7 +202,7 @@ static int make_dinode(struct fsck_inode *dip, struct gfs_inum *inum,
 	rgd = fs_blk2rgrpd(sdp, inum->no_addr);
 	if(!rgd){
 		log_err( "Unable to map block #%"PRIu64" to rgrp\n", inum->no_addr);
-		exit(1);
+		exit(FSCK_ERROR);
 	}
 
 	di.di_rgrp = rgd->rd_ri.ri_addr;
diff --git a/gfs/gfs_fsck/fsck.h b/gfs/gfs_fsck/fsck.h
index 1cb4291..d9d0e57 100644
--- a/gfs/gfs_fsck/fsck.h
+++ b/gfs/gfs_fsck/fsck.h
@@ -5,6 +5,19 @@
 #include "fsck_incore.h"
 #include "log.h"
 
+/*
+ * Exit codes used by fsck-type programs
+ * Copied from e2fsck's e2fsck.h
+ */
+#define FSCK_OK          0      /* No errors */
+#define FSCK_NONDESTRUCT 1      /* File system errors corrected */
+#define FSCK_REBOOT      2      /* System should be rebooted */
+#define FSCK_UNCORRECTED 4      /* File system errors left uncorrected */
+#define FSCK_ERROR       8      /* Operational error */
+#define FSCK_USAGE       16     /* Usage or syntax error */
+#define FSCK_CANCELED    32     /* Aborted with a signal or ^C */
+#define FSCK_LIBRARY     128    /* Shared library error */
+
 struct gfs_sb;
 struct fsck_sb;
 
@@ -16,6 +29,7 @@ struct options {
 
 extern uint64_t last_fs_block, last_reported_block;
 extern int skip_this_pass, fsck_abort, fsck_query;
+extern int errors_found, errors_corrected;
 
 int initialize(struct fsck_sb *sbp);
 void destroy(struct fsck_sb *sbp);
diff --git a/gfs/gfs_fsck/initialize.c b/gfs/gfs_fsck/initialize.c
index ffd1e8f..34233b5 100644
--- a/gfs/gfs_fsck/initialize.c
+++ b/gfs/gfs_fsck/initialize.c
@@ -348,35 +348,35 @@ static int fill_super_block(struct fsck_sb *sdp)
 }
 
 /**
- * init_sbp - initialize superblock pointer
+ * initialize - initialize superblock pointer
  *
  */
-static int init_sbp(struct fsck_sb *sbp)
+int initialize(struct fsck_sb *sbp)
 {
 	if(sbp->opts->no) {
 		if ((sbp->diskfd = open(sbp->opts->device, O_RDONLY)) < 0) {
 			log_crit("Unable to open device: %s\n", sbp->opts->device);
-			return -1;
+			return FSCK_USAGE;
 		}
 	} else {
 		/* read in sb from disk */
 		if ((sbp->diskfd = open(sbp->opts->device, O_RDWR)) < 0){
 			log_crit("Unable to open device: %s\n", sbp->opts->device);
-			return -1;
+			return FSCK_USAGE;
 		}
 	}
 
 	/* initialize lists and read in the sb */
 	if(read_super_block(sbp)) {
 		stack;
-		return -1;
+		return FSCK_ERROR;
 	}
 
 	/* Change lock protocol to be fsck_* instead of lock_* */
 	if(!sbp->opts->no) {
 		if(block_mounters(sbp, 1)) {
 			log_err("Unable to block other mounters\n");
-			return -1;
+			return FSCK_ERROR;
 		}
 	}
 
@@ -385,7 +385,7 @@ static int init_sbp(struct fsck_sb *sbp)
 		if(!sbp->opts->no)
 			block_mounters(sbp, 0);
 		stack;
-		return -1;
+		return FSCK_ERROR;
 	}
 
 	/* verify various things */
@@ -394,10 +394,10 @@ static int init_sbp(struct fsck_sb *sbp)
 		if(!sbp->opts->no)
 			block_mounters(sbp, 0);
 		stack;
-		return -1;
+		return FSCK_ERROR;
 	}
 
-	return 0;
+	return FSCK_OK;
 }
 
 static void destroy_sbp(struct fsck_sb *sbp)
@@ -414,13 +414,6 @@ static void destroy_sbp(struct fsck_sb *sbp)
 	close(sbp->diskfd);
 }
 
-int initialize(struct fsck_sb *sbp)
-{
-
-	return init_sbp(sbp);
-
-}
-
 void destroy(struct fsck_sb *sbp)
 {
 	destroy_sbp(sbp);
diff --git a/gfs/gfs_fsck/inode.c b/gfs/gfs_fsck/inode.c
index 7a88589..b900429 100644
--- a/gfs/gfs_fsck/inode.c
+++ b/gfs/gfs_fsck/inode.c
@@ -216,7 +216,7 @@ static int make_dinode(struct fsck_inode *dip, struct fsck_sb *sdp,
 	rgd = fs_blk2rgrpd(sdp, inum->no_addr);
 	if(!rgd){
 		log_crit("Unable to map block #%"PRIu64" to rgrp\n", inum->no_addr);
-		exit(1);
+		exit(FSCK_ERROR);
 	}
 
 	di.di_rgrp = rgd->rd_ri.ri_addr;
diff --git a/gfs/gfs_fsck/main.c b/gfs/gfs_fsck/main.c
index 58f8b91..78c8e4d 100644
--- a/gfs/gfs_fsck/main.c
+++ b/gfs/gfs_fsck/main.c
@@ -12,6 +12,7 @@
 
 uint64_t last_fs_block, last_reported_block = -1;
 int skip_this_pass = FALSE, fsck_abort = FALSE, fsck_query = FALSE;
+int errors_found = 0, errors_corrected = 0;
 const char *pass = "";
 
 #if 0
@@ -60,7 +61,7 @@ static int read_cmdline(int argc, char **argv, struct options *opts)
 
 		case 'h':
 			usage(argv[0]);
-			exit(0);
+			exit(FSCK_OK);
 			break;
 		case 'n':
 			opts->no = 1;
@@ -73,7 +74,7 @@ static int read_cmdline(int argc, char **argv, struct options *opts)
 			break;
 		case 'V':
 			version();
-			exit(0);
+			exit(FSCK_OK);
 			break;
 		case 'y':
 			opts->yes = 1;
@@ -81,12 +82,12 @@ static int read_cmdline(int argc, char **argv, struct options *opts)
 		case ':':
 		case '?':
 			fprintf(stderr, "Please use '-h' for usage.\n");
-			exit(1);
+			exit(FSCK_USAGE);
 			break;
 		default:
 			fprintf(stderr, "Bad programmer! You forgot to catch"
 				" the %c flag\n", c);
-			exit(1);
+			exit(FSCK_USAGE);
 			break;
 
 		}
@@ -95,11 +96,11 @@ static int read_cmdline(int argc, char **argv, struct options *opts)
 		opts->device = (argv[optind]);
 		if(!opts->device) {
 			fprintf(stderr, "Please use '-h' for usage.\n");
-			exit(1);
+			exit(FSCK_USAGE);
 		}
 	} else {
 		fprintf(stderr, "No device specified.  Use '-h' for usage.\n");
-		exit(1);
+		exit(FSCK_USAGE);
 	}
 	return 0;
 }
@@ -165,25 +166,25 @@ int main(int argc, char **argv)
 {
 	struct fsck_sb sb;
 	struct options opts = {0};
-
 	struct fsck_sb *sbp = &sb;
-	memset(sbp, 0, sizeof(*sbp));
+	int error = 0;
 
+	memset(sbp, 0, sizeof(*sbp));
 	sbp->opts = &opts;
 
-	if(read_cmdline(argc, argv, &opts))
-		return 1;
+	if((error = read_cmdline(argc, argv, &opts)))
+		exit(error);
 	setbuf(stdout, NULL);
 	log_notice("Initializing fsck\n");
-	if (initialize(sbp))
-		return 1;
+	if ((error = initialize(sbp)))
+		exit(error);
 
 	signal(SIGINT, interrupt);
 	log_notice("Starting pass1\n");
 	pass = "pass 1";
 	last_reported_block = 0;
-	if (pass1(sbp))
-		return 1;
+	if ((error = pass1(sbp)))
+		exit(error);
 	if (skip_this_pass || fsck_abort) {
 		skip_this_pass = FALSE;
 		log_notice("Pass1 interrupted   \n");
@@ -195,8 +196,8 @@ int main(int argc, char **argv)
 		last_reported_block = 0;
 		pass = "pass 1b";
 		log_notice("Starting pass1b\n");
-		if(pass1b(sbp))
-			return 1;
+		if((error = pass1b(sbp)))
+			exit(error);
 		if (skip_this_pass || fsck_abort) {
 			skip_this_pass = FALSE;
 			log_notice("Pass1b interrupted   \n");
@@ -208,8 +209,8 @@ int main(int argc, char **argv)
 		last_reported_block = 0;
 		pass = "pass 1c";
 		log_notice("Starting pass1c\n");
-		if(pass1c(sbp))
-			return 1;
+		if((error = pass1c(sbp)))
+			exit(error);
 		if (skip_this_pass || fsck_abort) {
 			skip_this_pass = FALSE;
 			log_notice("Pass1c interrupted   \n");
@@ -221,8 +222,8 @@ int main(int argc, char **argv)
 		last_reported_block = 0;
 		pass = "pass 2";
 		log_notice("Starting pass2\n");
-		if (pass2(sbp, &opts))
-			return 1;
+		if ((error = pass2(sbp, &opts)))
+			exit(error);
 		if (skip_this_pass || fsck_abort) {
 			skip_this_pass = FALSE;
 			log_notice("Pass2 interrupted   \n");
@@ -234,8 +235,8 @@ int main(int argc, char **argv)
 		last_reported_block = 0;
 		pass = "pass 3";
 		log_notice("Starting pass3\n");
-		if (pass3(sbp, &opts))
-			return 1;
+		if ((error = pass3(sbp, &opts)))
+			exit(error);
 		if (skip_this_pass || fsck_abort) {
 			skip_this_pass = FALSE;
 			log_notice("Pass3 interrupted   \n");
@@ -247,8 +248,8 @@ int main(int argc, char **argv)
 		last_reported_block = 0;
 		pass = "pass 4";
 		log_notice("Starting pass4\n");
-		if (pass4(sbp, &opts))
-			return 1;
+		if ((error = pass4(sbp, &opts)))
+			exit(error);
 		if (skip_this_pass || fsck_abort) {
 			skip_this_pass = FALSE;
 			log_notice("Pass4 interrupted   \n");
@@ -260,8 +261,8 @@ int main(int argc, char **argv)
 		last_reported_block = 0;
 		pass = "pass 5";
 		log_notice("Starting pass5\n");
-		if (pass5(sbp, &opts))
-			return 1;
+		if ((error = pass5(sbp, &opts)))
+			exit(error);
 		if (skip_this_pass || fsck_abort) {
 			skip_this_pass = FALSE;
 			log_notice("Pass5 interrupted   \n");
@@ -269,10 +270,20 @@ int main(int argc, char **argv)
 		else
 			log_notice("Pass5 complete      \n");
 		log_notice("Writing changes to disk\n");
+	} else {
+		error = FSCK_CANCELED;
 	}
-	destroy(sbp);
 
-	return 0;
+	destroy(sbp);
+	if (!error) {
+		if (!errors_found)
+			error = FSCK_OK;
+		else if (errors_found == errors_corrected)
+			error = FSCK_NONDESTRUCT;
+		else
+			error = FSCK_UNCORRECTED;
+	}
+	exit(error);
 }
 
 
diff --git a/gfs/gfs_fsck/metawalk.c b/gfs/gfs_fsck/metawalk.c
index 135d200..9ae00db 100644
--- a/gfs/gfs_fsck/metawalk.c
+++ b/gfs/gfs_fsck/metawalk.c
@@ -56,7 +56,7 @@ static int check_entries(struct fsck_inode *ip, osi_buf_t *bh, int type,
 
 	while(1) {
 		if (skip_this_pass || fsck_abort)
-			return 0;
+			return FSCK_OK;
 		memset(&de, 0, sizeof(struct gfs_dirent));
 		gfs_dirent_in(&de, (char *)dent);
 		filename = (char *)dent + sizeof(struct gfs_dirent);
@@ -68,6 +68,7 @@ static int check_entries(struct fsck_inode *ip, osi_buf_t *bh, int type,
 				PRIu64 ", entry %d of directory %"
 				PRIu64 " is corrupt.\n", BH_BLKNO(bh),
 				(*count) + 1, ip->i_di.di_num.no_addr);
+			errors_found++;
 			if (query(ip->i_sbd, "Attempt to repair it? (y/n) ")) {
 				if (dirent_repair(ip, bh, &de, dent, type,
 						  first)) {
@@ -79,10 +80,12 @@ static int check_entries(struct fsck_inode *ip, osi_buf_t *bh, int type,
 					log_err("Unable to repair corrupt "
 						"directory entry; the entry "
 						"was removed instead.\n");
+					errors_corrected++;
 					return 0;
 				} else {
 					log_err("Corrupt directory entry "
 						"repaired.\n");
+					errors_corrected++;
 					*update = 1;
 					/* keep looping through dentries */
 				}
@@ -102,12 +105,14 @@ static int check_entries(struct fsck_inode *ip, osi_buf_t *bh, int type,
 					"zero in leaf %"PRIu64" of directory "
 					"%"PRIu64"!\n", BH_BLKNO(bh),
 					ip->i_di.di_num.no_addr);
+				errors_found++;
 				if (query(ip->i_sbd,
 					  "Attempt to remove it? (y/n) ")) {
 					dirblk_truncate(ip, prev, bh);
 					*update = 1;
 					log_err("The corrupt directory entry "
 						"was removed.\n");
+					errors_corrected++;
 				} else {
 					log_err("Corrupt directory entry "
 						"ignored, stopped after "
@@ -157,8 +162,10 @@ static void warn_and_patch(struct fsck_inode *ip, uint64_t *leaf_no,
 			PRIu64 " %s.\n", ip->i_di.di_num.no_addr, *leaf_no,
 			msg);
 	}
+	errors_found++;
 	if (*leaf_no == *bad_leaf ||
 	    query(ip->i_sbd, "Attempt to patch around it? (y/n) ")) {
+		errors_corrected++;
 		if (check_range(ip->i_sbd, old_leaf) == 0)
 			put_leaf_nr(ip, lindex, old_leaf);
 		else
@@ -238,9 +245,11 @@ static int check_leaf_blks(struct fsck_inode *ip, int *update,
 				"\tFound: %u,  Expected: %u\n",
 				ip->i_num.no_addr, old_leaf, ref_count,
 				exp_count);
+			errors_found++;
 			if (query(ip->i_sbd, "Attempt to fix it? (y/n) ")) {
 				int factor = 0, divisor = ref_count;
 
+				errors_corrected++;
 				get_and_read_buf(sbp, old_leaf, &lbh, 0);
 				while (divisor > 1) {
 					factor++;
@@ -343,7 +352,9 @@ static int check_leaf_blks(struct fsck_inode *ip, int *update,
 					gfs_leaf_in(&leaf, BH_DATA(lbh));
 
 					log_err("Leaf(%"PRIu64") entry count in directory %"PRIu64" doesn't match number of entries found - is %u, found %u\n", leaf_no, ip->i_num.no_addr, leaf.lf_entries, count);
+					errors_found++;
 					if(query(sbp, "Update leaf entry count? (y/n) ")) {
+						errors_corrected++;
 						leaf.lf_entries = count;
 						gfs_leaf_out(&leaf, BH_DATA(lbh));
 						write_buf(sbp, lbh, 0);
@@ -419,9 +430,11 @@ static int check_eattr_entries(struct fsck_inode *ip, osi_buf_t *bh,
 							      bh, ea_hdr,
 							      ea_hdr_prev,
 							      pass->private)) {
+					errors_found++;
 					if (query(ip->i_sbd,
 						  "Repair the bad Extended "
 						  "Attribute? (y/n) ")) {
+						errors_corrected++;
 						ea_hdr->ea_num_ptrs = i;
 						ea_hdr->ea_data_len =
 							cpu_to_be32(tot_ealen);
@@ -535,9 +548,11 @@ static int check_indirect_eattr(struct fsck_inode *ip, uint64_t indirect,
 			if (error) {
 				leaf_pointer_errors++;
 				if (!update_indir_block) {
+					errors_found++;
 					if (query(sdp, "Fix the indirect "
 						  "block too? (y/n) ")) {
 						update_indir_block = 1;
+						errors_corrected++;
 						*ea_leaf_ptr = 0;
 					}
 				} else
diff --git a/gfs/gfs_fsck/pass1.c b/gfs/gfs_fsck/pass1.c
index fb09db5..386041b 100644
--- a/gfs/gfs_fsck/pass1.c
+++ b/gfs/gfs_fsck/pass1.c
@@ -248,8 +248,10 @@ static int check_data(struct fsck_inode *ip, uint64_t block, void *private)
 			log_err("Block #%llu seems to be journaled data, but "
 				"is marked as %s.\n",
 				(unsigned long long)block, allocdesc[btype]);
+			errors_found++;
 			if(query(sdp, "Okay to mark it as 'journaled data'? "
 				 "(y/n)")) {
+				errors_corrected++;
 				fs_set_bitmap(sdp, block, GFS_BLKST_USEDMETA);
 				log_err("The block was reassigned as "
 					"journaled data.\n");
@@ -260,8 +262,10 @@ static int check_data(struct fsck_inode *ip, uint64_t block, void *private)
 			log_err("Block #%llu seems to be data, but "
 				"is marked as %s.\n",
 				(unsigned long long)block, allocdesc[btype]);
+			errors_found++;
 			if(query(sdp, "Okay to mark it as 'data'? "
 				 "(y/n)")) {
+				errors_corrected++;
 				fs_set_bitmap(sdp, block, GFS_BLKST_USED);
 				log_err("The block was reassigned as "
 					"journaled data.\n");
@@ -311,6 +315,7 @@ static int ask_remove_inode_eattr(struct fsck_inode *ip,
 {
 	log_err("Inode %lld has unrecoverable Extended Attribute "
 		"errors.\n", (unsigned long long)ip->i_di.di_num.no_addr);
+	errors_found++;
 	if (query(ip->i_sbd, "Clear all Extended Attributes from the "
 		  "inode? (y/n) ")) {
 		struct block_query q;
@@ -319,9 +324,10 @@ static int ask_remove_inode_eattr(struct fsck_inode *ip,
 			stack;
 			return -1;
 		}
-		if (!remove_inode_eattr(ip, bc, q.dup_block))
+		if (!remove_inode_eattr(ip, bc, q.dup_block)) {
+			errors_corrected++;
 			log_err("Extended attributes were removed.\n");
-		else
+		} else
 			log_err("Unable to remove inode eattr pointer; "
 				"the error remains.\n");
 	} else {
@@ -347,6 +353,7 @@ static int clear_eas(struct fsck_inode *ip, struct block_count *bc,
 	log_err("Inode #%" PRIu64 " (0x%" PRIx64 "): %s",
 		ip->i_di.di_num.no_addr, ip->i_di.di_num.no_addr, emsg);
 	log_err(" at block #%" PRIu64 ".\n", block);
+	errors_found++;
 	if (query(sdp, "Clear the bad Extended Attribute? (y/n) ")) {
 		if (block == ip->i_di.di_eattr) {
 			remove_inode_eattr(ip, bc, duplicate);
@@ -357,6 +364,7 @@ static int clear_eas(struct fsck_inode *ip, struct block_count *bc,
 			log_err("The bad Extended Attribute was "
 				"removed.\n");
 		}
+		errors_corrected++;
 		return 1;
 	} else {
 		log_err("The bad Extended Attribute was not fixed.\n");
@@ -447,10 +455,12 @@ static int finish_eattr_indir(struct fsck_inode *ip, int leaf_pointers,
 	log_err("Inode %lld has recoverable indirect "
 		"Extended Attribute errors.\n",
 		(unsigned long long)ip->i_di.di_num.no_addr);
+	errors_found++;
 	if (query(ip->i_sbd, "Okay to fix the block count for the inode? "
 		  "(y/n) ")) {
 		ip->i_di.di_blocks = 1 + bc->indir_count +
 			bc->data_count + bc->ea_count;
+		errors_corrected++;
 		log_err("Block count fixed.\n");
 		return 1;
 	}
@@ -734,12 +744,14 @@ static int handle_di(struct fsck_sb *sdp, osi_buf_t *bh, uint64_t block, int mfr
 			goto success;
 		} else {
 			log_err("Found unused inode marked in-use\n");
+			errors_found++;
 			if(query(sdp, "Clear unused inode at block %"
 				 PRIu64"? (y/n) ", block)) {
 				if(block_set(sdp->bl, block, meta_inval)) {
 					stack;
 					goto fail;
 				}
+				errors_corrected++;
 				goto success;
 			} else {
 				log_err("Unused inode still marked in-use\n");
@@ -761,6 +773,7 @@ static int handle_di(struct fsck_sb *sdp, osi_buf_t *bh, uint64_t block, int mfr
 			"Found %"PRIu64", "
 			"Expected %"PRIu64"\n",
 			ip->i_di.di_num.no_addr, block);
+		errors_found++;
 		if(query(sdp, "Fix address in inode at block %"
 			 PRIu64"? (y/n) ", block)) {
 			ip->i_di.di_num.no_addr =
@@ -770,6 +783,7 @@ static int handle_di(struct fsck_sb *sdp, osi_buf_t *bh, uint64_t block, int mfr
 				log_crit("Bad dinode address can not be reset.\n");
 				goto fail;
 			} else {
+				errors_corrected++;
 				log_err("Bad dinode address reset.\n");
 			}
 		} else {
@@ -925,6 +939,7 @@ static int handle_di(struct fsck_sb *sdp, osi_buf_t *bh, uint64_t block, int mfr
 			 "%lld + data: %lld + ea: %lld\n",
 			 ip->i_di.di_blocks, bc.indir_count, bc.data_count,
 			 bc.ea_count);
+		errors_found++;
 		if(query(sdp, "Fix ondisk block count? (y/n) ")) {
 			ip->i_di.di_blocks = 1 + bc.indir_count +
 				bc.data_count + bc.ea_count;
@@ -938,7 +953,8 @@ static int handle_di(struct fsck_sb *sdp, osi_buf_t *bh, uint64_t block, int mfr
 					stack;
 					log_crit("Bad block count remains\n");
 				} else {
-					log_warn("Bad block count fixed\n");
+					errors_corrected++;
+					log_err("Bad block count fixed\n");
 				}
 				relse_buf(sdp, di_bh);
 			}
@@ -962,12 +978,14 @@ static int handle_di(struct fsck_sb *sdp, osi_buf_t *bh, uint64_t block, int mfr
 static int scan_meta(struct fsck_sb *sdp, osi_buf_t *bh, uint64_t block, int mfree)
 {
 	if (check_meta(bh, 0)) {
+		errors_found++;
 		log_err("Found invalid metadata block at %"PRIu64"\n", block);
 		if(block_set(sdp->bl, block, meta_inval)) {
 			stack;
 			return -1;
 		}
 		if(query(sdp, "Okay to free the invalid block? (y/n)")) {
+			errors_corrected++;
 			fs_set_bitmap(sdp, block, GFS_BLKST_FREE);
 			log_err("The invalid block was freed.\n");
 		} else {
@@ -1031,7 +1049,7 @@ int pass1(struct fsck_sb *sbp)
 		    j++) {
 			if(block_set(sbp->bl, j, journal_blk)) {
 				stack;
-				return -1;
+				return FSCK_ERROR;
 			}
 		}
 	}
@@ -1054,7 +1072,7 @@ int pass1(struct fsck_sb *sbp)
 		rgd = osi_list_entry(tmp, struct fsck_rgrp, rd_list);
 		if(fs_rgrp_read(rgd, FALSE)){
 			stack;
-			return -1;
+			return FSCK_ERROR;
 		}
 		log_debug("RG at %"PRIu64" is %u long\n", rgd->rd_ri.ri_addr,
 				  rgd->rd_ri.ri_length);
@@ -1062,7 +1080,7 @@ int pass1(struct fsck_sb *sbp)
 			if(block_set(sbp->bl, rgd->rd_ri.ri_addr + i,
 				     meta_other)){
 				stack;
-				return -1;
+				return FSCK_ERROR;
 			}
 		}
 
@@ -1076,7 +1094,7 @@ int pass1(struct fsck_sb *sbp)
 				break;
 			warm_fuzzy_stuff(block);
 			if (fsck_abort) /* if asked to abort */
-				return 0;
+				return FSCK_OK;
 			if (skip_this_pass) {
 				printf("Skipping pass 1 is not a good idea.\n");
 				skip_this_pass = FALSE;
@@ -1087,14 +1105,14 @@ int pass1(struct fsck_sb *sbp)
 				log_crit("Unable to retrieve block %"PRIu64
 					 "\n", block);
 				fs_rgrp_relse(rgd);
-				return -1;
+				return FSCK_ERROR;
 			}
 
 			if(scan_meta(sbp, bh, block, mfree)) {
 				stack;
 				relse_buf(sbp, bh);
 				fs_rgrp_relse(rgd);
-				return -1;
+				return FSCK_ERROR;
 			}
 			relse_buf(sbp, bh);
 			first = 0;
@@ -1102,5 +1120,5 @@ int pass1(struct fsck_sb *sbp)
 		fs_rgrp_relse(rgd);
 	}
 
-	return 0;
+	return FSCK_OK;
 }
diff --git a/gfs/gfs_fsck/pass1b.c b/gfs/gfs_fsck/pass1b.c
index 301f7d0..7a89d32 100644
--- a/gfs/gfs_fsck/pass1b.c
+++ b/gfs/gfs_fsck/pass1b.c
@@ -422,7 +422,9 @@ static int handle_dup_blk(struct fsck_sb *sbp, struct blocks *b)
 				 "data block %"PRIu64", but "
 				 "the block is really metadata.\n",
 				 id->name, id->block_no, b->block_no);
+			errors_found++;
 			if (query(sbp, "Clear the inode? (y/n) ")) {
+				errors_corrected++;
 				log_warn("Clearing inode %lld...\n",
 					 id->block_no);
 				load_inode(sbp, id->block_no, &ip);
@@ -452,12 +454,14 @@ static int handle_dup_blk(struct fsck_sb *sbp, struct blocks *b)
 	}
 	osi_list_foreach(tmp, &b->ref_inode_list) {
 		id = osi_list_entry(tmp, struct inode_with_dups, list);
+		errors_found++;
 		if (!query(sbp, "Okay to clear inode %lld? (y/n) ",
 			   id->block_no)) {
 			log_warn("The inode %lld was not cleared...\n",
 				 id->block_no);
 			continue;
 		}
+		errors_corrected++;
 		log_warn("Clearing inode %lld...\n", id->block_no);
 		load_inode(sbp, id->block_no, &ip);
 		dh.b = b;
@@ -493,7 +497,7 @@ int pass1b(struct fsck_sb *sbp)
 	struct block_query q;
 	osi_list_t *tmp = NULL, *x;
 	struct metawalk_fxns find_dirents = {0};
-	int rc = 0;
+	int rc = FSCK_OK;
 
 	find_dirents.check_dentry = &find_dentry;
 
@@ -505,7 +509,7 @@ int pass1b(struct fsck_sb *sbp)
 	/* If there were no dups in the bitmap, we don't need to do anymore */
 	if(osi_list_empty(&sbp->dup_list)) {
 		log_info("No duplicate blocks found\n");
-		return 0;
+		return FSCK_OK;
 	}
 
 	/* Rescan the fs looking for pointers to blocks that are in
@@ -519,7 +523,7 @@ int pass1b(struct fsck_sb *sbp)
 		log_debug("Scanning block %"PRIu64" for inodes\n", i);
 		if(block_check(sbp->bl, i, &q)) {
 			stack;
-			rc = -1;
+			rc = FSCK_ERROR;
 			goto out;
 		}
 		if((q.block_type == inode_dir) ||
@@ -533,7 +537,7 @@ int pass1b(struct fsck_sb *sbp)
 				b = osi_list_entry(tmp, struct blocks, list);
 				if(find_block_ref(sbp, i, b)) {
 					stack;
-					rc = -1;
+					rc = FSCK_ERROR;
 					goto out;
 				}
 			}
diff --git a/gfs/gfs_fsck/pass1c.c b/gfs/gfs_fsck/pass1c.c
index 925047d..2e68173 100644
--- a/gfs/gfs_fsck/pass1c.c
+++ b/gfs/gfs_fsck/pass1c.c
@@ -35,6 +35,7 @@ static int ask_remove_eattr_entry(struct fsck_sb *sdp, osi_buf_t *leaf_bh,
 				  struct gfs_ea_header *prev,
 				  int fix_curr, int fix_curr_len)
 {
+	errors_found++;
 	if (query(sdp, "Remove the bad Extended Attribute? (y/n) ")) {
 		if (fix_curr)
 			curr->ea_flags |= GFS_EAFLAG_LAST;
@@ -48,6 +49,7 @@ static int ask_remove_eattr_entry(struct fsck_sb *sdp, osi_buf_t *leaf_bh,
 			stack;
 			return -1;
 		}
+		errors_corrected++;
 	} else {
 		log_err("Bad Extended Attribute not removed.\n");
 	}
@@ -56,13 +58,16 @@ static int ask_remove_eattr_entry(struct fsck_sb *sdp, osi_buf_t *leaf_bh,
 
 static int ask_remove_eattr(struct fsck_inode *ip)
 {
+	errors_found++;
 	if (query(ip->i_sbd, "Remove the bad Extended Attribute? (y/n) ")) {
 		ip->i_di.di_eattr = 0;
 		if (fs_copyout_dinode(ip))
 			log_err("Bad Extended Attribute could not be "
 				"removed.\n");
-		else
+		else {
+			errors_corrected++;
 			log_err("Bad Extended Attribute removed.\n");
+		}
 	} else
 		log_err("Bad Extended Attribute not removed.\n");
 	return 1;
@@ -251,15 +256,15 @@ int pass1c(struct fsck_sb *sbp)
 	while (!find_next_block_type(sbp->bl, eattr_block, &block_no)) {
 
 		if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
-			return 0;
+			return FSCK_OK;
 		log_info("EA in inode %"PRIu64"\n", block_no);
 		if(get_and_read_buf(sbp, block_no, &bh, 0)) {
 			stack;
-			return -1;
+			return FSCK_ERROR;
 		}
 		if(copyin_inode(sbp, bh, &ip)) {
 			stack;
-			return -1;
+			return FSCK_ERROR;
 		}
 
 		block_unmark(sbp->bl, block_no, eattr_block);
@@ -268,7 +273,7 @@ int pass1c(struct fsck_sb *sbp)
 		error = check_inode_eattr(ip, &pass1c_fxns);
 		if(error < 0) {
 			stack;
-			return -1;
+			return FSCK_ERROR;
 		}
 
 		if(update) {
@@ -281,5 +286,5 @@ int pass1c(struct fsck_sb *sbp)
 
 		block_no++;
 	}
-	return 0;
+	return FSCK_OK;
 }
diff --git a/gfs/gfs_fsck/pass2.c b/gfs/gfs_fsck/pass2.c
index 9c4a298..31c5ad7 100644
--- a/gfs/gfs_fsck/pass2.c
+++ b/gfs/gfs_fsck/pass2.c
@@ -223,11 +223,14 @@ static int check_dentry(struct fsck_inode *ip, struct gfs_dirent *dent,
 	if(check_range(ip->i_sbd, entryblock)) {
 		log_err("Block # referenced by directory entry %s is out of range\n",
 			tmp_name);
+		errors_found++;
 		if(query(ip->i_sbd, "Clear directory entry tp out of range block? (y/n) ")) {
 			log_err("Clearing %s\n", tmp_name);
 			if(dirent_del(ip, bh, prev_de, dent))
 				log_err("Error encountered while removing bad "
 					"directory entry.  Skipping.\n");
+			else
+				errors_corrected++;
 			*update = 1;
 			return 1;
 		} else {
@@ -249,8 +252,10 @@ static int check_dentry(struct fsck_inode *ip, struct gfs_dirent *dent,
 		log_err("Found a bad directory entry: %s at block %lld.\n",
 			filename, de->de_inum.no_addr);
 
+		errors_found++;
 		if(query(sbp, "Delete the inode containing bad blocks? "
 			 "(y/n)")) {
+			errors_corrected++;
 			if (!load_inode(sbp, de->de_inum.no_addr, &entry_ip)) {
 				check_inode_eattr(entry_ip,
 						  &pass2_fxns_delete);
@@ -281,6 +286,7 @@ static int check_dentry(struct fsck_inode *ip, struct gfs_dirent *dent,
 			q.block_type, q.block_type == meta_inval ?
 			"previously marked invalid" : "is not an inode");
 
+		errors_found++;
 		if(query(sbp, "Clear directory entry to non-inode block? "
 			 "(y/n) ")) {
 			osi_buf_t *bhi;
@@ -290,6 +296,7 @@ static int check_dentry(struct fsck_inode *ip, struct gfs_dirent *dent,
 					"directory entry.  Skipping.\n");
 				return -1;
 			}
+			errors_corrected++;
 			*update = 1;
 			log_warn("Directory entry '%s' cleared\n", tmp_name);
 
@@ -331,6 +338,7 @@ static int check_dentry(struct fsck_inode *ip, struct gfs_dirent *dent,
 		log_warn("Type in dir entry (%s, %"PRIu64") conflicts with "
 			 "type in dinode. (Dir entry is stale.)\n",
 			 tmp_name, de->de_inum.no_addr);
+		errors_found++;
 		if(query(sbp, "Clear stale directory entry? (y/n) ")) {
 			load_inode(sbp, de->de_inum.no_addr, &entry_ip);
 			check_inode_eattr(entry_ip, &clear_eattrs);
@@ -339,8 +347,11 @@ static int check_dentry(struct fsck_inode *ip, struct gfs_dirent *dent,
 			if(dirent_del(ip, bh, prev_de, dent))
 				log_err("Error encountered while removing bad "
 					"directory entry.  Skipping.\n");
-			*update = 1;
-			log_err("Stale directory entry deleted\n");
+			else {
+				errors_corrected++;
+				*update = 1;
+				log_err("Stale directory entry deleted\n");
+			}
 			return 1;
 		} else {
 			log_err("Stale directory entry remains\n");
@@ -355,8 +366,10 @@ static int check_dentry(struct fsck_inode *ip, struct gfs_dirent *dent,
 
 		if(ds->dotdir) {
 			log_err("already found '.' entry\n");
+			errors_found++;
 			if(query(sbp, "Clear duplicate '.' entry? (y/n) ")) {
 
+				errors_corrected++;
 				load_inode(sbp, de->de_inum.no_addr, &entry_ip);
 				check_inode_eattr(entry_ip, &clear_eattrs);
 				free_inode(&entry_ip);
@@ -387,7 +400,9 @@ static int check_dentry(struct fsck_inode *ip, struct gfs_dirent *dent,
 				PRIu64".\n",
 				de->de_inum.no_addr,
 				ip->i_num.no_addr);
+			errors_found++;
 			if(query(sbp, "remove '.' reference? (y/n) ")) {
+				errors_corrected++;
 				load_inode(sbp, de->de_inum.no_addr, &entry_ip);
 				check_inode_eattr(entry_ip, &clear_eattrs);
 				free_inode(&entry_ip);
@@ -418,8 +433,10 @@ static int check_dentry(struct fsck_inode *ip, struct gfs_dirent *dent,
 		log_debug("Found .. dentry\n");
 		if(ds->dotdotdir) {
 			log_err("already found '..' entry\n");
+			errors_found++;
 			if(query(sbp, "Clear duplicate '..' entry? (y/n) ")) {
 
+				errors_corrected++;
 				load_inode(sbp, de->de_inum.no_addr, &entry_ip);
 				check_inode_eattr(entry_ip, &clear_eattrs);
 				free_inode(&entry_ip);
@@ -442,7 +459,9 @@ static int check_dentry(struct fsck_inode *ip, struct gfs_dirent *dent,
 		if(q.block_type != inode_dir) {
 			log_err("Found '..' entry pointing to"
 				" something that's not a directory");
+			errors_found++;
 			if(query(sbp, "Clear bad '..' directory entry? (y/n) ")) {
+				errors_corrected++;
 				load_inode(sbp, de->de_inum.no_addr, &entry_ip);
 				check_inode_eattr(entry_ip, &clear_eattrs);
 				free_inode(&entry_ip);
@@ -494,7 +513,9 @@ static int check_dentry(struct fsck_inode *ip, struct gfs_dirent *dent,
 	if(error > 0) {
 		log_err("Hard link to block %"PRIu64" detected.\n", filename, entryblock);
 
+		errors_found++;
 		if(query(sbp, "Clear hard link to directory? (y/n) ")) {
+			errors_corrected++;
 			*update = 1;
 
 			dirent_del(ip, bh, prev_de, dent);
@@ -624,11 +645,13 @@ static int check_root_dir(struct fsck_sb *sbp)
 	if(ds.q.block_type != inode_dir) {
 		log_err("Block %"PRIu64" marked as root inode in"
 			" superblock not a directory\n", rootblock);
+		errors_found++;
 		if(query(sbp, "Create new root inode? (y/n) ")) {
 			if(build_rooti(sbp)) {
 				stack;
 				return -1;
 			}
+			errors_corrected++;
 		} else {
 			log_err("Cannot continue without valid root inode\n");
 			return -1;
@@ -681,6 +704,7 @@ static int check_root_dir(struct fsck_sb *sbp)
 
 	if(!ds.dotdir) {
 		log_err("No '.' entry found\n");
+		errors_found++;
 		if (query(sbp, "Is it okay to add '.' entry? (y/n) ")) {
 			sprintf(tmp_name, ".");
 			filename.len = strlen(tmp_name); /* no trailing NULL */
@@ -704,6 +728,7 @@ static int check_root_dir(struct fsck_sb *sbp)
 					"directory.\n");
 				return -1;
 			}
+			errors_corrected++;
 			increment_link(ip->i_sbd, ip->i_num.no_addr);
 			ds.entry_count++;
 			free(filename.name);
@@ -728,10 +753,12 @@ static int check_root_dir(struct fsck_sb *sbp)
 	if(ip->i_di.di_entries != ds.entry_count) {
 		log_err("Entries is %d - should be %d for %"PRIu64"\n",
 			ip->i_di.di_entries, ds.entry_count, ip->i_di.di_num.no_addr);
+		errors_found++;
 		if(query(sbp, "Fix entries for %"PRIu64"? (y/n) ",
 			 ip->i_di.di_num.no_addr)) {
 			ip->i_di.di_entries = ds.entry_count;
-			log_warn("Entries updated\n");
+			log_err("Entries updated\n");
+			errors_corrected++;
 			update = 1;
 		} else {
 			log_err("Entries for %"PRIu64" left out of sync\n",
@@ -774,7 +801,7 @@ int pass2(struct fsck_sb *sbp, struct options *opts)
 
 	if(check_root_dir(sbp)) {
 		stack;
-		return -1;
+		return FSCK_ERROR;
 	}
 
 	log_info("Checking directory inodes.\n");
@@ -783,7 +810,7 @@ int pass2(struct fsck_sb *sbp, struct options *opts)
 		need_update = 0;
 		warm_fuzzy_stuff(i);
 		if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
-			return 0;
+			return FSCK_OK;
 
 		/* Skip the root inode - it's checked above */
 		if(i == sbp->sb.sb_root_di.no_addr)
@@ -792,7 +819,7 @@ int pass2(struct fsck_sb *sbp, struct options *opts)
 		if(block_check(sbp->bl, i, &q)) {
 			log_err("Can't get block %"PRIu64 " from block list\n",
 				i);
-			return -1;
+			return FSCK_ERROR;
 		}
 
 		if(q.block_type != inode_dir)
@@ -810,24 +837,25 @@ int pass2(struct fsck_sb *sbp, struct options *opts)
 			if(check_metatree(ip, &pass2_fxns)) {
 				stack;
 				free_inode(&ip);
-				return -1;
+				return FSCK_ERROR;
 			}
 			free_inode(&ip);
 		}
 		error = check_dir(sbp, i, &pass2_fxns);
 		if(error < 0) {
 			stack;
-			return -1;
+			return FSCK_ERROR;
 		}
 		if (error > 0) {
 			struct dir_info *di = NULL;
 			error = find_di(sbp, i, &di);
 			if(error < 0) {
 				stack;
-				return -1;
+				return FSCK_ERROR;
 			}
 			if(error == 0) {
 				/* FIXME: factor */
+				errors_found++;
 				if(query(sbp, "Remove directory entry for bad"
 					 " inode %"PRIu64" in %"PRIu64
 					 "? (y/n)", i, di->treewalk_parent)) {
@@ -836,13 +864,14 @@ int pass2(struct fsck_sb *sbp, struct options *opts)
 								       i);
 					if(error < 0) {
 						stack;
-						return -1;
+						return FSCK_ERROR;
 					}
 					if(error > 0) {
 						log_warn("Unable to find dentry for %"
 							 PRIu64" in %"PRIu64"\n",
 							 i, di->treewalk_parent);
 					}
+					errors_corrected++;
 					log_warn("Directory entry removed\n");
 				} else {
 					log_err("Directory entry to invalid inode remains\n");
@@ -856,18 +885,19 @@ int pass2(struct fsck_sb *sbp, struct options *opts)
 			log_err("Unable to retrieve block #%"PRIu64
 				" for directory\n",
 				i);
-			return -1;
+			return FSCK_ERROR;
 		}
 
 		if(copyin_inode(sbp, bh, &ip)) {
 			stack;
 			relse_buf(sbp, bh);
-			return -1;
+			return FSCK_ERROR;
 		}
 
 		if(!ds.dotdir) {
 			log_err("No '.' entry found for directory inode at "
 				"block %" PRIu64 "\n", i);
+			errors_found++;
 			if (query(sbp,
 				  "Is it okay to add '.' entry? (y/n) ")) {
 				sprintf(tmp_name, ".");
@@ -877,13 +907,13 @@ int pass2(struct fsck_sb *sbp, struct options *opts)
 							    filename.len))) {
 					log_err("Unable to allocate name\n");
 					stack;
-					return -1;
+					return FSCK_ERROR;
 				}
 				if(!memset(filename.name, 0, sizeof(char) *
 					   filename.len)) {
 					log_err("Unable to zero name\n");
 					stack;
-					return -1;
+					return FSCK_ERROR;
 				}
 				memcpy(filename.name, tmp_name, filename.len);
 
@@ -891,8 +921,9 @@ int pass2(struct fsck_sb *sbp, struct options *opts)
 					      ip->i_di.di_type)){
 					log_err("Failed to link \".\" entry "
 						"to directory.\n");
-					return -1;
+					return FSCK_ERROR;
 				}
+				errors_corrected++;
 				increment_link(ip->i_sbd, ip->i_num.no_addr);
 				ds.entry_count++;
 				free(filename.name);
@@ -908,7 +939,9 @@ int pass2(struct fsck_sb *sbp, struct options *opts)
 				"block %" PRIu64 "\n",
 				ip->i_di.di_entries, ds.entry_count,
 				ip->i_di.di_num.no_addr);
+			errors_found++;
 			if (query(sbp, "Fix the entry count? (y/n) ")) {
+				errors_corrected++;
 				ip->i_di.di_entries = ds.entry_count;
 				need_update = 1;
 			} else {
@@ -922,7 +955,7 @@ int pass2(struct fsck_sb *sbp, struct options *opts)
 			relse_buf(sbp, bh);
 		}
 	}
-	return 0;
+	return FSCK_OK;
 }
 
 
diff --git a/gfs/gfs_fsck/pass3.c b/gfs/gfs_fsck/pass3.c
index 4f6781b..08ee24f 100644
--- a/gfs/gfs_fsck/pass3.c
+++ b/gfs/gfs_fsck/pass3.c
@@ -114,6 +114,7 @@ static struct dir_info *mark_and_return_parent(struct fsck_sb *sbp,
 					 "is bad - reattaching to l+f");
 
 				/* FIXME: add a dinode for this entry instead? */
+				errors_found++;
 				if(query(sbp, "Remove directory entry for bad"
 					 " inode %"PRIu64" in %"PRIu64
 					 "? (y/n)", di->dinode,
@@ -130,6 +131,7 @@ static struct dir_info *mark_and_return_parent(struct fsck_sb *sbp,
 							 PRIu64" in %"PRIu64"\n",
 							 di->dinode, di->treewalk_parent);
 					}
+					errors_corrected++;
 					log_warn("Directory entry removed\n");
 				} else {
 					log_err("Directory entry to invalid inode remains\n");
@@ -199,20 +201,22 @@ int pass3(struct fsck_sb *sbp, struct options *opts)
 			 * failure and put the parent inode in a
 			 * param */
 			if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
-				return 0;
+				return FSCK_OK;
 			tdi = mark_and_return_parent(sbp, di);
 
 			/* FIXME: Factor this ? */
 			if(!tdi) {
 				if(block_check(sbp->bl, di->dinode, &q)) {
 					stack;
-					return -1;
+					return FSCK_ERROR;
 				}
 				if(q.bad_block) {
 					log_err("Found unlinked directory containing"
 						"bad block\n");
+					errors_found++;
 					if(query(sbp, "Clear unlinked directory with bad blocks? (y/n) ")) {
 						block_set(sbp->bl, di->dinode, block_free);
+						errors_corrected++;
 						break;
 					} else {
 						log_err("Unlinked directory with bad blocks remains\n");
@@ -237,7 +241,9 @@ int pass3(struct fsck_sb *sbp, struct options *opts)
 				 * with eattrs */
 				if(!ip->i_di.di_size && !ip->i_di.di_eattr){
 					log_err("Unlinked directory has zero size.\n");
+					errors_found++;
 					if(query(sbp, "Remove zero-size unlinked directory? (y/n) ")) {
+						errors_corrected++;
 						block_set(sbp->bl, di->dinode, block_free);
 						free_inode(&ip);
 						break;
@@ -245,11 +251,13 @@ int pass3(struct fsck_sb *sbp, struct options *opts)
 						log_err("Zero-size unlinked directory remains\n");
 					}
 				}
+				errors_found++;
 				if(query(sbp, "Add unlinked directory to l+f? (y/n) ")) {
+					errors_corrected++;
 					if(add_inode_to_lf(ip)) {
 						stack;
 						free_inode(&ip);
-						return -1;
+						return FSCK_ERROR;
 					}
 					log_warn("Directory relinked to l+f\n");
 				} else {
@@ -269,5 +277,5 @@ int pass3(struct fsck_sb *sbp, struct options *opts)
 	if(sbp->lf_dip)
 		log_debug("At end of pass3, l+f entries is %u\n",
 			  sbp->lf_dip->i_di.di_entries);
-	return 0;
+	return FSCK_OK;
 }
diff --git a/gfs/gfs_fsck/pass4.c b/gfs/gfs_fsck/pass4.c
index 4455fc6..edfd57d 100644
--- a/gfs/gfs_fsck/pass4.c
+++ b/gfs/gfs_fsck/pass4.c
@@ -49,7 +49,7 @@ static int scan_inode_list(struct fsck_sb *sbp, osi_list_t *list) {
 			return 0;
 		if(!(ii = osi_list_entry(tmp, struct inode_info, list))) {
 			log_crit("osi_list_foreach broken in scan_info_list!!\n");
-			exit(1);
+			exit(FSCK_ERROR);
 		}
 		/* Don't check reference counts on the special gfs files */
 		if((ii->inode == sbp->sb.sb_rindex_di.no_addr) ||
@@ -70,8 +70,10 @@ static int scan_inode_list(struct fsck_sb *sbp, osi_list_t *list) {
 				log_err("Unlinked inode contains"
 					"bad blocks\n",
 					ii->inode);
+				errors_found++;
 				if(query(sbp, "Delete unlinked inode with bad "
 					 "blocks? (y/n) ")) {
+					errors_corrected++;
 					load_inode(sbp, ii->inode, &ip);
 					check_inode_eattr(ip,
 							  &pass4_fxns_delete);
@@ -79,6 +81,7 @@ static int scan_inode_list(struct fsck_sb *sbp, osi_list_t *list) {
 					free_inode(&ip);
 					block_set(sbp->bl, ii->inode,
 						  block_free);
+					log_err("Unlinked inode with bad blocks cleared\n");
 					continue;
 				} else
 					log_err("Unlinked inode with bad blocks not cleared\n");
@@ -92,8 +95,10 @@ static int scan_inode_list(struct fsck_sb *sbp, osi_list_t *list) {
 			   q.block_type != inode_sock) {
 				log_err("Unlinked block marked as an inode is "
 					"not an inode (%d)\n", q.block_type);
+				errors_found++;
 				if(query(sbp, "Delete unlinked inode"
 					 "? (y/n) ")) {
+					errors_corrected++;
 					if (!load_inode(sbp, ii->inode, &ip)) {
 						check_inode_eattr(ip,
 							   &pass4_fxns_delete);
@@ -118,22 +123,32 @@ static int scan_inode_list(struct fsck_sb *sbp, osi_list_t *list) {
 			 * them. */
 			if(!ip->i_di.di_size && !ip->i_di.di_eattr){
 				log_err("Unlinked inode has zero size\n");
+				errors_found++;
 				if(query(sbp, "Clear zero-size unlinked inode? (y/n) ")) {
+					errors_corrected++;
 					block_set(sbp->bl, ii->inode, block_free);
 					free_inode(&ip);
+					log_err("Unlinked inode with zero size cleared\n");
 					continue;
-				}
+				} else
+					log_err("Unlinked inode with zero size"
+						" not cleared\n");
 
 			}
+			errors_found++;
 			if(query(sbp, "Add unlinked inode to l+f? (y/n)")) {
 				if(add_inode_to_lf(ip)) {
 					stack;
 					free_inode(&ip);
+					log_err("Unable to unlinked inode to "
+						"l+f\n");
 					return -1;
-				}
-				else {
+				} else {
 					fix_inode_count(sbp, ii, ip);
 					lf_addition = 1;
+					errors_corrected++;
+					log_err("Unlinked inode added to "
+						"l+f\n");
 				}
 			} else
 				log_err("Unlinked inode left unlinked\n");
@@ -145,8 +160,10 @@ static int scan_inode_list(struct fsck_sb *sbp, osi_list_t *list) {
 				ii->inode, ii->link_count, ii->counted_links);
 			/* Read in the inode, adjust the link count,
 			 * and write it back out */
+			errors_found++;
 			if(query(sbp, "Update link count for inode %"
 				 PRIu64"? (y/n) ", ii->inode)) {
+				errors_corrected++;
 				load_inode(sbp, ii->inode, &ip);
 				fix_inode_count(sbp, ii, ip);
 				free_inode(&ip);
@@ -193,16 +210,16 @@ int pass4(struct fsck_sb *sbp, struct options *opts)
 	log_info("Checking inode reference counts.\n");
 	for (i = 0; i < FSCK_HASH_SIZE; i++) {
 		if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
-			return 0;
+			return FSCK_OK;
 		list = &sbp->inode_hash[i];
 		if(scan_inode_list(sbp, list)) {
 			stack;
-			return -1;
+			return FSCK_ERROR;
 		}
 	}
 
 	if(sbp->lf_dip)
 		log_debug("At end of pass4, l+f entries is %u\n",
 			  sbp->lf_dip->i_di.di_entries);
-	return 0;
+	return FSCK_OK;
 }
diff --git a/gfs/gfs_fsck/pass5.c b/gfs/gfs_fsck/pass5.c
index ddddf5a..d8d0768 100644
--- a/gfs/gfs_fsck/pass5.c
+++ b/gfs/gfs_fsck/pass5.c
@@ -202,6 +202,7 @@ static int check_block_status(struct fsck_sb *sbp, char *buffer, unsigned int bu
 				  rg_status, block_status, q.block_type);
 			if((rg_status == GFS_BLKST_FREEMETA) &&
 			   (block_status == GFS_BLKST_FREE)) {
+				errors_found++;
 				log_info("Converting free metadata block at %"
 					 PRIu64" to a free data block\n", block);
 				if(!sbp->opts->no) {
@@ -209,7 +210,8 @@ static int check_block_status(struct fsck_sb *sbp, char *buffer, unsigned int bu
 						log_warn("Failed to convert free metadata block to free data block at %PRIu64.\n", block);
 					}
 					else {
-						log_info("Succeeded.\n");
+						log_err("Succeeded.\n");
+						errors_corrected++;
 					}
 				}
 			}
@@ -229,12 +231,15 @@ static int check_block_status(struct fsck_sb *sbp, char *buffer, unsigned int bu
 					q.block_type,
 					block_type_string(&q));
 
+				errors_found++;
 				if(query(sbp, "Fix bitmap for block %"
 					 PRIu64"? (y/n) ", block)) {
 					if(fs_set_bitmap(sbp, block, block_status))
 						log_err("Failed.\n");
-					else
+					else {
 						log_err("Succeeded.\n");
+						errors_corrected++;
+					}
 				} else
 					log_err("Bitmap at block %"PRIu64
 						" left inconsistent\n", block);
@@ -331,8 +336,10 @@ static int update_rgrp(struct fsck_rgrp *rgp, uint32_t *count, int rgcount)
 			rgp->rd_rg.rg_freemeta = count[4];
 		}
 
+		errors_found++;
 		if(query(rgp->rd_sbd,
 			 "Update resource group counts? (y/n) ")) {
+			errors_corrected++;
 			log_warn("Resource group counts updated\n");
 			/* write out the rgrp */
 			gfs_rgrp_out(&rgp->rd_rg, BH_DATA(rgp->rd_bh[0]));
@@ -361,14 +368,14 @@ int pass5(struct fsck_sb *sbp, struct options *opts)
 	/* Reconcile RG bitmaps with fsck bitmap */
 	for(tmp = sbp->rglist.next; tmp != &sbp->rglist; tmp = tmp->next){
 		if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
-			return 0;
+			return FSCK_OK;
 		log_info("Updating Resource Group %"PRIu64"\n", rg_count);
 		memset(count, 0, sizeof(*count) * 5);
 		rgp = osi_list_entry(tmp, struct fsck_rgrp, rd_list);
 
 		if(fs_rgrp_read(rgp, FALSE)){
 			stack;
-			return -1;
+			return FSCK_ERROR;
 		}
 		/* Compare the bitmaps and report the differences */
 		update_rgrp(rgp, count, rg_count);
@@ -379,5 +386,5 @@ int pass5(struct fsck_sb *sbp, struct options *opts)
 	 * anything to do here... */
 
 
-	return 0;
+	return FSCK_OK;
 }
diff --git a/gfs/gfs_fsck/rgrp.c b/gfs/gfs_fsck/rgrp.c
index 89a7c39..68d405e 100644
--- a/gfs/gfs_fsck/rgrp.c
+++ b/gfs/gfs_fsck/rgrp.c
@@ -162,7 +162,7 @@ int fs_rgrp_read(struct fsck_rgrp *rgd, int repair_if_corrupted)
 	for (x = 0; x < length; x++){
 		if(rgd->rd_bh[x]){
 			log_err("Programmer error!  Bitmaps are already present in rgrp.\n");
-			exit(1);
+			exit(FSCK_ERROR);
 		}
 		error = get_and_read_buf(sdp, rgd->rd_ri.ri_addr + x,
 								 &(rgd->rd_bh[x]), 0);
@@ -177,6 +177,7 @@ int fs_rgrp_read(struct fsck_rgrp *rgd, int repair_if_corrupted)
 					BH_BLKNO(rgd->rd_bh[x]), BH_BLKNO(rgd->rd_bh[x]),
 					(int)x+1, (int)length);
 			if (repair_if_corrupted) {
+				errors_found++;
 				if (query(sdp, "Fix the RG? (y/n)")) {
 					log_err("Attempting to repair the RG.\n");
 					if (x) {
@@ -203,6 +204,7 @@ int fs_rgrp_read(struct fsck_rgrp *rgd, int repair_if_corrupted)
 							     BH_DATA(rgd->rd_bh[x]));
 					}
 					write_buf(sdp, rgd->rd_bh[x], BW_WAIT);
+					errors_corrected++;
 				}
 			}
 			else {
diff --git a/gfs/gfs_fsck/super.c b/gfs/gfs_fsck/super.c
index 6d13839..0a13ce2 100644
--- a/gfs/gfs_fsck/super.c
+++ b/gfs/gfs_fsck/super.c
@@ -1293,6 +1293,7 @@ int ri_update(struct fsck_sb *sdp)
 						   ri_bitbytes, PRIx32);
 				/* If we modified the index, write it back to disk. */
 				if (rgindex_modified) {
+					errors_found++;
 					if(query(sdp, "Fix the index? (y/n)")) {
 						gfs_rindex_out(&rgd->rd_ri, (char *)&buf);
 						error = writei(sdp->riinode, (char *)&buf,
@@ -1302,6 +1303,8 @@ int ri_update(struct fsck_sb *sdp)
 							log_err("Unable to fix resource group index %u.\n",
 									rg + 1);
 							goto fail;
+						} else {
+							errors_corrected++;
 						}
 					}
 					else
@@ -1314,8 +1317,11 @@ int ri_update(struct fsck_sb *sdp)
 				if (rgd->rd_ri.ri_data == (uint32_t)-4) {
 					if (!fix_grow_problems) {
 						log_err("A problem with the rindex file caused by gfs_grow was detected.\n");
-						if(query(sdp, "Fix the rindex problem? (y/n)"))
+						errors_found++;
+						if(query(sdp, "Fix the rindex problem? (y/n)")) {
+							errors_corrected++;
 							fix_grow_problems = 1;
+						}
 					}
 					/* Keep a counter in case we hit it more than once. */
 					grow_problems++;
diff --git a/gfs/gfs_fsck/util.c b/gfs/gfs_fsck/util.c
index a7130e0..81aeb69 100644
--- a/gfs/gfs_fsck/util.c
+++ b/gfs/gfs_fsck/util.c
@@ -141,7 +141,7 @@ int next_rg_meta(struct fsck_rgrp *rgd, uint64 *block, int first)
 
   if(!first && (*block < rgd->rd_ri.ri_data1)){
     log_err("next_rg_meta:  Start block is outside rgrp bounds.\n");
-    exit(1);
+    exit(FSCK_ERROR);
   }
 
   for(i=0; i < length; i++){
@@ -194,7 +194,7 @@ int next_rg_meta_free(struct fsck_rgrp *rgd, uint64 *block, int first, int *mfre
 
   if(!first && (*block < rgd->rd_ri.ri_data1)){
     log_err("next_rg_meta:  Start block is outside rgrp bounds.\n");
-    exit(1);
+    exit(FSCK_ERROR);
   }
 
   for(i=0; i < length; i++){
@@ -258,13 +258,13 @@ int next_rg_metatype(struct fsck_rgrp *rgd, uint64 *block, uint32 type, int firs
     if(get_and_read_buf(sdp, *block, &bh, 0)){
       log_err("next_rg_metatype:  Unable to read meta block "
 	      "#%"PRIu64" from disk\n", *block);
-      exit(1);
+      exit(FSCK_ERROR);
     }
 
     if(check_meta(bh,0)){
       log_err("next_rg_metatype:  next_rg_meta returned block #%"PRIu64",\n"
 	      "                   which is not a valid meta block.\n", *block);
-      exit(1);
+      exit(FSCK_ERROR);
     }
 
     first = 0;


More information about the cluster-commits mailing list