[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[Cluster-devel] cluster/gfs2 libgfs2/gfs2_log.c libgfs2/libgfs ...



CVSROOT:	/cvs/cluster
Module name:	cluster
Changes by:	rpeterso sourceware org	2007-01-23 19:23:07

Modified files:
	gfs2/libgfs2   : gfs2_log.c libgfs2.h 
	gfs2/fsck      : fsck.h initialize.c main.c pass1.c pass1b.c 
	                 pass1c.c pass2.c pass3.c pass4.c pass5.c util.c 

Log message:
	Resolves: bz 223506: gfs2_fsck: fatal: invalid metadata block
	This is a crosswrite from gfs1.
	1. Fix a memory leak in pass1b.
	2. Improve performance of pass1b by combining loops through fs.
	3. Give an error message and abort if file system > 16TB and node
	architecture is 32-bits.
	4. Give users an "Abort" "Continue" and "Skip" if they interrupt
	with ctrl-c.  Also, report progress for that pass on interrupt.
	5. Added more "percent complete" messages for other passes.
	
	See bz comments for more details.

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/libgfs2/gfs2_log.c.diff?cvsroot=cluster&r1=1.2&r2=1.3
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/libgfs2/libgfs2.h.diff?cvsroot=cluster&r1=1.8&r2=1.9
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/fsck/fsck.h.diff?cvsroot=cluster&r1=1.3&r2=1.4
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/fsck/initialize.c.diff?cvsroot=cluster&r1=1.6&r2=1.7
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/fsck/main.c.diff?cvsroot=cluster&r1=1.4&r2=1.5
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/fsck/pass1.c.diff?cvsroot=cluster&r1=1.4&r2=1.5
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/fsck/pass1b.c.diff?cvsroot=cluster&r1=1.3&r2=1.4
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/fsck/pass1c.c.diff?cvsroot=cluster&r1=1.4&r2=1.5
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/fsck/pass2.c.diff?cvsroot=cluster&r1=1.4&r2=1.5
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/fsck/pass3.c.diff?cvsroot=cluster&r1=1.4&r2=1.5
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/fsck/pass4.c.diff?cvsroot=cluster&r1=1.4&r2=1.5
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/fsck/pass5.c.diff?cvsroot=cluster&r1=1.3&r2=1.4
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/fsck/util.c.diff?cvsroot=cluster&r1=1.4&r2=1.5

--- cluster/gfs2/libgfs2/gfs2_log.c	2006/06/15 18:45:22	1.2
+++ cluster/gfs2/libgfs2/gfs2_log.c	2007/01/23 19:23:06	1.3
@@ -103,6 +103,7 @@
 	if(opts->no)
 		return 0;
 
+	opts->query = TRUE;
 	/* Watch stdin (fd 0) to see when it has input. */
 	FD_ZERO(&rfds);
 	FD_SET(STDIN_FILENO, &rfds);
@@ -150,5 +151,6 @@
 		read(STDIN_FILENO, &response, sizeof(char));
 	}
 
+	opts->query = FALSE;
 	return ret;
 }
--- cluster/gfs2/libgfs2/libgfs2.h	2006/11/30 15:25:49	1.8
+++ cluster/gfs2/libgfs2/libgfs2.h	2007/01/23 19:23:06	1.9
@@ -437,6 +437,7 @@
 	char *device;
 	int yes:1;
 	int no:1;
+	int query:1;
 };
 
 #define MSG_DEBUG       7
--- cluster/gfs2/fsck/fsck.h	2006/06/12 20:41:43	1.3
+++ cluster/gfs2/fsck/fsck.h	2007/01/23 19:23:07	1.4
@@ -58,7 +58,8 @@
 extern osi_list_t dir_hash[FSCK_HASH_SIZE];
 extern osi_list_t inode_hash[FSCK_HASH_SIZE];
 extern struct gfs2_block_list *bl;
-extern uint64_t last_fs_block;
+extern uint64_t last_fs_block, last_reported_block;
+extern int skip_this_pass, fsck_abort, fsck_query;
 extern uint64_t last_data_block;
 extern uint64_t first_data_block;
 extern osi_list_t dup_list;
