From db8e986c61de164e2f4ec58420f3e03ab3ec74dd Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Nov 19 2015 03:36:40 +0000 Subject: import gfs2-utils-3.1.8-6.el7 --- diff --git a/.gfs2-utils.metadata b/.gfs2-utils.metadata index b9bded1..ef5589c 100644 --- a/.gfs2-utils.metadata +++ b/.gfs2-utils.metadata @@ -1 +1 @@ -eef8cf193ba4ca8edb32cab40307e702ab73fc2c SOURCES/gfs2-utils-3.1.7.tar.gz +cd76f70559b4c97b7dc8aa7c3cef74291ec7957b SOURCES/gfs2-utils-3.1.8.tar.gz diff --git a/.gitignore b/.gitignore index 603e861..da093ca 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/gfs2-utils-3.1.7.tar.gz +SOURCES/gfs2-utils-3.1.8.tar.gz diff --git a/SOURCES/bz1112342-1-gfs2_utils_tests_Build_unit_tests_with_consistent_cpp_flags.patch b/SOURCES/bz1112342-1-gfs2_utils_tests_Build_unit_tests_with_consistent_cpp_flags.patch deleted file mode 100644 index c85bb70..0000000 --- a/SOURCES/bz1112342-1-gfs2_utils_tests_Build_unit_tests_with_consistent_cpp_flags.patch +++ /dev/null @@ -1,56 +0,0 @@ -commit e0e4c93b80f36fc40a5d631a14615162f27f3371 -Author: Andrew Price -Date: Mon Sep 8 12:03:40 2014 +0200 - - gfs2-utils tests: Build unit tests with consistent cpp flags - - The check_rgrp unit test was failing on ARM and s390 due to struct - gfs2_sbd having a different alignment from libgfs2. This was due to the - unit tests being built with different options to libgfs2. Fix up the - unit test CPPFLAGS to make sure the alignment is consistent. - - Also bump the test timeout for check_rgrp to make sure it completes on - slower build machines. - - Signed-off-by: Andrew Price - -diff --git a/tests/Makefile.am b/tests/Makefile.am -index 70e77ef..b912dfa 100644 ---- a/tests/Makefile.am -+++ b/tests/Makefile.am -@@ -15,16 +15,22 @@ UNIT_CFLAGS = \ - UNIT_LDADD = \ - $(top_builddir)/gfs2/libgfs2/libgfs2.la \ - @check_LIBS@ -+UNIT_CPPFLAGS = \ -+ -D_FILE_OFFSET_BITS=64 \ -+ -D_LARGEFILE64_SOURCE \ -+ -D_GNU_SOURCE - - check_PROGRAMS = $(UNIT_TESTS) - - check_meta_SOURCES = $(UNIT_SOURCES) check_meta.c - check_meta_CFLAGS = $(UNIT_CFLAGS) - check_meta_LDADD = $(UNIT_LDADD) -+check_meta_CPPFLAGS = $(UNIT_CPPFLAGS) - - check_rgrp_SOURCES = $(UNIT_SOURCES) check_rgrp.c - check_rgrp_CFLAGS = $(UNIT_CFLAGS) - check_rgrp_LDADD = $(UNIT_LDADD) -+check_rgrp_CPPFLAGS = $(UNIT_CPPFLAGS) - endif - - # The `:;' works around a Bash 3.2 bug when the output is not writable. -diff --git a/tests/check_rgrp.c b/tests/check_rgrp.c -index d113846..e5fca8d 100644 ---- a/tests/check_rgrp.c -+++ b/tests/check_rgrp.c -@@ -125,7 +125,7 @@ static Suite * libgfs2_suite(void) - tcase_add_test(tc_rgrp, test_rbm_find_good); - tcase_add_test(tc_rgrp, test_rbm_find_bad); - tcase_add_test(tc_rgrp, test_rbm_find_lastblock); -- tcase_set_timeout(tc_rgrp, 60); -+ tcase_set_timeout(tc_rgrp, 120); - suite_add_tcase(s, tc_rgrp); - - return s; diff --git a/SOURCES/bz1112342-2-gfs2_utils_tests_Fix_unit_tests_for_RHEL7.patch b/SOURCES/bz1112342-2-gfs2_utils_tests_Fix_unit_tests_for_RHEL7.patch deleted file mode 100644 index 33d073c..0000000 --- a/SOURCES/bz1112342-2-gfs2_utils_tests_Fix_unit_tests_for_RHEL7.patch +++ /dev/null @@ -1,28 +0,0 @@ -commit 9142cd526adfb9739b92419fc1faa0b4730e936d -Author: Andrew Price -Date: Mon Sep 8 10:18:11 2014 +0100 - - gfs2-utils tests: Fix unit tests for RHEL7 - - Older versions of check-devel do not have ck_assert_ptr_ne nor - ck_assert_uint_eq so provide macros to map them to fail_unless calls. - - Resolves: rhbz#1112342 - - Signed-off-by: Andrew Price - -diff --git a/tests/check_rgrp.c b/tests/check_rgrp.c -index e5fca8d..36dffe4 100644 ---- a/tests/check_rgrp.c -+++ b/tests/check_rgrp.c -@@ -5,6 +5,10 @@ - // TODO: Remove this when the extern is removed from libgfs2 - void print_it(const char *label, const char *fmt, const char *fmt2, ...) {} - -+/* Older check-devel doesn't have these functions */ -+#define ck_assert_ptr_ne(ptr, val) fail_unless(ptr != val) -+#define ck_assert_uint_eq(u1, u2) fail_unless(u1 == u2) -+ - static lgfs2_rgrps_t mockup_rgrp(void) - { - struct gfs2_sbd *sdp; diff --git a/SOURCES/bz1146160-fsck_gfs2_Detect_and_correct_corrupt_journals.patch b/SOURCES/bz1146160-fsck_gfs2_Detect_and_correct_corrupt_journals.patch deleted file mode 100644 index 80a8836..0000000 --- a/SOURCES/bz1146160-fsck_gfs2_Detect_and_correct_corrupt_journals.patch +++ /dev/null @@ -1,161 +0,0 @@ -commit 86fe75d99f1838410bebaf6f459bfee3333e5756 -Author: Bob Peterson -Date: Thu Nov 13 09:54:16 2014 -0600 - - fsck.gfs2: Detect and correct corrupt journals - - This patch changes fsck.gfs2 so that it can detect corruption in the - journal sequence numbering scheme. If the corruption is within a - certain tolerance (currently 10 sequencing errors) the journal sequence - numbers are fixed and journal is replayed as normal. If there are more - errors than can be tolerated, the problem is detected and the journal - may be cleared. - - rhbz#1146160 - -diff --git a/gfs2/fsck/fs_recovery.c b/gfs2/fsck/fs_recovery.c -index bc4210d..3d8fe98 100644 ---- a/gfs2/fsck/fs_recovery.c -+++ b/gfs2/fsck/fs_recovery.c -@@ -17,6 +17,7 @@ - #include "util.h" - - #define JOURNAL_NAME_SIZE 16 -+#define JOURNAL_SEQ_TOLERANCE 10 - - unsigned int sd_found_jblocks = 0, sd_replayed_jblocks = 0; - unsigned int sd_found_metablocks = 0, sd_replayed_metablocks = 0; -@@ -138,10 +139,15 @@ static int buf_lo_scan_elements(struct gfs2_inode *ip, unsigned int start, - check_magic = ((struct gfs2_meta_header *) - (bh_ip->b_data))->mh_magic; - check_magic = be32_to_cpu(check_magic); -- if (check_magic != GFS2_MAGIC) -+ if (check_magic != GFS2_MAGIC) { -+ log_err(_("Journal corruption detected at block #" -+ "%lld (0x%llx) for journal+0x%x.\n"), -+ (unsigned long long)blkno, (unsigned long long)blkno, -+ start); - error = -EIO; -- else -+ } else { - bmodified(bh_ip); -+ } - - brelse(bh_log); - brelse(bh_ip); -@@ -313,8 +319,11 @@ static int foreach_descriptor(struct gfs2_inode *ip, unsigned int start, - brelse(bh); - continue; - } -- if (error == 1) -+ if (error == 1) { -+ log_err(_("Journal corruption detected at " -+ "journal+0x%x.\n"), start); - error = -EIO; -+ } - bmodified(bh); - brelse(bh); - return error; -@@ -354,10 +363,13 @@ static int foreach_descriptor(struct gfs2_inode *ip, unsigned int start, - } - - /** -- * fix_journal_seq_no - Fix log header sequencing problems -+ * check_journal_seq_no - Check and Fix log header sequencing problems - * @ip: the journal incore inode -+ * @fix: if 1, fix the sequence numbers, otherwise just report the problem -+ * -+ * Returns: The number of sequencing errors (hopefully none). - */ --static int fix_journal_seq_no(struct gfs2_inode *ip) -+static int check_journal_seq_no(struct gfs2_inode *ip, int fix) - { - int error = 0, wrapped = 0; - uint32_t jd_blocks = ip->i_di.di_size / ip->i_sbd->sd_sb.sb_bsize; -@@ -368,6 +380,7 @@ static int fix_journal_seq_no(struct gfs2_inode *ip) - uint64_t dblock; - uint32_t extlen; - struct gfs2_buffer_head *bh; -+ int seq_errors = 0; - - memset(&lh, 0, sizeof(lh)); - for (blk = 0; blk < jd_blocks; blk++) { -@@ -395,6 +408,10 @@ static int fix_journal_seq_no(struct gfs2_inode *ip) - (unsigned long long)lowest_seq, - (unsigned long long)highest_seq, - (unsigned long long)prev_seq); -+ if (!fix) { -+ seq_errors++; -+ continue; -+ } - highest_seq++; - lh.lh_sequence = highest_seq; - prev_seq = lh.lh_sequence; -@@ -404,7 +421,9 @@ static int fix_journal_seq_no(struct gfs2_inode *ip) - gfs2_log_header_out(&lh, bh); - brelse(bh); - } -- return 0; -+ if (seq_errors && fix) -+ log_err(_("%d sequence errors fixed.\n"), seq_errors); -+ return seq_errors; - } - - /** -@@ -456,6 +475,15 @@ static int gfs2_recover_journal(struct gfs2_inode *ip, int j, int preen, - - osi_list_init(&sd_revoke_list); - error = gfs2_find_jhead(ip, &head); -+ if (!error) { -+ error = check_journal_seq_no(ip, 0); -+ if (error > JOURNAL_SEQ_TOLERANCE) { -+ log_err( _("Journal #%d (\"journal%d\") has %d " -+ "sequencing errors; tolerance is %d.\n"), -+ j+1, j, error, JOURNAL_SEQ_TOLERANCE); -+ goto out; -+ } -+ } - if (error) { - if (opts.no) { - log_err( _("Journal #%d (\"journal%d\") is corrupt\n"),j+1, j); -@@ -481,7 +509,7 @@ static int gfs2_recover_journal(struct gfs2_inode *ip, int j, int preen, - goto out; - } - log_info( _("jid=%u: Repairing journal...\n"), j); -- error = fix_journal_seq_no(ip); -+ error = check_journal_seq_no(ip, 1); - if (error) { - log_err( _("jid=%u: Unable to fix the bad journal.\n"), - j); -@@ -530,8 +558,10 @@ static int gfs2_recover_journal(struct gfs2_inode *ip, int j, int preen, - for (pass = 0; pass < 2; pass++) { - error = foreach_descriptor(ip, head.lh_tail, - head.lh_blkno, pass); -- if (error) -+ if (error) { -+ log_err(_("Error found during journal replay.\n")); - goto out; -+ } - } - log_info( _("jid=%u: Found %u revoke tags\n"), j, sd_found_revokes); - gfs2_revoke_clean(sdp); -@@ -550,14 +580,16 @@ out: - log_info( _("jid=%u: Done\n"), j); - return 0; - } -- log_info( _("jid=%u: Failed\n"), j); -+ log_err( _("jid=%u: Failed\n"), j); - reinit: -- if (query( _("Do you want to clear the journal instead? (y/n)"))) -+ if (query( _("Do you want to clear the journal instead? (y/n)"))) { - error = write_journal(sdp->md.journal[j], sdp->bsize, - sdp->md.journal[j]->i_di.di_size / - sdp->sd_sb.sb_bsize); -- else -+ log_err(_("jid=%u: journal was cleared.\n"), j); -+ } else { - log_err( _("jid=%u: journal not cleared.\n"), j); -+ } - return error; - } - diff --git a/SOURCES/bz1154786-fsck_gfs2_Improve_reporting_of_pass_timings.patch b/SOURCES/bz1154786-fsck_gfs2_Improve_reporting_of_pass_timings.patch deleted file mode 100644 index a630fa8..0000000 --- a/SOURCES/bz1154786-fsck_gfs2_Improve_reporting_of_pass_timings.patch +++ /dev/null @@ -1,90 +0,0 @@ -commit 34ab6e375e654b5b8b4c4c3c01e12c9f9749a928 -Author: Andrew Price -Date: Thu Nov 13 07:43:01 2014 -0500 - - fsck.gfs2: Improve reporting of pass timings - - The days value is not currently reported in the pass timings but the - hours value is still reported modulo 24. Drop the use of gmtime(3) as - it's more appropriate for calendar time operations than elapsed time, - and add a simple duration reporting function which matches the existing - output format. - - Resolves: rhbz#1154786 - - Signed-off-by: Andrew Price - -diff --git a/gfs2/fsck/main.c b/gfs2/fsck/main.c -index b25d802..a4af25d 100644 ---- a/gfs2/fsck/main.c -+++ b/gfs2/fsck/main.c -@@ -246,18 +246,46 @@ static const struct fsck_pass passes[] = { - { .name = NULL, } - }; - -+static void print_pass_duration(const char *name, struct timeval *start) -+{ -+ char duration[17] = ""; /* strlen("XXdXXhXXmXX.XXXs") + 1 */ -+ struct timeval end, diff; -+ unsigned d, h, m, s; -+ char *p = duration; -+ -+ gettimeofday(&end, NULL); -+ timersub(&end, start, &diff); -+ -+ s = diff.tv_sec % 60; -+ diff.tv_sec /= 60; -+ m = diff.tv_sec % 60; -+ diff.tv_sec /= 60; -+ h = diff.tv_sec % 24; -+ d = diff.tv_sec / 24; -+ -+ if (d) -+ p += snprintf(p, 4, "%ud", d > 99 ? 99U : d); -+ if (h) -+ p += snprintf(p, 4, "%uh", h); -+ if (m) -+ p += snprintf(p, 4, "%um", m); -+ -+ snprintf(p, 8, "%u.%03lus", s, diff.tv_usec / 1000); -+ log_notice(_("%s completed in %s\n"), name, duration); -+} -+ - static int fsck_pass(const struct fsck_pass *p, struct gfs2_sbd *sdp) - { - int ret; -- struct timeval before, after, diff; -- time_t runtime; -- struct tm *run_tm; -+ struct timeval timer; - - if (fsck_abort) - return FSCK_CANCELED; - pass = p->name; -+ - log_notice( _("Starting %s\n"), p->name); -- gettimeofday(&before, 0); -+ gettimeofday(&timer, NULL); -+ - ret = p->f(sdp); - if (ret) - exit(ret); -@@ -266,16 +294,8 @@ static int fsck_pass(const struct fsck_pass *p, struct gfs2_sbd *sdp) - log_notice( _("%s interrupted \n"), p->name); - return FSCK_CANCELED; - } -- gettimeofday(&after, 0); -- timersub(&after, &before, &diff); -- runtime = (time_t)diff.tv_sec; -- run_tm = gmtime(&runtime); -- log_notice( _("%s completed in "), p->name); -- if (run_tm->tm_hour) -- log_notice("%dh", run_tm->tm_hour); -- if (run_tm->tm_min) -- log_notice("%dm", run_tm->tm_min); -- log_notice("%d.%03lds \n", run_tm->tm_sec, diff.tv_usec / 1000); -+ -+ print_pass_duration(p->name, &timer); - return 0; - } - diff --git a/SOURCES/bz1162216-gfs2_edit_savemeta_speed_up_is_block_in_per_node.patch b/SOURCES/bz1162216-gfs2_edit_savemeta_speed_up_is_block_in_per_node.patch new file mode 100644 index 0000000..313e77b --- /dev/null +++ b/SOURCES/bz1162216-gfs2_edit_savemeta_speed_up_is_block_in_per_node.patch @@ -0,0 +1,135 @@ +commit 342ab070d42625e6e4b65caf66f7b7117f7d4509 +Author: Andrew Price +Date: Wed Sep 2 14:12:31 2015 -0500 + + gfs2_edit savemeta: speed up is_block_in_per_node() + + Previously is_block_in_per_node() called lgfs2_inode_read() and + do_dinode_extended() for each block and savemeta was spending the vast + majority of its time in this function according to perf. This patch + speeds up the lookups by keeping a tree of per_node block addresses + which can be quickly consulted. In my tests with a full 700G filesystem + this patch cuts the run time in half. + + Resolves: rhbz#1162216 + Signed-off-by: Andrew Price + +diff --git a/gfs2/edit/savemeta.c b/gfs2/edit/savemeta.c +index b68b0ff..b08eb5e 100644 +--- a/gfs2/edit/savemeta.c ++++ b/gfs2/edit/savemeta.c +@@ -74,8 +74,70 @@ static int block_is_a_journal(void) + return FALSE; + } + ++struct osi_root per_node_tree; ++struct per_node_node { ++ struct osi_node node; ++ uint64_t block; ++}; ++ ++static void destroy_per_node_lookup(void) ++{ ++ struct osi_node *n; ++ struct per_node_node *pnp; ++ ++ while ((n = osi_first(&per_node_tree))) { ++ pnp = (struct per_node_node *)n; ++ osi_erase(n, &per_node_tree); ++ free(pnp); ++ } ++} ++ + static int block_is_in_per_node(void) + { ++ struct per_node_node *pnp = (struct per_node_node *)per_node_tree.osi_node; ++ ++ while (pnp) { ++ if (block < pnp->block) ++ pnp = (struct per_node_node *)pnp->node.osi_left; ++ else if (block > pnp->block) ++ pnp = (struct per_node_node *)pnp->node.osi_right; ++ else ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static int insert_per_node_lookup(uint64_t blk) ++{ ++ struct osi_node **newn = &per_node_tree.osi_node, *parent = NULL; ++ struct per_node_node *pnp; ++ ++ while (*newn) { ++ struct per_node_node *cur = (struct per_node_node *)*newn; ++ ++ parent = *newn; ++ if (blk < cur->block) ++ newn = &((*newn)->osi_left); ++ else if (blk > cur->block) ++ newn = &((*newn)->osi_right); ++ else ++ return 0; ++ } ++ ++ pnp = calloc(1, sizeof(struct per_node_node)); ++ if (pnp == NULL) { ++ perror("Failed to insert per_node lookup entry"); ++ return 1; ++ } ++ pnp->block = blk; ++ osi_link_node(&pnp->node, parent, newn); ++ osi_insert_color(&pnp->node, &per_node_tree); ++ return 0; ++} ++ ++static int init_per_node_lookup(void) ++{ + int i; + struct gfs2_inode *per_node_di; + +@@ -85,7 +147,7 @@ static int block_is_in_per_node(void) + per_node_di = lgfs2_inode_read(&sbd, masterblock("per_node")); + if (per_node_di == NULL) { + fprintf(stderr, "Failed to read per_node: %s\n", strerror(errno)); +- exit(1); ++ return 1; + } + + do_dinode_extended(&per_node_di->i_di, per_node_di->i_bh); +@@ -94,11 +156,12 @@ static int block_is_in_per_node(void) + for (i = 0; i < indirect_blocks; i++) { + int d; + for (d = 0; d < indirect->ii[i].dirents; d++) { +- if (block == indirect->ii[i].dirent[d].block) +- return TRUE; ++ int ret = insert_per_node_lookup(indirect->ii[i].dirent[d].block); ++ if (ret != 0) ++ return ret; + } + } +- return FALSE; ++ return 0; + } + + static int block_is_systemfile(void) +@@ -749,6 +812,10 @@ void savemeta(char *out_fn, int saveoption, int gziplevel) + printf("Filesystem size: %s\n", anthropomorphize(sbd.fssize * sbd.bsize)); + get_journal_inode_blocks(); + ++ err = init_per_node_lookup(); ++ if (err) ++ exit(1); ++ + /* Write the savemeta file header */ + err = save_header(&mfd, sbd.fssize * sbd.bsize); + if (err) { +@@ -810,6 +877,7 @@ void savemeta(char *out_fn, int saveoption, int gziplevel) + } + savemetaclose(&mfd); + close(sbd.device_fd); ++ destroy_per_node_lookup(); + free(indirect); + gfs2_rgrp_free(&sbd.rgtree); + exit(0); diff --git a/SOURCES/bz1162817-mkfs_gfs2_Revert_default_resource_group_size.patch b/SOURCES/bz1162817-mkfs_gfs2_Revert_default_resource_group_size.patch deleted file mode 100644 index 7bcc648..0000000 --- a/SOURCES/bz1162817-mkfs_gfs2_Revert_default_resource_group_size.patch +++ /dev/null @@ -1,27 +0,0 @@ -commit 33c48a55afa572b86de40364246d749a0e5d44e2 -Author: Andrew Price -Date: Thu Nov 13 14:09:08 2014 +0000 - - mkfs.gfs2: Revert default resource group size - - Choose a more performant resource group size than the maximum by default - until gfs2 is more tuned for the larger number of bitmap blocks required - for 2GB resource groups. - - Resolves: rhbz#1162817 - - Signed-off-by: Andrew Price - -diff --git a/gfs2/mkfs/main_mkfs.c b/gfs2/mkfs/main_mkfs.c -index e927d82..f4b8fe6 100644 ---- a/gfs2/mkfs/main_mkfs.c -+++ b/gfs2/mkfs/main_mkfs.c -@@ -159,7 +159,7 @@ static void opts_init(struct mkfs_opts *opts) - opts->bsize = GFS2_DEFAULT_BSIZE; - opts->jsize = GFS2_DEFAULT_JSIZE; - opts->qcsize = GFS2_DEFAULT_QCSIZE; -- opts->rgsize = GFS2_MAX_RGSIZE; -+ opts->rgsize = GFS2_DEFAULT_RGSIZE; - opts->lockproto = "lock_dlm"; - opts->locktable = ""; - opts->confirm = 1; diff --git a/SOURCES/bz1178604-1-fsck_gfs2_fix_broken_i_goal_values_in_inodes.patch b/SOURCES/bz1178604-1-fsck_gfs2_fix_broken_i_goal_values_in_inodes.patch deleted file mode 100644 index 55f6f7a..0000000 --- a/SOURCES/bz1178604-1-fsck_gfs2_fix_broken_i_goal_values_in_inodes.patch +++ /dev/null @@ -1,173 +0,0 @@ -commit b09dae840a4e91e59cf73089da8e18bc0f299e80 -Author: Abhi Das -Date: Fri Dec 5 10:16:49 2014 -0600 - - fsck.gfs2: fix broken i_goal values in inodes - - This patch allows fsck.gfs2 to fix bad values for the i_goal - field in inodes that could arise from a gfs1->gfs2 conversion - or through other corruption - - Resolves: rhbz#1149516 - Signed-off-by: Abhi Das - -diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c -index 329fc3b..9aa9fb8 100644 ---- a/gfs2/fsck/metawalk.c -+++ b/gfs2/fsck/metawalk.c -@@ -1395,7 +1395,8 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp, - */ - static int check_data(struct gfs2_inode *ip, struct metawalk_fxns *pass, - struct gfs2_buffer_head *bh, int head_size, -- uint64_t *blks_checked, uint64_t *error_blk) -+ uint64_t *last_block, uint64_t *blks_checked, -+ uint64_t *error_blk) - { - int error = 0, rc = 0; - uint64_t block, *ptr; -@@ -1410,7 +1411,7 @@ static int check_data(struct gfs2_inode *ip, struct metawalk_fxns *pass, - - if (skip_this_pass || fsck_abort) - return error; -- block = be64_to_cpu(*ptr); -+ *last_block = block = be64_to_cpu(*ptr); - /* It's important that we don't call valid_block() and - bypass calling check_data on invalid blocks because that - would defeat the rangecheck_block related functions in -@@ -1490,7 +1491,7 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass) - struct gfs2_buffer_head *bh; - uint32_t height = ip->i_di.di_height; - int i, head_size; -- uint64_t blks_checked = 0; -+ uint64_t blks_checked = 0, last_block = 0; - int error, rc; - int metadata_clean = 0; - uint64_t error_blk = 0; -@@ -1514,6 +1515,9 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass) - * comprise the directory hash table, so we perform the directory - * checks and exit. */ - if (is_dir(&ip->i_di, ip->i_sbd->gfs1)) { -+ last_block = ip->i_di.di_num.no_addr; -+ if (pass->check_i_goal) -+ pass->check_i_goal(ip, last_block, pass->private); - if (!(ip->i_di.di_flags & GFS2_DIF_EXHASH)) - goto out; - /* check validity of leaf blocks and leaf chains */ -@@ -1540,7 +1544,7 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass) - - if (pass->check_data) - error = check_data(ip, pass, bh, head_size, -- &blks_checked, &error_blk); -+ &last_block, &blks_checked, &error_blk); - if (pass->big_file_msg && ip->i_di.di_blocks > COMFORTABLE_BLKS) - pass->big_file_msg(ip, blks_checked); - } -@@ -1552,6 +1556,8 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass) - (unsigned long long)ip->i_di.di_num.no_addr); - fflush(stdout); - } -+ if (!error && pass->check_i_goal) -+ pass->check_i_goal(ip, last_block, pass->private); - undo_metalist: - if (!error) - goto out; -diff --git a/gfs2/fsck/metawalk.h b/gfs2/fsck/metawalk.h -index a4e0676..b3c1299 100644 ---- a/gfs2/fsck/metawalk.h -+++ b/gfs2/fsck/metawalk.h -@@ -90,6 +90,7 @@ enum meta_check_rc { - * check_dentry: - * check_eattr_entry: - * check_eattr_extentry: -+ * check_i_goal: - */ - struct metawalk_fxns { - void *private; -@@ -141,6 +142,8 @@ struct metawalk_fxns { - struct gfs2_ea_header *ea_hdr, - struct gfs2_ea_header *ea_hdr_prev, - void *private); -+ int (*check_i_goal) (struct gfs2_inode *ip, uint64_t goal_blk, -+ void *private); - int (*finish_eattr_indir) (struct gfs2_inode *ip, int leaf_pointers, - int leaf_pointer_errors, void *private); - void (*big_file_msg) (struct gfs2_inode *ip, uint64_t blks_checked); -diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c -index 90ca357..60f0356 100644 ---- a/gfs2/fsck/pass1.c -+++ b/gfs2/fsck/pass1.c -@@ -62,6 +62,7 @@ static int check_extended_leaf_eattr(struct gfs2_inode *ip, uint64_t *data_ptr, - struct gfs2_ea_header *ea_hdr, - struct gfs2_ea_header *ea_hdr_prev, - void *private); -+static int check_i_goal(struct gfs2_inode *ip, uint64_t goal_blk, void *private); - static int finish_eattr_indir(struct gfs2_inode *ip, int leaf_pointers, - int leaf_pointer_errors, void *private); - static int invalidate_metadata(struct gfs2_inode *ip, uint64_t block, -@@ -99,6 +100,7 @@ struct metawalk_fxns pass1_fxns = { - .check_dentry = NULL, - .check_eattr_entry = check_eattr_entries, - .check_eattr_extentry = check_extended_leaf_eattr, -+ .check_i_goal = NULL, - .finish_eattr_indir = finish_eattr_indir, - .big_file_msg = big_file_comfort, - .repair_leaf = pass1_repair_leaf, -@@ -792,6 +794,48 @@ static int check_extended_leaf_eattr(struct gfs2_inode *ip, uint64_t *data_ptr, - return error; - } - -+/** -+ * check_i_goal -+ * @ip -+ * @goal_blk: What the goal block should be for this inode -+ * -+ * The goal block for a regular file is typically the last -+ * data block of the file. If we can't get the right value, -+ * the inode metadata block is the next best thing. -+ * -+ * Returns: 0 if corrected, 1 if not corrected -+ */ -+static int check_i_goal(struct gfs2_inode *ip, uint64_t goal_blk, -+ void *private) -+{ -+ struct gfs2_sbd *sdp = ip->i_sbd; -+ -+ if (fsck_system_inode(sdp, ip->i_di.di_num.no_addr)) -+ return 0; -+ if (!goal_blk) -+ goal_blk = ip->i_di.di_num.no_addr; -+ if (ip->i_di.di_goal_meta != goal_blk || -+ ip->i_di.di_goal_data != goal_blk) { -+ log_err( _("Error: inode %llu (0x%llx) has invalid " -+ "allocation goal block %llu (0x%llx). Should" -+ " be %llu (0x%llx)\n"), -+ (unsigned long long)ip->i_di.di_num.no_addr, -+ (unsigned long long)ip->i_di.di_num.no_addr, -+ (unsigned long long)ip->i_di.di_goal_meta, -+ (unsigned long long)ip->i_di.di_goal_meta, -+ (unsigned long long)goal_blk, -+ (unsigned long long)goal_blk); -+ if (query( _("Fix the invalid goal block? (y/n) "))) { -+ ip->i_di.di_goal_meta = ip->i_di.di_goal_data = goal_blk; -+ bmodified(ip->i_bh); -+ } else { -+ log_err(_("Invalid goal block not fixed.\n")); -+ return 1; -+ } -+ } -+ return 0; -+} -+ - static int check_eattr_leaf(struct gfs2_inode *ip, uint64_t block, - uint64_t parent, struct gfs2_buffer_head **bh, - void *private) -@@ -1624,6 +1668,9 @@ int pass1(struct gfs2_sbd *sdp) - /* Make sure the system inodes are okay & represented in the bitmap. */ - check_system_inodes(sdp); - -+ /* Turn the check_i_goal function ON for the non-system inodes */ -+ pass1_fxns.check_i_goal = check_i_goal; -+ - /* So, do we do a depth first search starting at the root - * inode, or use the rg bitmaps, or just read every fs block - * to find the inodes? If we use the depth first search, why diff --git a/SOURCES/bz1178604-2-gfs2_convert_use_correct_i_goal_values_instead_of_zeros_for_inodes.patch b/SOURCES/bz1178604-2-gfs2_convert_use_correct_i_goal_values_instead_of_zeros_for_inodes.patch deleted file mode 100644 index 1e1ad7e..0000000 --- a/SOURCES/bz1178604-2-gfs2_convert_use_correct_i_goal_values_instead_of_zeros_for_inodes.patch +++ /dev/null @@ -1,56 +0,0 @@ -commit d79246d702623124595a008c732133e32cacba8e -Author: Abhi Das -Date: Mon Dec 8 18:21:47 2014 -0600 - - gfs2_convert: use correct i_goal values instead of zeros for inodes - - This patch sets the inode i_goal_data and i_goal_meta values to the - last allocated block for that inode instead of setting it to zero - as it did before. - - Resolves: rhbz#1149516 - Signed-off-by: Abhi Das - -diff --git a/gfs2/convert/gfs2_convert.c b/gfs2/convert/gfs2_convert.c -index 19a9839..0b56dd1 100644 ---- a/gfs2/convert/gfs2_convert.c -+++ b/gfs2/convert/gfs2_convert.c -@@ -618,8 +618,10 @@ static int fix_ind_reg_or_dir(struct gfs2_sbd *sbp, struct gfs2_inode *ip, uint3 - mp_gfs1_to_gfs2(sbp, di_height, gfs2_hgt, &blk->mp, &gfs2mp); - memcpy(&blk->mp, &gfs2mp, sizeof(struct metapath)); - blk->height -= di_height - gfs2_hgt; -- if (len) -+ if (len) { - fix_metatree(sbp, ip, blk, ptr1, len); -+ ip->i_di.di_goal_data = ip->i_di.di_goal_meta = be64_to_cpu(*ptr2); -+ } - - return 0; - } -@@ -903,7 +905,7 @@ static int adjust_inode(struct gfs2_sbd *sbp, struct gfs2_buffer_head *bh) - inode->i_di.di_mode |= S_IFSOCK; - break; - } -- -+ - /* ----------------------------------------------------------- */ - /* gfs2 inodes are slightly different from gfs1 inodes in that */ - /* di_goal_meta has shifted locations and di_goal_data has */ -@@ -929,7 +931,7 @@ static int adjust_inode(struct gfs2_sbd *sbp, struct gfs2_buffer_head *bh) - inode->i_di.di_goal_data = 0; /* make sure the upper 32b are 0 */ - inode->i_di.di_goal_data = gfs1_dinode_struct->di_goal_dblk; - inode->i_di.di_generation = 0; -- -+ - if (adjust_indirect_blocks(sbp, inode)) - return -1; - /* Check for cdpns */ -@@ -945,7 +947,7 @@ static int adjust_inode(struct gfs2_sbd *sbp, struct gfs2_buffer_head *bh) - return -1; - } - } -- -+ - bmodified(inode->i_bh); - inode_put(&inode); /* does gfs2_dinode_out if modified */ - sbp->md.next_inum++; /* update inode count */ diff --git a/SOURCES/bz1178604-3-tests_test_for_incorrect_inode_i_goal_values.patch b/SOURCES/bz1178604-3-tests_test_for_incorrect_inode_i_goal_values.patch deleted file mode 100644 index ec90c01..0000000 --- a/SOURCES/bz1178604-3-tests_test_for_incorrect_inode_i_goal_values.patch +++ /dev/null @@ -1,24 +0,0 @@ -commit c5b09c4f957d9690807610c8b5e789a280132d2e -Author: Abhi Das -Date: Tue Dec 23 12:51:27 2014 -0600 - - tests: test for incorrect inode i_goal values - - Test corresponds to the bug 1149516 - - Resolves: rhbz#1149516 - Signed-off-by: Abhi Das - -diff --git a/tests/fsck.at b/tests/fsck.at -index d7a8357..afe26db 100644 ---- a/tests/fsck.at -+++ b/tests/fsck.at -@@ -8,3 +8,8 @@ GFS_LANG_CHECK([mkfs.gfs2 -O -p lock_nolock $GFS_TGT], [set sb { sb_bsize: 513 } - GFS_LANG_CHECK([mkfs.gfs2 -O -p lock_nolock $GFS_TGT], [set sb { sb_bsize: 4095 }]) - GFS_LANG_CHECK([mkfs.gfs2 -O -p lock_nolock $GFS_TGT], [set sb { sb_bsize: 4097 }]) - AT_CLEANUP -+ -+AT_SETUP([Fix invalid goal blocks]) -+GFS_LANG_CHECK([mkfs.gfs2 -O -p lock_nolock $GFS_TGT], [set '/' { di_goal_meta: 0 }]) -+GFS_LANG_CHECK([mkfs.gfs2 -O -p lock_nolock $GFS_TGT], [set '/' { di_goal_data: 0 }]) -+AT_CLEANUP diff --git a/SOURCES/bz1178604-4-fsck_gfs2_Reprocess_nodes_if_anything_changed_addendum_1_of_2.patch b/SOURCES/bz1178604-4-fsck_gfs2_Reprocess_nodes_if_anything_changed_addendum_1_of_2.patch deleted file mode 100644 index 969787d..0000000 --- a/SOURCES/bz1178604-4-fsck_gfs2_Reprocess_nodes_if_anything_changed_addendum_1_of_2.patch +++ /dev/null @@ -1,314 +0,0 @@ -commit 5eccbb33c28604436d38f4148fbb651151af1aef -Author: Bob Peterson -Date: Wed Jan 14 10:54:28 2015 -0600 - - fsck.gfs2: Reprocess nodes if anything changed - addendum 1 of 2 - - Before this patch, fsck.gfs2 called "reprocess_inode" in several - places, especially when the number of blocks had changed from the - original. That works in almost all cases. However, there's a corner - case where a block may be deleted, due to errors (for example, a - bad directory leaf), and another block takes its place. In that - case the count of the number of blocks is still the same, but the - inode should be reprocessed anyway, because the deleted blocks - and replacement blocks may be at different locations or maybe of - different types. A hash table block may be "data" when it's freed, - but if the block is reused, it may be repurposed as a "leaf" block. - That may confuse subsequent processing. Another reason to call - reprocess_inode is when the goal block changes to a value outside - the resource group, due to block allocations for repairs. - - This patch is part 1 of 2 addendum fixes to make fsck fix i_goal - values correctly. The original three patches to fix this problem were - checked in against a wrong bz 1149516 (which is the rhel6 version - of the bug). The complete fix contains those three patches (b09dae8, - d79246d, c5b09c4) and this two-patch addendum for a total of 5 - patches. - - Resolves: rhbz#1178604 - Signed-off-by: Bob Peterson - -diff --git a/gfs2/fsck/lost_n_found.c b/gfs2/fsck/lost_n_found.c -index 9672c7a..b2e35e2 100644 ---- a/gfs2/fsck/lost_n_found.c -+++ b/gfs2/fsck/lost_n_found.c -@@ -174,7 +174,6 @@ void make_sure_lf_exists(struct gfs2_inode *ip) - int add_inode_to_lf(struct gfs2_inode *ip){ - char tmp_name[256]; - __be32 inode_type; -- uint64_t lf_blocks; - struct gfs2_sbd *sdp = ip->i_sbd; - int err = 0; - uint32_t mode; -@@ -184,7 +183,6 @@ int add_inode_to_lf(struct gfs2_inode *ip){ - log_err( _("Trying to add lost+found to itself...skipping")); - return 0; - } -- lf_blocks = lf_dip->i_di.di_blocks; - - if (sdp->gfs1) - mode = gfs_to_gfs2_mode(ip); -@@ -242,10 +240,6 @@ int add_inode_to_lf(struct gfs2_inode *ip){ - tmp_name, strerror(errno)); - exit(FSCK_ERROR); - } -- /* If the lf directory had new blocks added we have to mark them -- properly in the bitmap so they're not freed. */ -- if (lf_dip->i_di.di_blocks != lf_blocks) -- reprocess_inode(lf_dip, "lost+found"); - - /* This inode is linked from lost+found */ - incr_link_count(ip->i_di.di_num, lf_dip, _("from lost+found")); -diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c -index 9aa9fb8..82abb40 100644 ---- a/gfs2/fsck/metawalk.c -+++ b/gfs2/fsck/metawalk.c -@@ -1639,11 +1639,11 @@ int check_dir(struct gfs2_sbd *sdp, uint64_t block, struct metawalk_fxns *pass) - { - struct gfs2_inode *ip; - int error = 0; -- uint64_t cur_blks; -+ struct alloc_state as; - - ip = fsck_load_inode(sdp, block); - -- cur_blks = ip->i_di.di_blocks; -+ astate_save(ip, &as); - - if (ip->i_di.di_flags & GFS2_DIF_EXHASH) - error = check_leaf_blks(ip, pass); -@@ -1653,7 +1653,7 @@ int check_dir(struct gfs2_sbd *sdp, uint64_t block, struct metawalk_fxns *pass) - if (error < 0) - stack; - -- if (ip->i_di.di_blocks != cur_blks) -+ if (astate_changed(ip, &as)) - reprocess_inode(ip, _("Current")); - - fsck_inode_put(&ip); /* does a brelse */ -diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c -index 2971b8c..40c80b9 100644 ---- a/gfs2/fsck/pass2.c -+++ b/gfs2/fsck/pass2.c -@@ -1712,7 +1712,8 @@ build_it: - static int check_system_dir(struct gfs2_inode *sysinode, const char *dirname, - int builder(struct gfs2_sbd *sdp)) - { -- uint64_t iblock = 0, cur_blks; -+ uint64_t iblock = 0; -+ struct alloc_state as; - struct dir_status ds = {0}; - int error = 0; - -@@ -1729,14 +1730,14 @@ static int check_system_dir(struct gfs2_inode *sysinode, const char *dirname, - - pass2_fxns.private = (void *) &ds; - if (ds.q == gfs2_bad_block) { -- cur_blks = sysinode->i_di.di_blocks; -+ astate_save(sysinode, &as); - /* First check that the directory's metatree is valid */ - error = check_metatree(sysinode, &pass2_fxns); - if (error < 0) { - stack; - return error; - } -- if (sysinode->i_di.di_blocks != cur_blks) -+ if (astate_changed(sysinode, &as)) - reprocess_inode(sysinode, _("System inode")); - } - error = check_dir(sysinode->i_sbd, iblock, &pass2_fxns); -@@ -1757,7 +1758,7 @@ static int check_system_dir(struct gfs2_inode *sysinode, const char *dirname, - if (!ds.dotdir) { - log_err( _("No '.' entry found for %s directory.\n"), dirname); - if (query( _("Is it okay to add '.' entry? (y/n) "))) { -- cur_blks = sysinode->i_di.di_blocks; -+ astate_save(sysinode, &as); - log_warn( _("Adding '.' entry\n")); - error = dir_add(sysinode, ".", 1, &(sysinode->i_di.di_num), - (sysinode->i_sbd->gfs1 ? GFS_FILE_DIR : DT_DIR)); -@@ -1766,7 +1767,7 @@ static int check_system_dir(struct gfs2_inode *sysinode, const char *dirname, - strerror(errno)); - return -errno; - } -- if (cur_blks != sysinode->i_di.di_blocks) -+ if (astate_changed(sysinode, &as)) - reprocess_inode(sysinode, dirname); - /* This system inode is linked to itself via '.' */ - incr_link_count(sysinode->i_di.di_num, sysinode, -@@ -1848,7 +1849,8 @@ static inline int is_system_dir(struct gfs2_sbd *sdp, uint64_t block) - */ - int pass2(struct gfs2_sbd *sdp) - { -- uint64_t dirblk, cur_blks; -+ uint64_t dirblk; -+ struct alloc_state as; - uint8_t q; - struct dir_status ds = {0}; - struct gfs2_inode *ip; -@@ -1915,14 +1917,14 @@ int pass2(struct gfs2_sbd *sdp) - /* First check that the directory's metatree - * is valid */ - ip = fsck_load_inode(sdp, dirblk); -- cur_blks = ip->i_di.di_blocks; -+ astate_save(ip, &as); - error = check_metatree(ip, &pass2_fxns); - fsck_inode_put(&ip); - if (error < 0) { - stack; - return error; - } -- if (ip->i_di.di_blocks != cur_blks) -+ if (astate_changed(ip, &as)) - reprocess_inode(ip, "current"); - } - error = check_dir(sdp, dirblk, &pass2_fxns); -@@ -1982,7 +1984,7 @@ int pass2(struct gfs2_sbd *sdp) - (unsigned long long)dirblk); - - if (query( _("Is it okay to add '.' entry? (y/n) "))) { -- cur_blks = ip->i_di.di_blocks; -+ astate_save(ip, &as); - error = dir_add(ip, ".", 1, &(ip->i_di.di_num), - (sdp->gfs1 ? GFS_FILE_DIR : DT_DIR)); - if (error) { -@@ -1990,7 +1992,7 @@ int pass2(struct gfs2_sbd *sdp) - strerror(errno)); - return -errno; - } -- if (cur_blks != ip->i_di.di_blocks) { -+ if (astate_changed(ip, &as)) { - char dirname[80]; - - sprintf(dirname, _("Directory at %lld " -diff --git a/gfs2/fsck/pass3.c b/gfs2/fsck/pass3.c -index 9582b5b..167dac0 100644 ---- a/gfs2/fsck/pass3.c -+++ b/gfs2/fsck/pass3.c -@@ -24,7 +24,7 @@ static int attach_dotdot_to(struct gfs2_sbd *sdp, uint64_t newdotdot, - int filename_len = 2; - int err; - struct gfs2_inode *ip, *pip; -- uint64_t cur_blks; -+ struct alloc_state as; - - ip = fsck_load_inode(sdp, block); - pip = fsck_load_inode(sdp, newdotdot); -@@ -39,7 +39,7 @@ static int attach_dotdot_to(struct gfs2_sbd *sdp, uint64_t newdotdot, - log_warn( _("Unable to remove \"..\" directory entry.\n")); - else - decr_link_count(olddotdot, block, _("old \"..\"")); -- cur_blks = ip->i_di.di_blocks; -+ astate_save(ip, &as); - err = dir_add(ip, filename, filename_len, &pip->i_di.di_num, - (sdp->gfs1 ? GFS_FILE_DIR : DT_DIR)); - if (err) { -@@ -47,7 +47,7 @@ static int attach_dotdot_to(struct gfs2_sbd *sdp, uint64_t newdotdot, - filename, strerror(errno)); - exit(FSCK_ERROR); - } -- if (cur_blks != ip->i_di.di_blocks) { -+ if (astate_changed(ip, &as)) { - char dirname[80]; - - sprintf(dirname, _("Directory at %lld (0x%llx)"), -@@ -179,6 +179,7 @@ int pass3(struct gfs2_sbd *sdp) - struct dir_info *di, *tdi; - struct gfs2_inode *ip; - uint8_t q; -+ struct alloc_state lf_as = {.as_blocks = 0, .as_meta_goal = 0}; - - di = dirtree_find(sdp->md.rooti->i_di.di_num.no_addr); - if (di) { -@@ -225,6 +226,8 @@ int pass3(struct gfs2_sbd *sdp) - */ - log_info( _("Checking directory linkage.\n")); - for (tmp = osi_first(&dirtree); tmp; tmp = next) { -+ if (lf_dip && lf_as.as_blocks == 0) -+ astate_save(lf_dip, &lf_as); - next = osi_next(tmp); - di = (struct dir_info *)tmp; - while (!di->checked) { -@@ -327,8 +330,14 @@ int pass3(struct gfs2_sbd *sdp) - break; - } - } -- if (lf_dip) -+ if (lf_dip) { -+ /* If the lf directory had new blocks added we have to mark -+ them properly in the blockmap so they're not freed. */ -+ if (astate_changed(lf_dip, &lf_as)) -+ reprocess_inode(lf_dip, "lost+found"); -+ - log_debug( _("At end of pass3, lost+found entries is %u\n"), - lf_dip->i_di.di_entries); -+ } - return FSCK_OK; - } -diff --git a/gfs2/fsck/pass4.c b/gfs2/fsck/pass4.c -index 7b3cb87..f0c13fc 100644 ---- a/gfs2/fsck/pass4.c -+++ b/gfs2/fsck/pass4.c -@@ -48,12 +48,15 @@ static int scan_inode_list(struct gfs2_sbd *sdp) { - struct gfs2_inode *ip; - int lf_addition = 0; - uint8_t q; -+ struct alloc_state lf_as = {.as_blocks = 0, .as_meta_goal = 0}; - - /* FIXME: should probably factor this out into a generic - * scanning fxn */ - for (tmp = osi_first(&inodetree); tmp; tmp = next) { - if (skip_this_pass || fsck_abort) /* if asked to skip the rest */ - return 0; -+ if (lf_dip && lf_as.as_blocks == 0) -+ astate_save(lf_dip, &lf_as); - next = osi_next(tmp); - if (!(ii = (struct inode_info *)tmp)) { - log_crit( _("osi_tree broken in scan_info_list!!\n")); -@@ -182,6 +185,9 @@ static int scan_inode_list(struct gfs2_sbd *sdp) { - (unsigned long long)ii->di_num.no_addr, ii->di_nlink); - } /* osi_list_foreach(tmp, list) */ - -+ if (lf_dip && astate_changed(lf_dip, &lf_as)) -+ reprocess_inode(lf_dip, "lost+found"); -+ - if (lf_addition) { - if (!(ii = inodetree_find(lf_dip->i_di.di_num.no_addr))) { - log_crit( _("Unable to find lost+found inode in inode_hash!!\n")); -diff --git a/gfs2/fsck/util.h b/gfs2/fsck/util.h -index 276c726..66b9c7a 100644 ---- a/gfs2/fsck/util.h -+++ b/gfs2/fsck/util.h -@@ -12,6 +12,11 @@ - #define INODE_VALID 1 - #define INODE_INVALID 0 - -+struct alloc_state { -+ uint64_t as_blocks; -+ uint64_t as_meta_goal; -+}; -+ - struct di_info *search_list(osi_list_t *list, uint64_t addr); - void big_file_comfort(struct gfs2_inode *ip, uint64_t blks_checked); - void warm_fuzzy_stuff(uint64_t block); -@@ -27,6 +32,21 @@ extern const char *reftypes[ref_types + 1]; - #define BLOCKMAP_BYTE_OFFSET4(x) (((x) & 0x0000000000000001) << 2) - #define BLOCKMAP_MASK4 (0xf) - -+static inline void astate_save(struct gfs2_inode *ip, struct alloc_state *as) -+{ -+ as->as_blocks = ip->i_di.di_blocks; -+ as->as_meta_goal = ip->i_di.di_goal_meta; -+} -+ -+static inline int astate_changed(struct gfs2_inode *ip, struct alloc_state *as) -+{ -+ if (as->as_blocks != ip->i_di.di_blocks) -+ return 1; -+ if (as->as_meta_goal != ip->i_di.di_goal_meta) -+ return 1; -+ return 0; -+} -+ - static inline uint8_t block_type(uint64_t bblock) - { - static unsigned char *byte; diff --git a/SOURCES/bz1178604-5-fsck_gfs2_addendum_to_fix_broken_i_goal_values_in_inodes_addendum_2_of_2.patch b/SOURCES/bz1178604-5-fsck_gfs2_addendum_to_fix_broken_i_goal_values_in_inodes_addendum_2_of_2.patch deleted file mode 100644 index eb58328..0000000 --- a/SOURCES/bz1178604-5-fsck_gfs2_addendum_to_fix_broken_i_goal_values_in_inodes_addendum_2_of_2.patch +++ /dev/null @@ -1,258 +0,0 @@ -commit 6d89e9dfe83f68ebb05bfb2ef4715cc5fb1aa630 -Author: Abhi Das -Date: Thu Jan 15 12:49:48 2015 -0600 - - fsck.gfs2: addendum to fix broken i_goal values in inodes - addendum 2 of 2 - - This patch moves some code around and fixes some corner cases that - the previous patches did not address. - This patch also fixes some trailing whitespace and removes a test - that is no longer valid from test/fsck.at - - This patch is part 2 of 2 addendum fixes to make fsck fix i_goal - values correctly. The original three patches to fix this problem were - checked in against a wrong bz 1149516 (which is the rhel6 version - of the bug). The complete fix contains those three patches (b09dae8, - d79246d, c5b09c4) and this two-patch addendum for a total of 5 - patches. - - Resolves: rhbz#1178604 - Signed-off-by: Abhi Das - -diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c -index 82abb40..3460141 100644 ---- a/gfs2/fsck/metawalk.c -+++ b/gfs2/fsck/metawalk.c -@@ -1497,6 +1497,9 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass) - uint64_t error_blk = 0; - int hit_error_blk = 0; - -+ if (!height && pass->check_i_goal) -+ pass->check_i_goal(ip, ip->i_di.di_num.no_addr, -+ pass->private); - if (!height && !is_dir(&ip->i_di, ip->i_sbd->gfs1)) - return 0; - -@@ -1891,6 +1894,72 @@ static int alloc_leaf(struct gfs2_inode *ip, uint64_t block, void *private) - return 0; - } - -+/** -+ * rgrp_contains_block - Check if the rgrp provided contains the -+ * given block. Taken directly from the gfs2 kernel code -+ * @rgd: The rgrp to search within -+ * @block: The block to search for -+ * -+ * Returns: 1 if present, 0 if not. -+ */ -+static inline int rgrp_contains_block(struct rgrp_tree *rgd, uint64_t block) -+{ -+ uint64_t first = rgd->ri.ri_data0; -+ uint64_t last = first + rgd->ri.ri_data; -+ return first <= block && block < last; -+} -+ -+/** -+ * check_i_goal -+ * @ip -+ * @goal_blk: What the goal block should be for this inode -+ * -+ * The goal block for a regular file is typically the last -+ * data block of the file. If we can't get the right value, -+ * the inode metadata block is the next best thing. -+ * -+ * Returns: 0 if corrected, 1 if not corrected -+ */ -+int check_i_goal(struct gfs2_inode *ip, uint64_t goal_blk, -+ void *private) -+{ -+ struct gfs2_sbd *sdp = ip->i_sbd; -+ uint64_t i_block = ip->i_di.di_num.no_addr; -+ -+ /* Don't fix gfs1 inodes, system inodes or inodes whose goal blocks are -+ * set to the inode blocks themselves. */ -+ if (sdp->gfs1 || ip->i_di.di_flags & GFS2_DIF_SYSTEM || -+ ip->i_di.di_goal_meta == i_block) -+ return 0; -+ /* We default to the inode block */ -+ if (!goal_blk) -+ goal_blk = i_block; -+ -+ if (ip->i_di.di_goal_meta != goal_blk) { -+ /* If the existing goal block is in the same rgrp as the inode, -+ * we give the benefit of doubt and assume the value is correct */ -+ if (ip->i_rgd && -+ rgrp_contains_block(ip->i_rgd, ip->i_di.di_goal_meta)) -+ goto skip; -+ log_err( _("Error: inode %llu (0x%llx) has invalid " -+ "allocation goal block %llu (0x%llx). Should" -+ " be %llu (0x%llx)\n"), -+ (unsigned long long)i_block, (unsigned long long)i_block, -+ (unsigned long long)ip->i_di.di_goal_meta, -+ (unsigned long long)ip->i_di.di_goal_meta, -+ (unsigned long long)goal_blk, (unsigned long long)goal_blk); -+ if (query( _("Fix the invalid goal block? (y/n) "))) { -+ ip->i_di.di_goal_meta = ip->i_di.di_goal_data = goal_blk; -+ bmodified(ip->i_bh); -+ } else { -+ log_err(_("Invalid goal block not fixed.\n")); -+ return 1; -+ } -+ } -+skip: -+ return 0; -+} -+ - struct metawalk_fxns alloc_fxns = { - .private = NULL, - .check_leaf = alloc_leaf, -@@ -1901,6 +1970,7 @@ struct metawalk_fxns alloc_fxns = { - .check_dentry = NULL, - .check_eattr_entry = NULL, - .check_eattr_extentry = NULL, -+ .check_i_goal = check_i_goal, - .finish_eattr_indir = NULL, - }; - -diff --git a/gfs2/fsck/metawalk.h b/gfs2/fsck/metawalk.h -index b3c1299..482016a 100644 ---- a/gfs2/fsck/metawalk.h -+++ b/gfs2/fsck/metawalk.h -@@ -51,6 +51,8 @@ extern int _fsck_blockmap_set(struct gfs2_inode *ip, uint64_t bblock, - extern int check_n_fix_bitmap(struct gfs2_sbd *sdp, uint64_t blk, - int error_on_dinode, - enum gfs2_mark_block new_blockmap_state); -+extern int check_i_goal(struct gfs2_inode *ip, uint64_t goal_blk, -+ void *private); - extern void reprocess_inode(struct gfs2_inode *ip, const char *desc); - extern struct duptree *dupfind(uint64_t block); - extern struct gfs2_inode *fsck_system_inode(struct gfs2_sbd *sdp, -diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c -index 60f0356..dbe60bd 100644 ---- a/gfs2/fsck/pass1.c -+++ b/gfs2/fsck/pass1.c -@@ -62,7 +62,6 @@ static int check_extended_leaf_eattr(struct gfs2_inode *ip, uint64_t *data_ptr, - struct gfs2_ea_header *ea_hdr, - struct gfs2_ea_header *ea_hdr_prev, - void *private); --static int check_i_goal(struct gfs2_inode *ip, uint64_t goal_blk, void *private); - static int finish_eattr_indir(struct gfs2_inode *ip, int leaf_pointers, - int leaf_pointer_errors, void *private); - static int invalidate_metadata(struct gfs2_inode *ip, uint64_t block, -@@ -100,7 +99,7 @@ struct metawalk_fxns pass1_fxns = { - .check_dentry = NULL, - .check_eattr_entry = check_eattr_entries, - .check_eattr_extentry = check_extended_leaf_eattr, -- .check_i_goal = NULL, -+ .check_i_goal = check_i_goal, - .finish_eattr_indir = finish_eattr_indir, - .big_file_msg = big_file_comfort, - .repair_leaf = pass1_repair_leaf, -@@ -794,48 +793,6 @@ static int check_extended_leaf_eattr(struct gfs2_inode *ip, uint64_t *data_ptr, - return error; - } - --/** -- * check_i_goal -- * @ip -- * @goal_blk: What the goal block should be for this inode -- * -- * The goal block for a regular file is typically the last -- * data block of the file. If we can't get the right value, -- * the inode metadata block is the next best thing. -- * -- * Returns: 0 if corrected, 1 if not corrected -- */ --static int check_i_goal(struct gfs2_inode *ip, uint64_t goal_blk, -- void *private) --{ -- struct gfs2_sbd *sdp = ip->i_sbd; -- -- if (fsck_system_inode(sdp, ip->i_di.di_num.no_addr)) -- return 0; -- if (!goal_blk) -- goal_blk = ip->i_di.di_num.no_addr; -- if (ip->i_di.di_goal_meta != goal_blk || -- ip->i_di.di_goal_data != goal_blk) { -- log_err( _("Error: inode %llu (0x%llx) has invalid " -- "allocation goal block %llu (0x%llx). Should" -- " be %llu (0x%llx)\n"), -- (unsigned long long)ip->i_di.di_num.no_addr, -- (unsigned long long)ip->i_di.di_num.no_addr, -- (unsigned long long)ip->i_di.di_goal_meta, -- (unsigned long long)ip->i_di.di_goal_meta, -- (unsigned long long)goal_blk, -- (unsigned long long)goal_blk); -- if (query( _("Fix the invalid goal block? (y/n) "))) { -- ip->i_di.di_goal_meta = ip->i_di.di_goal_data = goal_blk; -- bmodified(ip->i_bh); -- } else { -- log_err(_("Invalid goal block not fixed.\n")); -- return 1; -- } -- } -- return 0; --} -- - static int check_eattr_leaf(struct gfs2_inode *ip, uint64_t block, - uint64_t parent, struct gfs2_buffer_head **bh, - void *private) -@@ -1217,7 +1174,8 @@ bad_dinode: - * handle_di - This is now a wrapper function that takes a gfs2_buffer_head - * and calls handle_ip, which takes an in-code dinode structure. - */ --static int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh) -+static int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh, -+ struct rgrp_tree *rgd) - { - int error = 0; - uint64_t block = bh->b_blocknr; -@@ -1259,6 +1217,7 @@ static int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh) - (unsigned long long)block, - (unsigned long long)block); - } -+ ip->i_rgd = rgd; - error = handle_ip(sdp, ip); - fsck_inode_put(&ip); - return error; -@@ -1585,7 +1544,7 @@ static int pass1_process_bitmap(struct gfs2_sbd *sdp, struct rgrp_tree *rgd, uin - (unsigned long long)block, - (unsigned long long)block); - check_n_fix_bitmap(sdp, block, 0, gfs2_block_free); -- } else if (handle_di(sdp, bh) < 0) { -+ } else if (handle_di(sdp, bh, rgd) < 0) { - stack; - brelse(bh); - gfs2_special_free(&gfs1_rindex_blks); -@@ -1668,9 +1627,6 @@ int pass1(struct gfs2_sbd *sdp) - /* Make sure the system inodes are okay & represented in the bitmap. */ - check_system_inodes(sdp); - -- /* Turn the check_i_goal function ON for the non-system inodes */ -- pass1_fxns.check_i_goal = check_i_goal; -- - /* So, do we do a depth first search starting at the root - * inode, or use the rg bitmaps, or just read every fs block - * to find the inodes? If we use the depth first search, why -diff --git a/gfs2/libgfs2/libgfs2.h b/gfs2/libgfs2/libgfs2.h -index 10df2d4..d024e56 100644 ---- a/gfs2/libgfs2/libgfs2.h -+++ b/gfs2/libgfs2/libgfs2.h -@@ -233,6 +233,7 @@ struct gfs2_inode { - struct gfs2_dinode i_di; - struct gfs2_buffer_head *i_bh; - struct gfs2_sbd *i_sbd; -+ struct rgrp_tree *i_rgd; /* The rgrp this inode is in */ - }; - - /* FIXME not sure that i want to keep a record of the inodes or the -diff --git a/tests/fsck.at b/tests/fsck.at -index afe26db..e3b82bd 100644 ---- a/tests/fsck.at -+++ b/tests/fsck.at -@@ -11,5 +11,4 @@ AT_CLEANUP - - AT_SETUP([Fix invalid goal blocks]) - GFS_LANG_CHECK([mkfs.gfs2 -O -p lock_nolock $GFS_TGT], [set '/' { di_goal_meta: 0 }]) --GFS_LANG_CHECK([mkfs.gfs2 -O -p lock_nolock $GFS_TGT], [set '/' { di_goal_data: 0 }]) - AT_CLEANUP diff --git a/SOURCES/bz1186515-fsck_gfs2_replace_recent_i_goal_fixes_with_simple_logic.patch b/SOURCES/bz1186515-fsck_gfs2_replace_recent_i_goal_fixes_with_simple_logic.patch new file mode 100644 index 0000000..2ada585 --- /dev/null +++ b/SOURCES/bz1186515-fsck_gfs2_replace_recent_i_goal_fixes_with_simple_logic.patch @@ -0,0 +1,304 @@ +commit e394013ec812e7fa359344a3b901b8b15b15bc4a +Author: Abhi Das +Date: Tue Apr 14 19:51:55 2015 -0500 + + fsck.gfs2: replace recent i_goal fixes with simple logic + + This patch reverses the recent set of i_goal fixes for fsck.gfs2. + This is because of two problems. + 1. It is not possible to determine if a valid block within the fs + is the correct goal block for a given inode. + 2. Conversely, given an inode, it is also not possible to accurately + determine what its goal block should be. + + The previous patches assumed that the last block of a file is its + goal block, but that is not true if the file is a directory or if + its blocks are not allocated sequentially. fsck.gfs2 would flag + these inodes incorrectly as having bad i_goal values. + + This patch takes a simple approach. It checks if the i_goal of a + given inode is out of bounds of the fs. If so, we can be certain + that it is wrong and we set it to the inode metadata block. This + is a safe starting point for gfs2 to determine where to allocate + from next. + + Resolves: rhbz#1186515 + Signed-off-by: Abhi Das + +diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c +index f05fb51..4d5a660 100644 +--- a/gfs2/fsck/metawalk.c ++++ b/gfs2/fsck/metawalk.c +@@ -1428,8 +1428,7 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp, + */ + static int check_data(struct gfs2_inode *ip, struct metawalk_fxns *pass, + struct gfs2_buffer_head *bh, int head_size, +- uint64_t *last_block, uint64_t *blks_checked, +- uint64_t *error_blk) ++ uint64_t *blks_checked, uint64_t *error_blk) + { + int error = 0, rc = 0; + uint64_t block, *ptr; +@@ -1444,7 +1443,7 @@ static int check_data(struct gfs2_inode *ip, struct metawalk_fxns *pass, + + if (skip_this_pass || fsck_abort) + return error; +- *last_block = block = be64_to_cpu(*ptr); ++ block = be64_to_cpu(*ptr); + /* It's important that we don't call valid_block() and + bypass calling check_data on invalid blocks because that + would defeat the rangecheck_block related functions in +@@ -1548,15 +1547,12 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass) + struct gfs2_buffer_head *bh; + uint32_t height = ip->i_di.di_height; + int i, head_size; +- uint64_t blks_checked = 0, last_block = 0; ++ uint64_t blks_checked = 0; + int error, rc; + int metadata_clean = 0; + uint64_t error_blk = 0; + int hit_error_blk = 0; + +- if (!height && pass->check_i_goal) +- pass->check_i_goal(ip, ip->i_di.di_num.no_addr, +- pass->private); + if (!height && !is_dir(&ip->i_di, ip->i_sbd->gfs1)) + return 0; + +@@ -1575,9 +1571,6 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass) + * comprise the directory hash table, so we perform the directory + * checks and exit. */ + if (is_dir(&ip->i_di, ip->i_sbd->gfs1)) { +- last_block = ip->i_di.di_num.no_addr; +- if (pass->check_i_goal) +- pass->check_i_goal(ip, last_block, pass->private); + if (!(ip->i_di.di_flags & GFS2_DIF_EXHASH)) + goto out; + /* check validity of leaf blocks and leaf chains */ +@@ -1604,7 +1597,7 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass) + + if (pass->check_data) + error = check_data(ip, pass, bh, head_size, +- &last_block, &blks_checked, &error_blk); ++ &blks_checked, &error_blk); + if (pass->big_file_msg && ip->i_di.di_blocks > COMFORTABLE_BLKS) + pass->big_file_msg(ip, blks_checked); + } +@@ -1616,8 +1609,6 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass) + (unsigned long long)ip->i_di.di_num.no_addr); + fflush(stdout); + } +- if (!error && pass->check_i_goal) +- pass->check_i_goal(ip, last_block, pass->private); + undo_metalist: + if (!error) + goto out; +@@ -1958,80 +1949,6 @@ static int alloc_leaf(struct gfs2_inode *ip, uint64_t block, void *private) + return 0; + } + +-/** +- * rgrp_contains_block - Check if the rgrp provided contains the +- * given block. Taken directly from the gfs2 kernel code +- * @rgd: The rgrp to search within +- * @block: The block to search for +- * +- * Returns: 1 if present, 0 if not. +- */ +-static inline int rgrp_contains_block(struct rgrp_tree *rgd, uint64_t block) +-{ +- uint64_t first = rgd->ri.ri_data0; +- uint64_t last = first + rgd->ri.ri_data; +- return first <= block && block < last; +-} +- +-/** +- * check_i_goal +- * @ip +- * @goal_blk: What the goal block should be for this inode +- * +- * The goal block for a regular file is typically the last +- * data block of the file. If we can't get the right value, +- * the inode metadata block is the next best thing. +- * +- * Returns: 0 if corrected, 1 if not corrected +- */ +-int check_i_goal(struct gfs2_inode *ip, uint64_t goal_blk, +- void *private) +-{ +- struct gfs2_sbd *sdp = ip->i_sbd; +- uint64_t i_block = ip->i_di.di_num.no_addr; +- +- /* Don't fix gfs1 inodes, system inodes or inodes whose goal blocks are +- * set to the inode blocks themselves. */ +- if (sdp->gfs1 || ip->i_di.di_flags & GFS2_DIF_SYSTEM || +- ip->i_di.di_goal_meta == i_block) +- return 0; +- /* Don't fix directory goal blocks unless we know they're wrong. +- * i.e. out of bounds of the fs. Directories can easily have blocks +- * outside of the dinode's rgrp and thus we have no way of knowing +- * if the goal block is bogus or not. */ +- if (is_dir(&ip->i_di, ip->i_sbd->gfs1) && +- (ip->i_di.di_goal_meta > sdp->sb_addr && +- ip->i_di.di_goal_meta <= sdp->fssize)) +- return 0; +- /* We default to the inode block */ +- if (!goal_blk) +- goal_blk = i_block; +- +- if (ip->i_di.di_goal_meta != goal_blk) { +- /* If the existing goal block is in the same rgrp as the inode, +- * we give the benefit of doubt and assume the value is correct */ +- if (ip->i_rgd && +- rgrp_contains_block(ip->i_rgd, ip->i_di.di_goal_meta)) +- goto skip; +- log_err( _("Error: inode %llu (0x%llx) has invalid " +- "allocation goal block %llu (0x%llx). Should" +- " be %llu (0x%llx)\n"), +- (unsigned long long)i_block, (unsigned long long)i_block, +- (unsigned long long)ip->i_di.di_goal_meta, +- (unsigned long long)ip->i_di.di_goal_meta, +- (unsigned long long)goal_blk, (unsigned long long)goal_blk); +- if (query( _("Fix the invalid goal block? (y/n) "))) { +- ip->i_di.di_goal_meta = ip->i_di.di_goal_data = goal_blk; +- bmodified(ip->i_bh); +- } else { +- log_err(_("Invalid goal block not fixed.\n")); +- return 1; +- } +- } +-skip: +- return 0; +-} +- + struct metawalk_fxns alloc_fxns = { + .private = NULL, + .check_leaf = alloc_leaf, +@@ -2042,7 +1959,6 @@ struct metawalk_fxns alloc_fxns = { + .check_dentry = NULL, + .check_eattr_entry = NULL, + .check_eattr_extentry = NULL, +- .check_i_goal = check_i_goal, + .finish_eattr_indir = NULL, + }; + +diff --git a/gfs2/fsck/metawalk.h b/gfs2/fsck/metawalk.h +index 779360e..fa4c850 100644 +--- a/gfs2/fsck/metawalk.h ++++ b/gfs2/fsck/metawalk.h +@@ -50,8 +50,6 @@ extern int _fsck_blockmap_set(struct gfs2_inode *ip, uint64_t bblock, + const char *caller, int line); + extern int check_n_fix_bitmap(struct gfs2_sbd *sdp, uint64_t blk, + int error_on_dinode, int new_blockmap_state); +-extern int check_i_goal(struct gfs2_inode *ip, uint64_t goal_blk, +- void *private); + extern void reprocess_inode(struct gfs2_inode *ip, const char *desc); + extern struct duptree *dupfind(uint64_t block); + extern struct gfs2_inode *fsck_system_inode(struct gfs2_sbd *sdp, +@@ -91,7 +89,6 @@ enum meta_check_rc { + * check_dentry: + * check_eattr_entry: + * check_eattr_extentry: +- * check_i_goal: + */ + struct metawalk_fxns { + void *private; +@@ -143,8 +140,6 @@ struct metawalk_fxns { + struct gfs2_ea_header *ea_hdr, + struct gfs2_ea_header *ea_hdr_prev, + void *private); +- int (*check_i_goal) (struct gfs2_inode *ip, uint64_t goal_blk, +- void *private); + int (*finish_eattr_indir) (struct gfs2_inode *ip, int leaf_pointers, + int leaf_pointer_errors, void *private); + void (*big_file_msg) (struct gfs2_inode *ip, uint64_t blks_checked); +diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c +index 69c88f4..0909873 100644 +--- a/gfs2/fsck/pass1.c ++++ b/gfs2/fsck/pass1.c +@@ -100,7 +100,6 @@ struct metawalk_fxns pass1_fxns = { + .check_dentry = NULL, + .check_eattr_entry = check_eattr_entries, + .check_eattr_extentry = check_extended_leaf_eattr, +- .check_i_goal = check_i_goal, + .finish_eattr_indir = finish_eattr_indir, + .big_file_msg = big_file_comfort, + .repair_leaf = pass1_repair_leaf, +@@ -1205,12 +1204,37 @@ bad_dinode: + return -1; + } + ++static void check_i_goal(struct gfs2_sbd *sdp, struct gfs2_inode *ip) ++{ ++ if (sdp->gfs1 || ip->i_di.di_flags & GFS2_DIF_SYSTEM) ++ return; ++ ++ if (ip->i_di.di_goal_meta <= sdp->sb_addr || ++ ip->i_di.di_goal_meta > sdp->fssize) { ++ log_err(_("Inode #%llu (0x%llx): Bad allocation goal block " ++ "found: %llu (0x%llx)\n"), ++ (unsigned long long)ip->i_di.di_num.no_addr, ++ (unsigned long long)ip->i_di.di_num.no_addr, ++ (unsigned long long)ip->i_di.di_goal_meta, ++ (unsigned long long)ip->i_di.di_goal_meta); ++ if (query( _("Fix goal block in inode #%llu (0x%llx)? (y/n) "), ++ (unsigned long long)ip->i_di.di_num.no_addr, ++ (unsigned long long)ip->i_di.di_num.no_addr)) { ++ ip->i_di.di_goal_meta = ip->i_di.di_num.no_addr; ++ bmodified(ip->i_bh); ++ } else ++ log_err(_("Allocation goal block in inode #%lld " ++ "(0x%llx) not fixed\n"), ++ (unsigned long long)ip->i_di.di_num.no_addr, ++ (unsigned long long)ip->i_di.di_num.no_addr); ++ } ++} ++ + /* + * handle_di - This is now a wrapper function that takes a gfs2_buffer_head + * and calls handle_ip, which takes an in-code dinode structure. + */ +-static int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh, +- struct rgrp_tree *rgd) ++static int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh) + { + int error = 0; + uint64_t block = bh->b_blocknr; +@@ -1252,7 +1276,7 @@ static int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh, + (unsigned long long)block, + (unsigned long long)block); + } +- ip->i_rgd = rgd; ++ check_i_goal(sdp, ip); + error = handle_ip(sdp, ip); + fsck_inode_put(&ip); + return error; +@@ -1378,6 +1402,7 @@ static int check_system_inode(struct gfs2_sbd *sdp, + "directory entries.\n"), filename); + } + } ++ check_i_goal(sdp, *sysinode); + error = handle_ip(sdp, *sysinode); + return error ? error : err; + } +@@ -1602,7 +1627,7 @@ static int pass1_process_bitmap(struct gfs2_sbd *sdp, struct rgrp_tree *rgd, uin + (unsigned long long)block, + (unsigned long long)block); + check_n_fix_bitmap(sdp, block, 0, GFS2_BLKST_FREE); +- } else if (handle_di(sdp, bh, rgd) < 0) { ++ } else if (handle_di(sdp, bh) < 0) { + stack; + brelse(bh); + gfs2_special_free(&gfs1_rindex_blks); +diff --git a/gfs2/libgfs2/libgfs2.h b/gfs2/libgfs2/libgfs2.h +index f1f81d3..ccae721 100644 +--- a/gfs2/libgfs2/libgfs2.h ++++ b/gfs2/libgfs2/libgfs2.h +@@ -233,7 +233,6 @@ struct gfs2_inode { + struct gfs2_dinode i_di; + struct gfs2_buffer_head *i_bh; + struct gfs2_sbd *i_sbd; +- struct rgrp_tree *i_rgd; /* The rgrp this inode is in */ + }; + + struct master_dir diff --git a/SOURCES/bz1202831-mkfs_gfs2_Allow_longer_cluster_names.patch b/SOURCES/bz1202831-mkfs_gfs2_Allow_longer_cluster_names.patch new file mode 100644 index 0000000..40c8e2d --- /dev/null +++ b/SOURCES/bz1202831-mkfs_gfs2_Allow_longer_cluster_names.patch @@ -0,0 +1,87 @@ +commit a523af584645a01bb4900b10d0c9232d0ae50339 +Author: Paul Evans +Date: Wed Apr 22 17:43:26 2015 +0100 + + mkfs.gfs2: Allow longer cluster names + + Increase the enforced limit for cluster name to 32 bytes and file + system name to 30 bytes for mkfs.gfs2 (was previously 16 + 16 + bytes). + + Also increased this limit in tunegfs2 when labelling gfs2 file + systems. + + Updated the formation in the man pages along with adding a new test + case for mkfs.gfs2 to validate the increased cluster/file system + name support. + + Resolves: rhbz#1202831 + Signed-off-by: Paul Evans + +diff --git a/gfs2/man/mkfs.gfs2.8 b/gfs2/man/mkfs.gfs2.8 +index ceb6f38..f480082 100644 +--- a/gfs2/man/mkfs.gfs2.8 ++++ b/gfs2/man/mkfs.gfs2.8 +@@ -101,9 +101,9 @@ bigger file systems will have bigger RGs for better performance. + The lock table field appropriate to the lock module you're using. + It is \fIclustername:fsname\fR. + Clustername must match that in cluster.conf; only members of this +-cluster are permitted to use this file system. ++cluster are permitted to use this file system (1 to 32 characters). + Fsname is a unique file system name used to distinguish this GFS2 file +-system from others created (1 to 16 characters). Lock_nolock doesn't ++system from others created (1 to 30 characters). Lock_nolock doesn't + use this field. Valid \fIclustername\fRs and \fIfsname\fRs may only contain + alphanumeric characters, hyphens (-) and underscores (_). + .TP +diff --git a/gfs2/mkfs/main_mkfs.c b/gfs2/mkfs/main_mkfs.c +index 0636f0b..3fab08c 100644 +--- a/gfs2/mkfs/main_mkfs.c ++++ b/gfs2/mkfs/main_mkfs.c +@@ -398,7 +398,7 @@ static void test_locking(const char *lockproto, const char *locktable) + + if (c == locktable) + die("%s %s\n", errprefix, _("cluster name is missing")); +- if (c - locktable > 16) ++ if (c - locktable > 32) + die("%s %s\n", errprefix, _("cluster name is too long")); + + c++; +@@ -406,7 +406,7 @@ static void test_locking(const char *lockproto, const char *locktable) + die("%s %s\n", errprefix, _("contains more than one colon")); + if (!strlen(c)) + die("%s %s\n", errprefix, _("file system name is missing")); +- if (strlen(c) > 16) ++ if (strlen(c) > 30) + die("%s %s\n", errprefix, _("file system name is too long")); + } else { + die( _("Invalid lock protocol: %s\n"), lockproto); +diff --git a/gfs2/tune/super.c b/gfs2/tune/super.c +index cbd0026..560ce68 100644 +--- a/gfs2/tune/super.c ++++ b/gfs2/tune/super.c +@@ -194,7 +194,7 @@ int change_locktable(struct tunegfs2 *tfs, const char *locktable) + fprintf(stderr, "%s %s\n", errpre, _("missing colon")); + return EX_DATAERR; + } +- if (strlen(++fsname) > 16) { ++ if (strlen(++fsname) > 30) { + fprintf(stderr, "%s %s\n", errpre, _("file system name is too long")); + return EX_DATAERR; + } +diff --git a/tests/mkfs.at b/tests/mkfs.at +index 438184c..e25b6dc 100644 +--- a/tests/mkfs.at ++++ b/tests/mkfs.at +@@ -89,3 +89,11 @@ AT_SETUP([Min. quota change file size]) + AT_KEYWORDS(mkfs.gfs2 mkfs) + GFS_FSCK_CHECK([$GFS_MKFS -p lock_nolock -c 1 $GFS_TGT]) + AT_CLEANUP ++ ++AT_SETUP([Incr. cluster/file system name validation]) ++AT_KEYWORDS(mkfs.gfs2 mkfs) ++AT_CHECK([$GFS_MKFS -p lock_dlm -t "" $GFS_TGT], 255, [ignore], [ignore]) ++AT_CHECK([$GFS_MKFS -p lock_dlm -t "quite_long_cluster_name_test_here:intec34p" $GFS_TGT], 255, [ignore], [ignore]) ++AT_CHECK([$GFS_MKFS -p lock_dlm -t "financial_cluster:this_time_we_test_fs_naming_len" $GFS_TGT], 255, [ignore], [ignore]) ++GFS_FSCK_CHECK([$GFS_MKFS -p lock_dlm -t "a_really_long_named_cluster_here:concurrently_lets_check_fs_len" $GFS_TGT]) ++AT_CLEANUP diff --git a/SOURCES/bz1225634-1-gfs2_utils_Fix_hang_on_withdraw.patch b/SOURCES/bz1225634-1-gfs2_utils_Fix_hang_on_withdraw.patch new file mode 100644 index 0000000..191e79f --- /dev/null +++ b/SOURCES/bz1225634-1-gfs2_utils_Fix_hang_on_withdraw.patch @@ -0,0 +1,97 @@ +commit 40b872651561de2e8a06fdb1b792be8874e2b19a +Author: Abhi Das +Date: Tue Aug 4 11:00:51 2015 -0500 + + gfs2-utils: Fix hang on withdraw + + Issuing a withdraw on a gfs2 filesystem causes a hang. When + gfs_controld was removed, the userspace functionality that + completes a withdraw operation went away. This causes gfs2 + kernel to hang waiting for a withdraw completion ack from + userspace. + + This patchset introduces a uevent-based shell script to do + the job that gfs_controld used to do on withdraw. An 'offline' + uevent triggers the execution of this script. This script + suspends the device associated with the filesystem and signals + a completed withdraw to the kernel. + + Resolves: rhbz#1225634 + Signed-off-by: Abhi Das + +diff --git a/README.build b/README.build +index f4ebe53..6487bae 100644 +--- a/README.build ++++ b/README.build +@@ -29,5 +29,14 @@ To install gfs2-utils, run: + + make install + ++The following scripts (located in gfs2/scripts) are used to complete ++the userland portion of the gfs2 withdraw feature using uevents. They ++are not installed by 'make install' and need to be installed manually ++or during rpm installation to the corresponding locations. ++ ++ 82-gfs2-withdraw.rules in /etc/udev/rules.d/ ++ gfs2_wd_udev.sh in /usr/sbin/ ++ + See also doc/README.contributing for details on submitting patches and + doc/README.tests for more details regarding the test suite. ++ +diff --git a/gfs2/scripts/82-gfs2-withdraw.rules b/gfs2/scripts/82-gfs2-withdraw.rules +new file mode 100644 +index 0000000..2228615 +--- /dev/null ++++ b/gfs2/scripts/82-gfs2-withdraw.rules +@@ -0,0 +1,2 @@ ++SUBSYSTEM=="gfs2", ACTION=="offline", RUN+="/bin/sh /usr/sbin/gfs2_wd_udev.sh" ++ +diff --git a/gfs2/scripts/Makefile.am b/gfs2/scripts/Makefile.am +index 62fb2fe..dde906f 100644 +--- a/gfs2/scripts/Makefile.am ++++ b/gfs2/scripts/Makefile.am +@@ -3,3 +3,8 @@ MAINTAINERCLEANFILES = Makefile.in + dist_sbin_SCRIPTS = \ + gfs2_lockcapture \ + gfs2_trace ++ ++noinst_SCRIPTS = \ ++ 82-gfs2-withdraw.rules \ ++ gfs2_wd_udev.sh ++ +diff --git a/gfs2/scripts/gfs2_wd_udev.sh b/gfs2/scripts/gfs2_wd_udev.sh +new file mode 100755 +index 0000000..ac3ce35 +--- /dev/null ++++ b/gfs2/scripts/gfs2_wd_udev.sh +@@ -0,0 +1,30 @@ ++#!/bin/sh ++# ++# Do not run this script manually. This script is called by udev on a gfs2 ++# withdraw uevent and is used to complete the withdraw action and notify the ++# kernel. ++# ++ ++# Sanity checks ++if [ "$SUBSYSTEM" != "gfs2" ] || [ "$LOCKPROTO" != "lock_dlm" ] || ++ [ -z "$DEVPATH" ] || [ "$ACTION" != "offline" ] ++then ++ exit 1 # Nothing to do here ++fi ++ ++# Try and suspend the device ++SYSFS_TOPDIR="/sys"$DEVPATH ++DM_NAME=$(cat "$SYSFS_TOPDIR/device/dm/name") ++DM_DEV="/dev/mapper/"$DM_NAME ++ ++if [ -z "$DM_DEV" ] ++then ++ /usr/bin/dmsetup suspend $DM_DEV ++fi ++ ++# Signal completion of withdraw ++WD_ACK="$SYSFS_TOPDIR/lock_module/withdraw" ++if [ -f "$WD_ACK" ] ++then ++ echo "1" > $WD_ACK ++fi diff --git a/SOURCES/bz1225634-2-scripts_rename_gfs2_wd_udev_sh_to_gfs2_withdraw_helper.patch b/SOURCES/bz1225634-2-scripts_rename_gfs2_wd_udev_sh_to_gfs2_withdraw_helper.patch new file mode 100644 index 0000000..749ffaf --- /dev/null +++ b/SOURCES/bz1225634-2-scripts_rename_gfs2_wd_udev_sh_to_gfs2_withdraw_helper.patch @@ -0,0 +1,116 @@ +commit 60db3c365128dc8aa7e0d3c903c426c8a743b8e2 +Author: Andrew Price +Date: Tue Aug 18 12:35:52 2015 +0100 + + scripts: rename gfs2_wd_udev.sh to gfs2_withdraw_helper + + Makes the name more descriptive and consistent with the name of the udev + rules script. + + Resolves: rhbz#1225634 + Signed-off-by: Andrew Price + +diff --git a/README.build b/README.build +index 6487bae..acfde1b 100644 +--- a/README.build ++++ b/README.build +@@ -35,7 +35,7 @@ are not installed by 'make install' and need to be installed manually + or during rpm installation to the corresponding locations. + + 82-gfs2-withdraw.rules in /etc/udev/rules.d/ +- gfs2_wd_udev.sh in /usr/sbin/ ++ gfs2_withdraw_helper in /usr/sbin/ + + See also doc/README.contributing for details on submitting patches and + doc/README.tests for more details regarding the test suite. +diff --git a/gfs2/scripts/82-gfs2-withdraw.rules b/gfs2/scripts/82-gfs2-withdraw.rules +index 2228615..2c9e0e8 100644 +--- a/gfs2/scripts/82-gfs2-withdraw.rules ++++ b/gfs2/scripts/82-gfs2-withdraw.rules +@@ -1,2 +1,2 @@ +-SUBSYSTEM=="gfs2", ACTION=="offline", RUN+="/bin/sh /usr/sbin/gfs2_wd_udev.sh" ++SUBSYSTEM=="gfs2", ACTION=="offline", RUN+="/bin/sh /usr/sbin/gfs2_withdraw_helper" + +diff --git a/gfs2/scripts/Makefile.am b/gfs2/scripts/Makefile.am +index dde906f..51764fa 100644 +--- a/gfs2/scripts/Makefile.am ++++ b/gfs2/scripts/Makefile.am +@@ -6,5 +6,5 @@ dist_sbin_SCRIPTS = \ + + noinst_SCRIPTS = \ + 82-gfs2-withdraw.rules \ +- gfs2_wd_udev.sh ++ gfs2_withdraw_helper + +diff --git a/gfs2/scripts/gfs2_wd_udev.sh b/gfs2/scripts/gfs2_wd_udev.sh +deleted file mode 100755 +index ac3ce35..0000000 +--- a/gfs2/scripts/gfs2_wd_udev.sh ++++ /dev/null +@@ -1,30 +0,0 @@ +-#!/bin/sh +-# +-# Do not run this script manually. This script is called by udev on a gfs2 +-# withdraw uevent and is used to complete the withdraw action and notify the +-# kernel. +-# +- +-# Sanity checks +-if [ "$SUBSYSTEM" != "gfs2" ] || [ "$LOCKPROTO" != "lock_dlm" ] || +- [ -z "$DEVPATH" ] || [ "$ACTION" != "offline" ] +-then +- exit 1 # Nothing to do here +-fi +- +-# Try and suspend the device +-SYSFS_TOPDIR="/sys"$DEVPATH +-DM_NAME=$(cat "$SYSFS_TOPDIR/device/dm/name") +-DM_DEV="/dev/mapper/"$DM_NAME +- +-if [ -z "$DM_DEV" ] +-then +- /usr/bin/dmsetup suspend $DM_DEV +-fi +- +-# Signal completion of withdraw +-WD_ACK="$SYSFS_TOPDIR/lock_module/withdraw" +-if [ -f "$WD_ACK" ] +-then +- echo "1" > $WD_ACK +-fi +diff --git a/gfs2/scripts/gfs2_withdraw_helper b/gfs2/scripts/gfs2_withdraw_helper +new file mode 100755 +index 0000000..ac3ce35 +--- /dev/null ++++ b/gfs2/scripts/gfs2_withdraw_helper +@@ -0,0 +1,30 @@ ++#!/bin/sh ++# ++# Do not run this script manually. This script is called by udev on a gfs2 ++# withdraw uevent and is used to complete the withdraw action and notify the ++# kernel. ++# ++ ++# Sanity checks ++if [ "$SUBSYSTEM" != "gfs2" ] || [ "$LOCKPROTO" != "lock_dlm" ] || ++ [ -z "$DEVPATH" ] || [ "$ACTION" != "offline" ] ++then ++ exit 1 # Nothing to do here ++fi ++ ++# Try and suspend the device ++SYSFS_TOPDIR="/sys"$DEVPATH ++DM_NAME=$(cat "$SYSFS_TOPDIR/device/dm/name") ++DM_DEV="/dev/mapper/"$DM_NAME ++ ++if [ -z "$DM_DEV" ] ++then ++ /usr/bin/dmsetup suspend $DM_DEV ++fi ++ ++# Signal completion of withdraw ++WD_ACK="$SYSFS_TOPDIR/lock_module/withdraw" ++if [ -f "$WD_ACK" ] ++then ++ echo "1" > $WD_ACK ++fi diff --git a/SOURCES/bz1225634-3-scripts_install_the_withdraw_helper_script.patch b/SOURCES/bz1225634-3-scripts_install_the_withdraw_helper_script.patch new file mode 100644 index 0000000..cfd0149 --- /dev/null +++ b/SOURCES/bz1225634-3-scripts_install_the_withdraw_helper_script.patch @@ -0,0 +1,28 @@ +commit c17455947281083e73567871ba1777d7ec135d4e +Author: Andrew Price +Date: Tue Aug 18 12:48:50 2015 +0100 + + scripts: install the withdraw helper script + + Install gfs2_withdraw_helper into /usr/sbin in 'make install'. + + Resolves: rhbz#1225634 + Signed-off-by: Andrew Price + +diff --git a/gfs2/scripts/Makefile.am b/gfs2/scripts/Makefile.am +index 51764fa..056aaa5 100644 +--- a/gfs2/scripts/Makefile.am ++++ b/gfs2/scripts/Makefile.am +@@ -2,9 +2,9 @@ MAINTAINERCLEANFILES = Makefile.in + + dist_sbin_SCRIPTS = \ + gfs2_lockcapture \ +- gfs2_trace ++ gfs2_trace \ ++ gfs2_withdraw_helper + + noinst_SCRIPTS = \ +- 82-gfs2-withdraw.rules \ +- gfs2_withdraw_helper ++ 82-gfs2-withdraw.rules + diff --git a/SOURCES/bz1225634-4-scripts_install_the_withdraw_udev_rules_script.patch b/SOURCES/bz1225634-4-scripts_install_the_withdraw_udev_rules_script.patch new file mode 100644 index 0000000..6b960a8 --- /dev/null +++ b/SOURCES/bz1225634-4-scripts_install_the_withdraw_udev_rules_script.patch @@ -0,0 +1,73 @@ +commit f26de3589548a9fde9797e9f515b5b27de5a961d +Author: Andrew Price +Date: Wed Aug 19 12:13:39 2015 +0100 + + scripts: install the withdraw udev rules script + + Add a --with-udevdir configure option and default to $prefix/lib/udev. + Note that we can't use $libdir for this as that will often be /usr/lib64 + and the udevdir is arch-independent. + + Also add the autoconf bits needed to install 82-gfs2-withdraw.rules into + $udevdir/rules.d + + Resolves: rhbz#1225634 + Signed-off-by: Andrew Price + +diff --git a/README.build b/README.build +index acfde1b..d0a21c3 100644 +--- a/README.build ++++ b/README.build +@@ -31,10 +31,9 @@ To install gfs2-utils, run: + + The following scripts (located in gfs2/scripts) are used to complete + the userland portion of the gfs2 withdraw feature using uevents. They +-are not installed by 'make install' and need to be installed manually +-or during rpm installation to the corresponding locations. ++will be installed by 'make install' to these directories by default: + +- 82-gfs2-withdraw.rules in /etc/udev/rules.d/ ++ 82-gfs2-withdraw.rules in /usr/lib/udev/rules.d/ + gfs2_withdraw_helper in /usr/sbin/ + + See also doc/README.contributing for details on submitting patches and +diff --git a/configure.ac b/configure.ac +index de96e5a..35cafe6 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -110,6 +110,12 @@ if test -z "$ncurses_CFLAGS" && test -z "$ncurses_LIBS"; then + ncurses_LIBS=-lncurses + fi + ++AC_ARG_WITH([udevdir], ++ AS_HELP_STRING([--with-udevdir=DIR], ++ [udev directory containing rules.d [default=${prefix}/lib/udev]]), ++ [], [with_udevdir=\${prefix}/lib/udev]) ++AC_SUBST([udevdir], [$with_udevdir]) ++ + # Checks for header files. + AC_CHECK_HEADERS([fcntl.h libintl.h limits.h locale.h mntent.h stddef.h sys/file.h sys/ioctl.h sys/mount.h sys/time.h sys/vfs.h syslog.h termios.h]) + AC_CHECK_HEADER([linux/fs.h], [], [AC_MSG_ERROR([Unable to find linux/fs.h])]) +@@ -209,7 +215,9 @@ echo " Configure summary" + echo " ===================" + echo " prefix : $prefix" + echo " exec_prefix : $exec_prefix" ++echo " libdir : $libdir" + echo " sbindir : $sbindir" ++echo " udevdir : $udevdir" + echo " ------------------" + echo " debug build : $enable_debug" + echo " C unit tests : $have_check" +diff --git a/gfs2/scripts/Makefile.am b/gfs2/scripts/Makefile.am +index 056aaa5..d4bda04 100644 +--- a/gfs2/scripts/Makefile.am ++++ b/gfs2/scripts/Makefile.am +@@ -5,6 +5,6 @@ dist_sbin_SCRIPTS = \ + gfs2_trace \ + gfs2_withdraw_helper + +-noinst_SCRIPTS = \ ++udevrulesdir=@udevdir@/rules.d ++dist_udevrules_DATA = \ + 82-gfs2-withdraw.rules +- diff --git a/SOURCES/bz1236669-1-fsck_gfs2_Change_duptree_structure_to_have_generic_flags.patch b/SOURCES/bz1236669-1-fsck_gfs2_Change_duptree_structure_to_have_generic_flags.patch new file mode 100644 index 0000000..a4a8de1 --- /dev/null +++ b/SOURCES/bz1236669-1-fsck_gfs2_Change_duptree_structure_to_have_generic_flags.patch @@ -0,0 +1,76 @@ +commit f9b17da3f2e4b278bfcb04465a7a22c45c441d04 +Author: Bob Peterson +Date: Fri Jun 26 12:18:59 2015 -0500 + + fsck.gfs2: Change duptree structure to have generic flags + + This patch does not change any functionality. It merely changes the + specialized first_ref_found flag to a flag within a multi-flag var. + + rhbz#1236669 + +diff --git a/gfs2/fsck/fsck.h b/gfs2/fsck/fsck.h +index 09db668..78e8ad4 100644 +--- a/gfs2/fsck/fsck.h ++++ b/gfs2/fsck/fsck.h +@@ -57,9 +57,11 @@ struct dir_status { + uint32_t entry_count; + }; + ++#define DUPFLAG_REF1_FOUND 1 /* Has the original reference been found? */ ++ + struct duptree { + struct osi_node node; +- int first_ref_found; /* Has the original reference been found? */ ++ int dup_flags; + int refs; + uint64_t block; + osi_list_t ref_inode_list; /* list of inodes referencing a dup block */ +diff --git a/gfs2/fsck/util.c b/gfs2/fsck/util.c +index efdd132..4022fee 100644 +--- a/gfs2/fsck/util.c ++++ b/gfs2/fsck/util.c +@@ -261,7 +261,6 @@ static struct duptree *gfs2_dup_set(uint64_t dblock, int create) + dt->block = dblock; + dt->refs = 1; /* reference 1 is actually the reference we need to + discover in pass1b. */ +- dt->first_ref_found = 0; + osi_list_init(&dt->ref_inode_list); + osi_list_init(&dt->ref_invinode_list); + osi_link_node(&dt->node, parent, newn); +@@ -326,7 +325,7 @@ int add_duplicate_ref(struct gfs2_inode *ip, uint64_t block, + /* If we found the duplicate reference but we've already discovered + the first reference (in pass1b) and the other references in pass1, + we don't need to count it, so just return. */ +- if (dt->first_ref_found) ++ if (dt->dup_flags & DUPFLAG_REF1_FOUND) + return meta_is_good; + + /* Check for a previous reference to this duplicate */ +@@ -338,7 +337,7 @@ int add_duplicate_ref(struct gfs2_inode *ip, uint64_t block, + that case, we don't want to be confused and consider this second + reference the same as the first. If we do, we'll never be able to + resolve it. The first reference can't be the second reference. */ +- if (id && first && !dt->first_ref_found) { ++ if (id && first && !(dt->dup_flags & DUPFLAG_REF1_FOUND)) { + log_info(_("Original reference to block %llu (0x%llx) was " + "previously found to be bad and deleted.\n"), + (unsigned long long)block, +@@ -347,7 +346,7 @@ int add_duplicate_ref(struct gfs2_inode *ip, uint64_t block, + "(0x%llx) the first reference.\n"), + (unsigned long long)ip->i_di.di_num.no_addr, + (unsigned long long)ip->i_di.di_num.no_addr); +- dt->first_ref_found = 1; ++ dt->dup_flags |= DUPFLAG_REF1_FOUND; + return meta_is_good; + } + +@@ -356,7 +355,7 @@ int add_duplicate_ref(struct gfs2_inode *ip, uint64_t block, + reference, we don't want to increment the reference count because + it's already accounted for. */ + if (first) { +- dt->first_ref_found = 1; ++ dt->dup_flags |= DUPFLAG_REF1_FOUND; + dups_found_first++; /* We found another first ref. */ + } else { + dt->refs++; diff --git a/SOURCES/bz1236669-2-fsck_gfs2_Detect_fix_and_clone_duplicate_block_refs_within_a_dinode.patch b/SOURCES/bz1236669-2-fsck_gfs2_Detect_fix_and_clone_duplicate_block_refs_within_a_dinode.patch new file mode 100644 index 0000000..3595b4e --- /dev/null +++ b/SOURCES/bz1236669-2-fsck_gfs2_Detect_fix_and_clone_duplicate_block_refs_within_a_dinode.patch @@ -0,0 +1,343 @@ +commit ce7b371a5ef76526eeba90b2eb62e1912d9b772f +Author: Bob Peterson +Date: Mon Jun 29 10:53:52 2015 -0500 + + fsck.gfs2: Detect, fix and clone duplicate block refs within a dinode + + Prior to this patch, fsck.gfs2 was unable to detect and fix duplicate + block references within the same file. This patch detects when data + blocks are duplicated within a dinode, then tries to clone the data + to a new block. + + rhbz#1236669 + +diff --git a/gfs2/fsck/fs_recovery.c b/gfs2/fsck/fs_recovery.c +index 9be5a95..ce11fb4 100644 +--- a/gfs2/fsck/fs_recovery.c ++++ b/gfs2/fsck/fs_recovery.c +@@ -668,7 +668,8 @@ static int rangecheck_jmeta(struct gfs2_inode *ip, uint64_t block, + } + + static int rangecheck_jdata(struct gfs2_inode *ip, uint64_t metablock, +- uint64_t block, void *private) ++ uint64_t block, void *private, ++ struct gfs2_buffer_head *bh, uint64_t *ptr) + { + return rangecheck_jblock(ip, block); + } +diff --git a/gfs2/fsck/fsck.h b/gfs2/fsck/fsck.h +index 78e8ad4..a3c5f72 100644 +--- a/gfs2/fsck/fsck.h ++++ b/gfs2/fsck/fsck.h +@@ -58,6 +58,8 @@ struct dir_status { + }; + + #define DUPFLAG_REF1_FOUND 1 /* Has the original reference been found? */ ++#define DUPFLAG_REF1_IS_DUPL 2 /* The original reference is also where we ++ determined there was a duplicate. */ + + struct duptree { + struct osi_node node; +diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c +index 4d5a660..333bec6 100644 +--- a/gfs2/fsck/metawalk.c ++++ b/gfs2/fsck/metawalk.c +@@ -1449,7 +1449,8 @@ static int check_data(struct gfs2_inode *ip, struct metawalk_fxns *pass, + would defeat the rangecheck_block related functions in + pass1. Therefore the individual check_data functions + should do a range check. */ +- rc = pass->check_data(ip, metablock, block, pass->private); ++ rc = pass->check_data(ip, metablock, block, pass->private, ++ bh, ptr); + if (rc && (!error || (rc < error))) { + log_info("\n"); + if (rc < 0) { +@@ -1787,7 +1788,8 @@ int delete_leaf(struct gfs2_inode *ip, uint64_t block, void *private) + } + + int delete_data(struct gfs2_inode *ip, uint64_t metablock, +- uint64_t block, void *private) ++ uint64_t block, void *private, struct gfs2_buffer_head *bh, ++ uint64_t *ptr) + { + return delete_block_if_notdup(ip, block, NULL, _("data"), NULL, + private); +@@ -1915,7 +1917,8 @@ static int alloc_metalist(struct gfs2_inode *ip, uint64_t block, + } + + static int alloc_data(struct gfs2_inode *ip, uint64_t metablock, +- uint64_t block, void *private) ++ uint64_t block, void *private, ++ struct gfs2_buffer_head *bh, uint64_t *ptr) + { + uint8_t q; + const char *desc = (const char *)private; +diff --git a/gfs2/fsck/metawalk.h b/gfs2/fsck/metawalk.h +index fa4c850..8ec38d0 100644 +--- a/gfs2/fsck/metawalk.h ++++ b/gfs2/fsck/metawalk.h +@@ -29,7 +29,8 @@ extern int delete_metadata(struct gfs2_inode *ip, uint64_t block, + int *was_duplicate, void *private); + extern int delete_leaf(struct gfs2_inode *ip, uint64_t block, void *private); + extern int delete_data(struct gfs2_inode *ip, uint64_t metablock, +- uint64_t block, void *private); ++ uint64_t block, void *private, ++ struct gfs2_buffer_head *bh, uint64_t *ptr); + extern int delete_eattr_indir(struct gfs2_inode *ip, uint64_t block, uint64_t parent, + struct gfs2_buffer_head **bh, void *private); + extern int delete_eattr_leaf(struct gfs2_inode *ip, uint64_t block, uint64_t parent, +@@ -117,7 +118,8 @@ struct metawalk_fxns { + int *is_valid, int *was_duplicate, + void *private); + int (*check_data) (struct gfs2_inode *ip, uint64_t metablock, +- uint64_t block, void *private); ++ uint64_t block, void *private, ++ struct gfs2_buffer_head *bh, uint64_t *ptr); + int (*check_eattr_indir) (struct gfs2_inode *ip, uint64_t block, + uint64_t parent, + struct gfs2_buffer_head **bh, void *private); +diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c +index 0909873..c0f2f1e 100644 +--- a/gfs2/fsck/pass1.c ++++ b/gfs2/fsck/pass1.c +@@ -44,7 +44,8 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block, + static int undo_check_metalist(struct gfs2_inode *ip, uint64_t block, + int h, void *private); + static int check_data(struct gfs2_inode *ip, uint64_t metablock, +- uint64_t block, void *private); ++ uint64_t block, void *private, ++ struct gfs2_buffer_head *bh, uint64_t *ptr); + static int undo_check_data(struct gfs2_inode *ip, uint64_t block, + void *private); + static int check_eattr_indir(struct gfs2_inode *ip, uint64_t indirect, +@@ -72,7 +73,8 @@ static int invalidate_metadata(struct gfs2_inode *ip, uint64_t block, + static int invalidate_leaf(struct gfs2_inode *ip, uint64_t block, + void *private); + static int invalidate_data(struct gfs2_inode *ip, uint64_t metablock, +- uint64_t block, void *private); ++ uint64_t block, void *private, ++ struct gfs2_buffer_head *bh, uint64_t *ptr); + static int invalidate_eattr_indir(struct gfs2_inode *ip, uint64_t block, + uint64_t parent, + struct gfs2_buffer_head **bh, +@@ -441,7 +443,8 @@ out: + } + + static int check_data(struct gfs2_inode *ip, uint64_t metablock, +- uint64_t block, void *private) ++ uint64_t block, void *private, ++ struct gfs2_buffer_head *bbh, uint64_t *ptr) + { + uint8_t q; + struct block_count *bc = (struct block_count *) private; +@@ -969,7 +972,8 @@ static int invalidate_leaf(struct gfs2_inode *ip, uint64_t block, + } + + static int invalidate_data(struct gfs2_inode *ip, uint64_t metablock, +- uint64_t block, void *private) ++ uint64_t block, void *private, ++ struct gfs2_buffer_head *bh, uint64_t *ptr) + { + return mark_block_invalid(ip, block, ref_as_data, _("data"), + NULL, NULL); +@@ -1069,7 +1073,8 @@ static int rangecheck_leaf(struct gfs2_inode *ip, uint64_t block, + } + + static int rangecheck_data(struct gfs2_inode *ip, uint64_t metablock, +- uint64_t block, void *private) ++ uint64_t block, void *private, ++ struct gfs2_buffer_head *bh, uint64_t *ptr) + { + return rangecheck_block(ip, block, NULL, btype_data, private); + } +diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c +index a8f3d28..c1598ff 100644 +--- a/gfs2/fsck/pass1b.c ++++ b/gfs2/fsck/pass1b.c +@@ -28,6 +28,11 @@ struct dup_handler { + int ref_count; + }; + ++struct clone_target { ++ uint64_t dup_block; ++ int first; ++}; ++ + static void log_inode_reference(struct duptree *dt, osi_list_t *tmp, int inval) + { + char reftypestring[32]; +@@ -249,6 +254,116 @@ static void revise_dup_handler(uint64_t dup_blk, struct dup_handler *dh) + } + } + ++static int clone_check_meta(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 0; ++} ++ ++/* clone_data - clone a duplicate reference ++ * ++ * This function remembers the first reference to the specified block, and ++ * clones all subsequent references to it (with permission). ++ */ ++static int clone_data(struct gfs2_inode *ip, uint64_t metablock, ++ uint64_t block, void *private, ++ struct gfs2_buffer_head *bh, uint64_t *ptr) ++{ ++ struct clone_target *clonet = (struct clone_target *)private; ++ struct gfs2_buffer_head *clone_bh; ++ uint64_t cloneblock; ++ int error; ++ ++ if (block != clonet->dup_block) ++ return 0; ++ ++ if (clonet->first) { ++ log_debug(_("Inode %lld (0x%llx)'s first reference to " ++ "block %lld (0x%llx) is targeted for cloning.\n"), ++ (unsigned long long)ip->i_di.di_num.no_addr, ++ (unsigned long long)ip->i_di.di_num.no_addr, ++ (unsigned long long)block, ++ (unsigned long long)block); ++ clonet->first = 0; ++ return 0; ++ } ++ log_err(_("Error: Inode %lld (0x%llx)'s subsequent reference to " ++ "block %lld (0x%llx) is an error.\n"), ++ (unsigned long long)ip->i_di.di_num.no_addr, ++ (unsigned long long)ip->i_di.di_num.no_addr, ++ (unsigned long long)block, (unsigned long long)block); ++ if (query( _("Okay to clone the duplicated reference? (y/n) "))) { ++ error = lgfs2_meta_alloc(ip, &cloneblock); ++ if (!error) { ++ clone_bh = bread(ip->i_sbd, clonet->dup_block); ++ if (clone_bh) { ++ fsck_blockmap_set(ip, cloneblock, _("data"), ++ GFS2_BLKST_USED); ++ clone_bh->b_blocknr = cloneblock; ++ bmodified(clone_bh); ++ brelse(clone_bh); ++ /* Now fix the reference: */ ++ *ptr = cpu_to_be64(cloneblock); ++ bmodified(bh); ++ log_err(_("Duplicate reference to block %lld " ++ "(0x%llx) was cloned to block %lld " ++ "(0x%llx).\n"), ++ (unsigned long long)block, ++ (unsigned long long)block, ++ (unsigned long long)cloneblock, ++ (unsigned long long)cloneblock); ++ return 0; ++ } ++ } ++ log_err(_("Error: Unable to allocate a new data block.\n")); ++ if (!query("Should I zero the reference instead? (y/n)")) { ++ log_err(_("Duplicate reference to block %lld " ++ "(0x%llx) was not fixed.\n"), ++ (unsigned long long)block, ++ (unsigned long long)block); ++ return 0; ++ } ++ *ptr = 0; ++ bmodified(bh); ++ log_err(_("Duplicate reference to block %lld (0x%llx) was " ++ "zeroed.\n"), ++ (unsigned long long)block, ++ (unsigned long long)block); ++ } else { ++ log_err(_("Duplicate reference to block %lld (0x%llx) " ++ "was not fixed.\n"), (unsigned long long)block, ++ (unsigned long long)block); ++ } ++ return 0; ++} ++ ++/* clone_dup_ref_in_inode - clone a duplicate reference within a single inode ++ * ++ * This function traverses the metadata tree of an inode, cloning all ++ * but the first reference to a duplicate block reference. ++ */ ++static void clone_dup_ref_in_inode(struct gfs2_inode *ip, struct duptree *dt) ++{ ++ int error; ++ struct clone_target clonet = {.dup_block = dt->block, .first = 1}; ++ struct metawalk_fxns pass1b_fxns_clone = { ++ .private = &clonet, ++ .check_metalist = clone_check_meta, ++ .check_data = clone_data, ++ }; ++ ++ error = check_metatree(ip, &pass1b_fxns_clone); ++ if (error) { ++ log_err(_("Error cloning duplicate reference(s) to block %lld " ++ "(0x%llx).\n"), (unsigned long long)dt->block, ++ (unsigned long long)dt->block); ++ } ++} ++ + /* handle_dup_blk - handle a duplicate block reference. + * + * This function should resolve and delete the duplicate block reference given, +@@ -389,6 +504,9 @@ static int handle_dup_blk(struct gfs2_sbd *sdp, struct duptree *dt) + (unsigned long long)id->block_no); + ip = fsck_load_inode(sdp, id->block_no); + ++ if (dt->dup_flags & DUPFLAG_REF1_IS_DUPL) ++ clone_dup_ref_in_inode(ip, dt); ++ + q = block_type(id->block_no); + if (q == GFS2_BLKST_UNLINKED) { + log_debug( _("The remaining reference inode %lld " +@@ -468,7 +586,8 @@ static int check_metalist_refs(struct gfs2_inode *ip, uint64_t block, + } + + static int check_data_refs(struct gfs2_inode *ip, uint64_t metablock, +- uint64_t block, void *private) ++ uint64_t block, void *private, ++ struct gfs2_buffer_head *bh, uint64_t *ptr) + { + return add_duplicate_ref(ip, block, ref_as_data, 1, INODE_VALID); + } +diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c +index b31fbd4..900d4e1 100644 +--- a/gfs2/fsck/pass2.c ++++ b/gfs2/fsck/pass2.c +@@ -1580,7 +1580,8 @@ static int check_metalist_qc(struct gfs2_inode *ip, uint64_t block, + } + + static int check_data_qc(struct gfs2_inode *ip, uint64_t metablock, +- uint64_t block, void *private) ++ uint64_t block, void *private, ++ struct gfs2_buffer_head *bbh, uint64_t *ptr) + { + struct gfs2_buffer_head *bh; + +diff --git a/gfs2/fsck/util.c b/gfs2/fsck/util.c +index 4022fee..a6a5cdc 100644 +--- a/gfs2/fsck/util.c ++++ b/gfs2/fsck/util.c +@@ -339,15 +339,16 @@ int add_duplicate_ref(struct gfs2_inode *ip, uint64_t block, + resolve it. The first reference can't be the second reference. */ + if (id && first && !(dt->dup_flags & DUPFLAG_REF1_FOUND)) { + log_info(_("Original reference to block %llu (0x%llx) was " +- "previously found to be bad and deleted.\n"), ++ "either found to be bad and deleted, or else " ++ "a duplicate within the same inode.\n"), + (unsigned long long)block, + (unsigned long long)block); + log_info(_("I'll consider the reference from inode %llu " + "(0x%llx) the first reference.\n"), + (unsigned long long)ip->i_di.di_num.no_addr, + (unsigned long long)ip->i_di.di_num.no_addr); +- dt->dup_flags |= DUPFLAG_REF1_FOUND; +- return meta_is_good; ++ dt->dup_flags |= DUPFLAG_REF1_IS_DUPL; ++ dt->refs++; + } + + /* The first time this is called from pass1 is actually the second diff --git a/SPECS/gfs2-utils.spec b/SPECS/gfs2-utils.spec index 564f879..7fbb8a7 100644 --- a/SPECS/gfs2-utils.spec +++ b/SPECS/gfs2-utils.spec @@ -11,7 +11,7 @@ ############################################################################### Name: gfs2-utils -Version: 3.1.7 +Version: 3.1.8 Release: 6%{?dist} License: GPLv2+ and LGPLv2+ Group: System Environment/Kernel @@ -21,7 +21,6 @@ Obsoletes: gfs2-cluster < %{version} BuildRequires: ncurses-devel BuildRequires: kernel-headers BuildRequires: automake -BuildRequires: perl BuildRequires: libtool BuildRequires: zlib-devel BuildRequires: gettext-devel @@ -42,31 +41,29 @@ ExclusiveArch: x86_64 s390x # ./make-tarball.sh # Source0: https://fedorahosted.org/released/gfs2-utils/gfs2-utils-%{version}.tar.gz -Patch0: bz1112342-1-gfs2_utils_tests_Build_unit_tests_with_consistent_cpp_flags.patch -Patch1: bz1112342-2-gfs2_utils_tests_Fix_unit_tests_for_RHEL7.patch -Patch2: bz1154786-fsck_gfs2_Improve_reporting_of_pass_timings.patch -Patch3: bz1146160-fsck_gfs2_Detect_and_correct_corrupt_journals.patch -Patch4: bz1162817-mkfs_gfs2_Revert_default_resource_group_size.patch -Patch5: bz1178604-1-fsck_gfs2_fix_broken_i_goal_values_in_inodes.patch -Patch6: bz1178604-2-gfs2_convert_use_correct_i_goal_values_instead_of_zeros_for_inodes.patch -Patch7: bz1178604-3-tests_test_for_incorrect_inode_i_goal_values.patch -Patch8: bz1178604-4-fsck_gfs2_Reprocess_nodes_if_anything_changed_addendum_1_of_2.patch -Patch9: bz1178604-5-fsck_gfs2_addendum_to_fix_broken_i_goal_values_in_inodes_addendum_2_of_2.patch +Patch0: bz1186515-fsck_gfs2_replace_recent_i_goal_fixes_with_simple_logic.patch +Patch1: bz1202831-mkfs_gfs2_Allow_longer_cluster_names.patch +Patch2: bz1236669-1-fsck_gfs2_Change_duptree_structure_to_have_generic_flags.patch +Patch3: bz1236669-2-fsck_gfs2_Detect_fix_and_clone_duplicate_block_refs_within_a_dinode.patch +Patch4: bz1225634-1-gfs2_utils_Fix_hang_on_withdraw.patch +Patch5: bz1225634-2-scripts_rename_gfs2_wd_udev_sh_to_gfs2_withdraw_helper.patch +Patch6: bz1225634-3-scripts_install_the_withdraw_helper_script.patch +Patch7: bz1225634-4-scripts_install_the_withdraw_udev_rules_script.patch +Patch8: bz1162216-gfs2_edit_savemeta_speed_up_is_block_in_per_node.patch BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) %prep %setup -q -n gfs2-utils-%{version} -%patch0 -p1 -b .bz1112342-1-gfs2_utils_tests_Build_unit_tests_with_consistent_cpp_flags -%patch1 -p1 -b .bz1112342-2-gfs2_utils_tests_Fix_unit_tests_for_RHEL7 -%patch2 -p1 -b .bz1154786-fsck_gfs2_Improve_reporting_of_pass_timings -%patch3 -p1 -b .bz1146160-fsck_gfs2_Detect_and_correct_corrupt_journals -%patch4 -p1 -b .bz1162817-mkfs_gfs2_Revert_default_resource_group_size -%patch5 -p1 -b .bz1178604-1-fsck_gfs2_fix_broken_i_goal_values_in_inodes -%patch6 -p1 -b .bz1178604-2-gfs2_convert_use_correct_i_goal_values_instead_of_zeros_for_inodes -%patch7 -p1 -b .bz1178604-3-tests_test_for_incorrect_inode_i_goal_values -%patch8 -p1 -b .bz1178604-4-fsck_gfs2_Reprocess_nodes_if_anything_changed_addendum_1_of_2 -%patch9 -p1 -b .bz1178604-5-fsck_gfs2_addendum_to_fix_broken_i_goal_values_in_inodes_addendum_2_of_2 +%patch0 -p1 -b .bz1186515-fsck_gfs2_replace_recent_i_goal_fixes_with_simple_logic +%patch1 -p1 -b .bz1202831-mkfs_gfs2_Allow_longer_cluster_names +%patch2 -p1 -b .bz1236669-1-fsck_gfs2_Change_duptree_structure_to_have_generic_flags +%patch3 -p1 -b .bz1236669-2-fsck_gfs2_Detect_fix_and_clone_duplicate_block_refs_within_a_dinode +%patch4 -p1 -b .bz1225634-1-gfs2_utils_Fix_hang_on_withdraw +%patch5 -p1 -b .bz1225634-2-scripts_rename_gfs2_wd_udev_sh_to_gfs2_withdraw_helper +%patch6 -p1 -b .bz1225634-3-scripts_install_the_withdraw_helper_script +%patch7 -p1 -b .bz1225634-4-scripts_install_the_withdraw_udev_rules_script +%patch8 -p1 -b .bz1162216-gfs2_edit_savemeta_speed_up_is_block_in_per_node %build ./autogen.sh @@ -80,25 +77,20 @@ make check rm -rf %{buildroot} make -C gfs2 install DESTDIR=%{buildroot} # Don't ship gfs2_{trace,lockcapture} in this package -rm -f %{buildroot}/sbin/gfs2_trace -rm -f %{buildroot}/sbin/gfs2_lockcapture +rm -f %{buildroot}/usr/sbin/gfs2_trace +rm -f %{buildroot}/usr/sbin/gfs2_lockcapture rm -f %{buildroot}%{_mandir}/man8/gfs2_trace.8 rm -f %{buildroot}%{_mandir}/man8/gfs2_lockcapture.8 -# Install into /usr/sbin per UsrMove -mv %{buildroot}/sbin/fsck.gfs2 %{buildroot}/usr/sbin/ -mv %{buildroot}/sbin/mkfs.gfs2 %{buildroot}/usr/sbin/ -mv %{buildroot}/sbin/gfs2_grow %{buildroot}/usr/sbin/ -mv %{buildroot}/sbin/gfs2_jadd %{buildroot}/usr/sbin/ %clean rm -rf %{buildroot} -%description -n gfs2-utils +%description The gfs2-utils package contains a number of utilities for creating, checking, modifying, and correcting any inconsistencies in GFS2 file systems. -%files -n gfs2-utils +%files %defattr(-,root,root,-) %doc doc/COPYING.* doc/COPYRIGHT doc/*.txt %doc doc/README.contributing doc/README.licence doc/README.tests @@ -109,10 +101,46 @@ file systems. %{_sbindir}/gfs2_convert %{_sbindir}/gfs2_edit %{_sbindir}/tunegfs2 +%{_sbindir}/gfs2_withdraw_helper %{_mandir}/man8/*gfs2* %{_mandir}/man5/* +%{_prefix}/lib/udev/rules.d/82-gfs2-withdraw.rules %changelog +* Thu Sep 17 2015 Andrew Price - 3.1.8-6 +- gfs2_edit savemeta: speed up is_block_in_per_node() + Resolves: rhbz#1162216 + +* Thu Aug 20 2015 Andrew Price - 3.1.8-5 +- gfs2-utils: Fix hang on withdraw (4 patches) +- Include new withdraw helper scripts in files section + Resolves: rhbz#1225634 + +* Tue Jul 07 2015 Andrew Price - 3.1.8-4 +- fsck.gfs2: Change duptree structure to have generic flags +- fsck.gfs2: Detect, fix and clone duplicate block refs within a dinode + Resolves: rhbz#1236669 + +* Mon Apr 27 2015 Andrew Price - 3.1.8-3 +- mkfs.gfs2: Allow longer cluster names + Resolves: rhbz#1202831 + +* Fri Apr 17 2015 Andrew Price - 3.1.8-2 +- fsck.gfs2: replace recent i_goal fixes with simple logic + Resolves: rhbz#1186515 + +* Tue Apr 07 2015 Andrew Price - 3.1.8-1 +- Rebase to new upstream version 3.1.8 + Resolves: rhbz#1184482 + Resolves: rhbz#1153316 + Resolves: rhbz#1154726 + Resolves: rhbz#1162216 + Resolves: rhbz#1165285 + Resolves: rhbz#1186515 + Resolves: rhbz#1186847 + Resolves: rhbz#1194446 + Resolves: rhbz#1195394 + * Thu Jan 15 2015 Andrew Price - 3.1.7-6 - fsck.gfs2: fix broken i_goal values in inodes - gfs2_convert: use correct i_goal values instead of zeros for inodes