From mboxrd@z Thu Jan 1 00:00:00 1970 From: rpeterso@sourceware.org Date: 23 Jan 2007 19:30:21 -0000 Subject: [Cluster-devel] cluster/gfs2 fsck/fsck.h fsck/initialize.c fsc ... Message-ID: <20070123193021.26271.qmail@sourceware.org> List-Id: To: cluster-devel.redhat.com MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit CVSROOT: /cvs/cluster Module name: cluster Branch: RHEL5 Changes by: rpeterso at sourceware.org 2007-01-23 19:30:19 Modified files: gfs2/fsck : fsck.h initialize.c main.c pass1.c pass1b.c pass1c.c pass2.c pass3.c pass4.c pass5.c util.c gfs2/libgfs2 : gfs2_log.c libgfs2.h 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/fsck/fsck.h.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.3&r2=1.3.2.1 http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/fsck/initialize.c.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.6&r2=1.6.2.1 http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/fsck/main.c.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.4&r2=1.4.2.1 http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/fsck/pass1.c.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.4&r2=1.4.2.1 http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/fsck/pass1b.c.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.3&r2=1.3.2.1 http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/fsck/pass1c.c.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.4&r2=1.4.2.1 http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/fsck/pass2.c.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.4&r2=1.4.2.1 http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/fsck/pass3.c.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.4&r2=1.4.2.1 http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/fsck/pass4.c.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.4&r2=1.4.2.1 http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/fsck/pass5.c.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.3&r2=1.3.2.1 http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/fsck/util.c.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.4&r2=1.4.2.1 http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/libgfs2/gfs2_log.c.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.2&r2=1.2.2.1 http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/libgfs2/libgfs2.h.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.7.2.1&r2=1.7.2.2 --- cluster/gfs2/fsck/fsck.h 2006/06/12 20:41:43 1.3 +++ cluster/gfs2/fsck/fsck.h 2007/01/23 19:30:19 1.3.2.1 @@ -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:30:19 1.6.2.1 @@ -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:30:19 1.4.2.1 @@ -17,6 +17,8 @@ #include #include #include +#include +#include #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:30:19 1.4.2.1 @@ -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:30:19 1.3.2.1 @@ -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:30:19 1.4.2.1 @@ -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:30:19 1.4.2.1 @@ -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:30:19 1.4.2.1 @@ -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:30:19 1.4.2.1 @@ -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:30:19 1.3.2.1 @@ -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:30:19 1.4.2.1 @@ -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); + } } } --- cluster/gfs2/libgfs2/gfs2_log.c 2006/06/15 18:45:22 1.2 +++ cluster/gfs2/libgfs2/gfs2_log.c 2007/01/23 19:30:19 1.2.2.1 @@ -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:29:48 1.7.2.1 +++ cluster/gfs2/libgfs2/libgfs2.h 2007/01/23 19:30:19 1.7.2.2 @@ -437,6 +437,7 @@ char *device; int yes:1; int no:1; + int query:1; }; #define MSG_DEBUG 7