--- cluster/gfs2/fsck/initialize.c	2006/09/20 16:43:25	1.6
+++ cluster/gfs2/fsck/initialize.c	2007/01/23 19:23:07	1.7
@@ -95,6 +95,7 @@
 {
 	uint32_t i;
 
+	log_info("Freeing buffers.\n");
 	while(!osi_list_empty(&sdp->rglist)){
 		struct rgrp_list *rgd;
 
@@ -157,6 +158,12 @@
 	}
 
 	last_fs_block = rmax;
+	if (last_fs_block > 0xffffffff && sizeof(unsigned long) <= 4) {
+		log_crit("This file system is too big for this computer to handle.\n");
+		log_crit("Last fs block = 0x%llx, but sizeof(unsigned long) is %d bytes.\n",
+				 last_fs_block, sizeof(unsigned long));
+		goto fail;
+	}
 
 	last_data_block = rmax;
 	first_data_block = rmin;
--- cluster/gfs2/fsck/main.c	2006/06/15 18:48:45	1.4
+++ cluster/gfs2/fsck/main.c	2007/01/23 19:23:07	1.5
@@ -17,6 +17,8 @@
 #include <libgen.h>
 #include <string.h>
 #include <stdarg.h>
+#include <ctype.h>
+#include <signal.h>
 
 #include "copyright.cf"
 #include "libgfs2.h"
@@ -28,7 +30,9 @@
 osi_list_t dir_hash[FSCK_HASH_SIZE];
 osi_list_t inode_hash[FSCK_HASH_SIZE];
 struct gfs2_block_list *bl;
-uint64_t last_fs_block;
+uint64_t last_fs_block, last_reported_block = -1;
+int skip_this_pass = FALSE, fsck_abort = FALSE;
+const char *pass = "";
 uint64_t last_data_block;
 uint64_t first_data_block;
 osi_list_t dup_list;
@@ -133,6 +137,61 @@
 	return 0;
 }
 
+void interrupt(int sig)
+{
+	fd_set rfds;
+	struct timeval tv;
+	char response;
+	int err;
+
+	if (opts.query) /* if we're asking them a question */
+		return;     /* ignore the interrupt signal */
+	FD_ZERO(&rfds);
+	FD_SET(STDIN_FILENO, &rfds);
+
+	tv.tv_sec = 0;
+	tv.tv_usec = 0;
+	/* Make sure there isn't extraneous input before asking the
+	 * user the question */
+	while((err = select(STDIN_FILENO + 1, &rfds, NULL, NULL, &tv))) {
+		if(err < 0) {
+			log_debug("Error in select() on stdin\n");
+			break;
+		}
+		read(STDIN_FILENO, &response, sizeof(char));
+	}
+	while (TRUE) {
+		printf("\ngfs_fsck interrupted in %s:  ", pass);
+		if (!last_reported_block || last_reported_block == last_fs_block)
+			printf("progress unknown.\n");
+		else
+			printf("processing block %" PRIu64 " out of %" PRIu64 "\n",
+				   last_reported_block, last_fs_block);
+		printf("Do you want to abort gfs_fsck, skip the rest of %s or continue (a/s/c)?", pass);
+
+		/* Make sure query is printed out */
+		fflush(stdout);
+		read(STDIN_FILENO, &response, sizeof(char));
+
+		if(tolower(response) == 's') {
+			skip_this_pass = TRUE;
+			return;
+		}
+		else if (tolower(response) == 'a') {
+			fsck_abort = TRUE;
+			return;
+		}
+		else if (tolower(response) == 'c')
+			return;
+        else {
+			while(response != '\n')
+				read(STDIN_FILENO, &response, sizeof(char));
+			printf("Bad response, please type 'c', 'a' or 's'.\n");
+			continue;
+        }
+	}
+}
+
 int main(int argc, char **argv)
 {
 	struct gfs2_sbd sb;
@@ -148,41 +207,97 @@
 	if (initialize(sbp))
 		return 1;
 
+	signal(SIGINT, interrupt);
 	log_notice("Starting pass1\n");
+	pass = "pass 1";
+	last_reported_block = 0;
 	if (pass1(sbp))
 		return 1;
-	log_notice("Pass1 complete      \n");
-
-	log_notice("Starting pass1b\n");
-	if(pass1b(sbp))
-		return 1;
-	log_notice("Pass1b complete\n");
-
-	log_notice("Starting pass1c\n");
-	if(pass1c(sbp))
-		return 1;
-	log_notice("Pass1c complete\n");
-
-	log_notice("Starting pass2\n");
-	if (pass2(sbp))
-		return 1;
-	log_notice("Pass2 complete      \n");
-
-	log_notice("Starting pass3\n");
-	if (pass3(sbp))
-		return 1;
-	log_notice("Pass3 complete      \n");
-
-	log_notice("Starting pass4\n");
-	if (pass4(sbp))
-		return 1;
-	log_notice("Pass4 complete      \n");
-
-	log_notice("Starting pass5\n");
-	if (pass5(sbp))
-		return 1;
-	log_notice("Pass5 complete      \n");
+	if (skip_this_pass || fsck_abort) {
+		skip_this_pass = FALSE;
+		log_notice("Pass1 interrupted   \n");
+	}
+	else
+		log_notice("Pass1 complete      \n");
 
+	if (!fsck_abort) {
+		last_reported_block = 0;
+		pass = "pass 1b";
+		log_notice("Starting pass1b\n");
+		if(pass1b(sbp))
+			return 1;
+		if (skip_this_pass || fsck_abort) {
+			skip_this_pass = FALSE;
+			log_notice("Pass1b interrupted   \n");
+		}
+		else
+			log_notice("Pass1b complete\n");
+	}
+	if (!fsck_abort) {
+		last_reported_block = 0;
+		pass = "pass 1c";
+		log_notice("Starting pass1c\n");
+		if(pass1c(sbp))
+			return 1;
+		if (skip_this_pass || fsck_abort) {
+			skip_this_pass = FALSE;
+			log_notice("Pass1c interrupted   \n");
+		}
+		else
+			log_notice("Pass1c complete\n");
+	}
+	if (!fsck_abort) {
+		last_reported_block = 0;
+		pass = "pass 2";
+		log_notice("Starting pass2\n");
+		if (pass2(sbp))
+			return 1;
+		if (skip_this_pass || fsck_abort) {
+			skip_this_pass = FALSE;
+			log_notice("Pass2 interrupted   \n");
+		}
+		else
+			log_notice("Pass2 complete      \n");
+	}
+	if (!fsck_abort) {
+		last_reported_block = 0;
+		pass = "pass 3";
+		log_notice("Starting pass3\n");
+		if (pass3(sbp))
+			return 1;
+		if (skip_this_pass || fsck_abort) {
+			skip_this_pass = FALSE;
+			log_notice("Pass3 interrupted   \n");
+		}
+		else
+			log_notice("Pass3 complete      \n");
+	}
+	if (!fsck_abort) {
+		last_reported_block = 0;
+		pass = "pass 4";
+		log_notice("Starting pass4\n");
+		if (pass4(sbp))
+			return 1;
+		if (skip_this_pass || fsck_abort) {
+			skip_this_pass = FALSE;
+			log_notice("Pass4 interrupted   \n");
+		}
+		else
+			log_notice("Pass4 complete      \n");
+	}
+	if (!fsck_abort) {
+		last_reported_block = 0;
+		pass = "pass 5";
+		log_notice("Starting pass5\n");
+		if (pass5(sbp))
+			return 1;
+		if (skip_this_pass || fsck_abort) {
+			skip_this_pass = FALSE;
+			log_notice("Pass5 interrupted   \n");
+		}
+		else
+			log_notice("Pass5 complete      \n");
+	}
 	/* Free up our system inodes */
 	inode_put(sbp->md.inum, updated);
 	inode_put(sbp->md.statfs, updated);
--- cluster/gfs2/fsck/pass1.c	2006/06/20 18:30:55	1.4
+++ cluster/gfs2/fsck/pass1.c	2007/01/23 19:23:07	1.5
@@ -801,6 +801,13 @@
 			if (gfs2_next_rg_meta(rgd, &block, first))
 				break;
 			warm_fuzzy_stuff(block);
+			if (fsck_abort) /* if asked to abort */
+				return 0;
+			if (skip_this_pass) {
+				printf("Skipping pass 1 is not a good idea.\n");
+				skip_this_pass = FALSE;
+				fflush(stdout);
+			}
 			bh = bread(sbp, block);
 
 			if (scan_meta(sbp, bh, block)) {
--- cluster/gfs2/fsck/pass1b.c	2006/06/12 20:41:43	1.3
+++ cluster/gfs2/fsck/pass1b.c	2007/01/23 19:23:07	1.4
@@ -466,6 +466,7 @@
 	osi_list_t *tmp;
 	struct metawalk_fxns find_dirents = {0};
 	find_dirents.check_dentry = &find_dentry;
+	int rc = 0;
 
 	osi_list_init(&dup_list);
 	/* Shove all blocks marked as duplicated into a list */
@@ -484,11 +485,15 @@
 	log_debug("Filesystem has %"PRIu64" (0x%" PRIx64 ") blocks total\n",
 			  last_fs_block, last_fs_block);
 	for(i = 0; i < last_fs_block; i += 1) {
+		warm_fuzzy_stuff(i);
+		if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
+			goto out;
 		log_debug("Scanning block %" PRIu64 " (0x%" PRIx64 ") for inodes\n",
 				  i, i);
 		if(gfs2_block_check(bl, i, &q)) {
 			stack;
-			return -1;
+			rc = -1;
+			goto out;
 		}
 		if((q.block_type == gfs2_inode_dir) ||
 		   (q.block_type == gfs2_inode_file) ||
@@ -501,33 +506,26 @@
 				b = osi_list_entry(tmp, struct blocks, list);
 				if(find_block_ref(sbp, i, b)) {
 					stack;
-					return -1;
+					rc = -1;
+					goto out;
 				}
 			}
 		}
-	}
-
-	/* Rescan the fs looking for directory entries to the inodes
-	 * with duplicate blocks - might need this to deal with the
-	 * inode correctly */
-	log_info("Looking through directory entries for inodes with duplicate blocks...\n");
-	for(i = 0; i < last_fs_block; i++) {
-		if(gfs2_block_check(bl, i, &q)) {
-			stack;
-			return 0;
-		}
 		if(q.block_type == gfs2_inode_dir) {
 			check_dir(sbp, i, &find_dirents);
 		}
 	}
 
-
 	/* Fix dups here - it's going to slow things down a lot to fix
 	 * it later */
 	log_info("Handling duplicate blocks\n");
-	osi_list_foreach(tmp, &dup_list) {
+out:
+	while (!osi_list_empty(&dup_list)) {
 		b = osi_list_entry(tmp, struct blocks, list);
-		handle_dup_blk(sbp, b);
+		if (!skip_this_pass && !rc) /* no error & not asked to skip the rest */
+			handle_dup_blk(sbp, b);
+		osi_list_del(&b->list);
+		free(b);
 	}
-	return 0;
+	return rc;
 }
--- cluster/gfs2/fsck/pass1c.c	2006/06/20 18:30:55	1.4
+++ cluster/gfs2/fsck/pass1c.c	2007/01/23 19:23:07	1.5
@@ -235,6 +235,8 @@
 	log_info("Looking for inodes containing ea blocks...\n");
 	while (!gfs2_find_next_block_type(bl, gfs2_eattr_block, &block_no)) {
 
+		if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
+			return 0;
 		log_info("EA in inode %"PRIu64" (0x%" PRIx64 ")\n", block_no,
 				 block_no);
 		bh = bread(sbp, block_no);
--- cluster/gfs2/fsck/pass2.c	2006/06/15 18:48:45	1.4
+++ cluster/gfs2/fsck/pass2.c	2007/01/23 19:23:07	1.5
@@ -757,8 +757,13 @@
 		stack;
 		return -1;
 	}
+	log_info("Checking directory inodes.\n");
 	/* Grab each directory inode, and run checks on it */
 	for(i = 0; i < last_fs_block; i++) {
+		warm_fuzzy_stuff(i);
+		if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
+			return 0;
+
 		/* Skip the root inode - it's checked above */
 		if(i == sbp->md.rooti->i_di.di_num.no_addr)
 			continue;
--- cluster/gfs2/fsck/pass3.c	2006/06/15 18:48:45	1.4
+++ cluster/gfs2/fsck/pass3.c	2007/01/23 19:23:07	1.5
@@ -214,6 +214,8 @@
 			/* FIXME: Change this so it returns success or
 			 * failure and put the parent inode in a
 			 * param */
+			if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
+				return 0;
 			tdi = mark_and_return_parent(sbp, di);
 
 			/* FIXME: Factor this ? */
--- cluster/gfs2/fsck/pass4.c	2006/06/15 18:48:45	1.4
+++ cluster/gfs2/fsck/pass4.c	2007/01/23 19:23:07	1.5
@@ -48,6 +48,8 @@
 	/* FIXME: should probably factor this out into a generic
 	 * scanning fxn */
 	osi_list_foreach(tmp, list) {
+		if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
+			return 0;
 		f = not_updated;
 		if(!(ii = osi_list_entry(tmp, struct inode_info, list))) {
 			log_crit("osi_list_foreach broken in scan_info_list!!\n");
@@ -165,6 +167,8 @@
 				  lf_dip->i_di.di_entries);
 	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;
 		list = &inode_hash[i];
 		if(scan_inode_list(sbp, list)) {
 			stack;
--- cluster/gfs2/fsck/pass5.c	2006/06/12 20:41:43	1.3
+++ cluster/gfs2/fsck/pass5.c	2007/01/23 19:23:07	1.4
@@ -77,7 +77,10 @@
 	while(byte < end) {
 		rg_status = ((*byte >> bit) & GFS2_BIT_MASK);
 		block = rg_data + *rg_block;
+		log_debug("Checking block %" PRIu64 "\n", block);
 		warm_fuzzy_stuff(block);
+		if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
+			return 0;
 		gfs2_block_check(bl, block, &q);
 
 		block_status = convert_mark(q.block_type, count);
@@ -128,6 +131,8 @@
 		/* update the bitmaps */
 		check_block_status(sbp, rgp->bh[i]->b_data + bits->bi_offset,
 						   bits->bi_len, &rg_block, rgp->ri.ri_data0, count);
+		if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
+			return 0;
 	}
 
 	/* actually adjust counters and write out to disk */
@@ -180,6 +185,8 @@
 	for(tmp = sbp->rglist.next; tmp != &sbp->rglist; tmp = tmp->next){
 		enum update_flags f;
 
+		if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
+			return 0;
 		log_info("Verifying Resource Group #%" PRIu64 "\n", rg_count);
 		memset(count, 0, sizeof(count));
 		rgp = osi_list_entry(tmp, struct rgrp_list, list);
--- cluster/gfs2/fsck/util.c	2006/06/15 18:48:45	1.4
+++ cluster/gfs2/fsck/util.c	2007/01/23 19:23:07	1.5
@@ -60,16 +60,19 @@
 {
 	static struct timeval tv;
 	static uint32_t seconds = 0;
-
+	
+	last_reported_block = block;
 	gettimeofday(&tv, NULL);
 	if (!seconds)
-        seconds = tv.tv_sec;
+		seconds = tv.tv_sec;
 	if (tv.tv_sec - seconds) {
 		uint64_t percent;
 
 		seconds = tv.tv_sec;
-		percent = (block * 100) / last_fs_block;
-		log_notice("\r%" PRIu64 " percent complete.\r", percent);
+		if (last_fs_block) {
+			percent = (block * 100) / last_fs_block;
+			log_notice("\r%" PRIu64 " percent complete.\r", percent);
+		}
 	}
 }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]