From 9257a66d38c8408cdad77ad43ffe99aa5ad0fafe Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Sep 29 2020 07:07:48 +0000 Subject: import gfs2-utils-3.1.10-11.el7 --- diff --git a/SOURCES/bz1487726-1-libgfs2_Use_sizeof_for_reserved_fields_in_ondisk_c.patch b/SOURCES/bz1487726-1-libgfs2_Use_sizeof_for_reserved_fields_in_ondisk_c.patch new file mode 100644 index 0000000..4a25b48 --- /dev/null +++ b/SOURCES/bz1487726-1-libgfs2_Use_sizeof_for_reserved_fields_in_ondisk_c.patch @@ -0,0 +1,48 @@ +commit f1969cd08d656377527455903d90431889c48211 +Author: Andrew Price +Date: Wed May 9 17:59:32 2018 +0100 + + libgfs2: Use sizeof for 'reserved' fields in ondisk.c + + Signed-off-by: Andrew Price + +diff --git a/gfs2/libgfs2/ondisk.c b/gfs2/libgfs2/ondisk.c +index 66de2234..bf3c6638 100644 +--- a/gfs2/libgfs2/ondisk.c ++++ b/gfs2/libgfs2/ondisk.c +@@ -189,7 +189,7 @@ void gfs2_rindex_in(struct gfs2_rindex *ri, char *buf) + CPIN_64(ri, str, ri_data0); + CPIN_32(ri, str, ri_data); + CPIN_32(ri, str, ri_bitbytes); +- CPIN_08(ri, str, ri_reserved, 64); ++ CPIN_08(ri, str, ri_reserved, sizeof(ri->ri_reserved)); + } + + void gfs2_rindex_out(const struct gfs2_rindex *ri, char *buf) +@@ -205,7 +205,7 @@ void gfs2_rindex_out(const struct gfs2_rindex *ri, char *buf) + + CPOUT_32(ri, str, ri_bitbytes); + +- CPOUT_08(ri, str, ri_reserved, 64); ++ CPOUT_08(ri, str, ri_reserved, sizeof(ri->ri_reserved)); + } + + void gfs2_rindex_print(const struct gfs2_rindex *ri) +@@ -228,7 +228,7 @@ void gfs2_rgrp_in(struct gfs2_rgrp *rg, struct gfs2_buffer_head *bh) + CPIN_32(rg, str, rg_free); + CPIN_32(rg, str, rg_dinodes); + +- CPIN_08(rg, str, rg_reserved, 80); ++ CPIN_08(rg, str, rg_reserved, sizeof(rg->rg_reserved)); + } + + void gfs2_rgrp_out(const struct gfs2_rgrp *rg, char *buf) +@@ -240,7 +240,7 @@ void gfs2_rgrp_out(const struct gfs2_rgrp *rg, char *buf) + CPOUT_32(rg, str, rg_free); + CPOUT_32(rg, str, rg_dinodes); + +- CPOUT_08(rg, str, rg_reserved, 80); ++ CPOUT_08(rg, str, rg_reserved, sizeof(rg->rg_reserved)); + } + + void gfs2_rgrp_out_bh(const struct gfs2_rgrp *rg, struct gfs2_buffer_head *bh) diff --git a/SOURCES/bz1487726-2-fsck_gfs2_Disambiguate_check_data.patch b/SOURCES/bz1487726-2-fsck_gfs2_Disambiguate_check_data.patch new file mode 100644 index 0000000..36c7905 --- /dev/null +++ b/SOURCES/bz1487726-2-fsck_gfs2_Disambiguate_check_data.patch @@ -0,0 +1,65 @@ +commit 0b04ce1ec5309002b5990e300c46a806421a8503 +Author: Andrew Price +Date: Tue Jun 4 17:16:18 2019 +0100 + + fsck.gfs2: Disambiguate 'check_data' + + Having several functions with this name confuses profiling tools and + makes reports difficult to read. Give the different check_data + functions better names. + + Signed-off-by: Andrew Price + +diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c +index 4d6dcfae..a334180f 100644 +--- a/gfs2/fsck/metawalk.c ++++ b/gfs2/fsck/metawalk.c +@@ -1390,7 +1390,7 @@ error_undo: /* undo what we've done so far for this block */ + * 1 if errors were found and corrected + * 2 (ENOENT) is there were too many bad pointers + */ +-static int check_data(struct gfs2_inode *ip, struct metawalk_fxns *pass, ++static int metawalk_check_data(struct gfs2_inode *ip, struct metawalk_fxns *pass, + struct gfs2_buffer_head *bh, int head_size, + uint64_t *blks_checked, struct error_block *error_blk) + { +@@ -1589,7 +1589,7 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass) + continue; + + if (pass->check_data) +- error = check_data(ip, pass, bh, head_size, ++ error = metawalk_check_data(ip, pass, bh, head_size, + &blks_checked, &error_blk); + if (pass->big_file_msg && ip->i_di.di_blocks > COMFORTABLE_BLKS) + pass->big_file_msg(ip, blks_checked); +diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c +index 6f04109b..c7de3e39 100644 +--- a/gfs2/fsck/pass1.c ++++ b/gfs2/fsck/pass1.c +@@ -44,7 +44,7 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block, + int *was_duplicate, void *private); + 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, ++static int pass1_check_data(struct gfs2_inode *ip, uint64_t metablock, + 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, +@@ -192,7 +192,7 @@ struct metawalk_fxns pass1_fxns = { + .private = NULL, + .check_leaf = p1check_leaf, + .check_metalist = check_metalist, +- .check_data = check_data, ++ .check_data = pass1_check_data, + .check_eattr_indir = check_eattr_indir, + .check_eattr_leaf = check_eattr_leaf, + .check_dentry = NULL, +@@ -542,7 +542,7 @@ out: + return error; + } + +-static int check_data(struct gfs2_inode *ip, uint64_t metablock, ++static int pass1_check_data(struct gfs2_inode *ip, uint64_t metablock, + uint64_t block, void *private, + struct gfs2_buffer_head *bbh, uint64_t *ptr) + { diff --git a/SOURCES/bz1487726-3-gfs2_utils_Accept_a_char_instead_of_a_buffer_head_in_gfs2_check_meta.patch b/SOURCES/bz1487726-3-gfs2_utils_Accept_a_char_instead_of_a_buffer_head_in_gfs2_check_meta.patch new file mode 100644 index 0000000..d931ea5 --- /dev/null +++ b/SOURCES/bz1487726-3-gfs2_utils_Accept_a_char_instead_of_a_buffer_head_in_gfs2_check_meta.patch @@ -0,0 +1,444 @@ +commit 2c070ddf1f552e459d8cb7e08e404b56480353df +Author: Andrew Price +Date: Mon Jan 28 15:50:51 2019 +0000 + + gfs2-utils: Accept a char* instead of a buffer head in gfs2_check_meta + + This allows us to call it from different contexts. + + Signed-off-by: Andrew Price + +diff --git a/gfs2/convert/gfs2_convert.c b/gfs2/convert/gfs2_convert.c +index 98450493..d13a5252 100644 +--- a/gfs2/convert/gfs2_convert.c ++++ b/gfs2/convert/gfs2_convert.c +@@ -832,7 +832,7 @@ static int fix_xattr(struct gfs2_sbd *sbp, struct gfs2_buffer_head *bh, struct g + + /* Read in the i_di.di_eattr block */ + eabh = bread(sbp, ip->i_di.di_eattr); +- if (!gfs2_check_meta(eabh, GFS_METATYPE_IN)) {/* if it is an indirect block */ ++ if (!gfs2_check_meta(eabh->b_data, GFS_METATYPE_IN)) {/* if it is an indirect block */ + len = sbp->bsize - sizeof(struct gfs_indirect); + buf = malloc(len); + if (!buf) { +@@ -1008,7 +1008,7 @@ static int next_rg_metatype(struct gfs2_sbd *sdp, struct rgrp_tree *rgd, + return -1; + bh = bread(sdp, *block); + first = 0; +- } while(gfs2_check_meta(bh, type)); ++ } while(gfs2_check_meta(bh->b_data, type)); + brelse(bh); + return 0; + } +@@ -1068,7 +1068,7 @@ static int inode_renumber(struct gfs2_sbd *sbp, uint64_t root_inode_addr, osi_li + sbp->sd_sb.sb_root_dir.no_formal_ino = sbp->md.next_inum; + } + bh = bread(sbp, block); +- if (!gfs2_check_meta(bh, GFS_METATYPE_DI)) {/* if it is an dinode */ ++ if (!gfs2_check_meta(bh->b_data, GFS_METATYPE_DI)) {/* if it is an dinode */ + /* Skip the rindex and jindex inodes for now. */ + if (block != rindex_addr && block != jindex_addr) { + error = adjust_inode(sbp, bh); +diff --git a/gfs2/edit/hexedit.c b/gfs2/edit/hexedit.c +index b67fde2d..923d6b43 100644 +--- a/gfs2/edit/hexedit.c ++++ b/gfs2/edit/hexedit.c +@@ -1274,7 +1274,7 @@ static int find_rg_metatype(struct rgrp_tree *rgd, uint64_t *blk, uint64_t start + for (j = 0; j < m; j++) { + *blk = ibuf[j]; + bhp = bread(&sbd, *blk); +- found = (*blk > startblk) && !gfs2_check_meta(bhp, mtype); ++ found = (*blk > startblk) && !gfs2_check_meta(bhp->b_data, mtype); + brelse(bhp); + if (found) { + free(ibuf); +@@ -2279,7 +2279,7 @@ static int count_dinode_blks(struct rgrp_tree *rgd, int bitmap, + rgd->bits[bitmap].bi_start + b); + byte = rbh->b_data + off + (b / GFS2_NBBY); + bit = (b % GFS2_NBBY) * GFS2_BIT_SIZE; +- if (gfs2_check_meta(tbh, GFS2_METATYPE_DI) == 0) { ++ if (gfs2_check_meta(tbh->b_data, GFS2_METATYPE_DI) == 0) { + dinodes++; + new_state = GFS2_BLKST_DINODE; + } else { +@@ -2350,7 +2350,7 @@ static void rg_repair(void) + + printf("Bitmap #%d:", b); + rbh = bread(&sbd, rgd->ri.ri_addr + b); +- if (gfs2_check_meta(rbh, mtype)) { /* wrong type */ ++ if (gfs2_check_meta(rbh->b_data, mtype)) { /* wrong type */ + printf("Damaged. Repairing..."); + /* Fix the meta header */ + memset(rbh->b_data, 0, sbd.bsize); +diff --git a/gfs2/edit/savemeta.c b/gfs2/edit/savemeta.c +index 04f67fc7..1065e407 100644 +--- a/gfs2/edit/savemeta.c ++++ b/gfs2/edit/savemeta.c +@@ -567,7 +567,7 @@ static int save_leaf_chain(struct metafd *mfd, struct gfs2_sbd *sdp, uint64_t bl + return 1; + } + warm_fuzzy_stuff(blk, FALSE); +- if (gfs2_check_meta(bh, GFS2_METATYPE_LF) == 0) { ++ if (gfs2_check_meta(bh->b_data, GFS2_METATYPE_LF) == 0) { + int ret = save_bh(mfd, bh, blk, NULL); + if (ret != 0) { + brelse(bh); +diff --git a/gfs2/fsck/fs_recovery.c b/gfs2/fsck/fs_recovery.c +index 17b2a3ab..3acbb5d7 100644 +--- a/gfs2/fsck/fs_recovery.c ++++ b/gfs2/fsck/fs_recovery.c +@@ -211,7 +211,7 @@ static int revoke_lo_scan_elements(struct gfs2_inode *ip, unsigned int start, + return error; + + if (!first) { +- if (gfs2_check_meta(bh, GFS2_METATYPE_LB)) ++ if (gfs2_check_meta(bh->b_data, GFS2_METATYPE_LB)) + continue; + } + while (offset + sizeof(uint64_t) <= sdp->sd_sb.sb_bsize) { +@@ -355,7 +355,7 @@ static int foreach_descriptor(struct gfs2_inode *ip, unsigned int start, + bmodified(bh); + brelse(bh); + return error; +- } else if (gfs2_check_meta(bh, GFS2_METATYPE_LD)) { ++ } else if (gfs2_check_meta(bh->b_data, GFS2_METATYPE_LD)) { + bmodified(bh); + brelse(bh); + return -EIO; +@@ -649,7 +649,7 @@ static int rangecheck_jmeta(struct gfs2_inode *ip, uint64_t block, + rc = rangecheck_jblock(ip, block); + if (rc == meta_is_good) { + *bh = bread(ip->i_sbd, block); +- *is_valid = (gfs2_check_meta(*bh, GFS2_METATYPE_IN) == 0); ++ *is_valid = (gfs2_check_meta((*bh)->b_data, GFS2_METATYPE_IN) == 0); + if (!(*is_valid)) { + log_err( _("Journal at block %lld (0x%llx) has a bad " + "indirect block pointer %lld (0x%llx) " +diff --git a/gfs2/fsck/initialize.c b/gfs2/fsck/initialize.c +index 4e323ffa..5720c095 100644 +--- a/gfs2/fsck/initialize.c ++++ b/gfs2/fsck/initialize.c +@@ -243,7 +243,7 @@ static void check_rgrp_integrity(struct gfs2_sbd *sdp, struct rgrp_tree *rgd, + if (state == GFS2_BLKST_DINODE) { + if (sdp->gfs1) { + bh = bread(sdp, diblock); +- if (!gfs2_check_meta(bh, ++ if (!gfs2_check_meta(bh->b_data, + GFS2_METATYPE_DI)) + rg_useddi++; + else +@@ -298,7 +298,7 @@ static void check_rgrp_integrity(struct gfs2_sbd *sdp, struct rgrp_tree *rgd, + (unsigned long long)diblock, + (unsigned long long)diblock); + bh = bread(sdp, diblock); +- if (!gfs2_check_meta(bh, GFS2_METATYPE_DI)) { ++ if (!gfs2_check_meta(bh->b_data, GFS2_METATYPE_DI)) { + struct gfs2_inode *ip = + fsck_inode_get(sdp, rgd, bh); + if (ip->i_di.di_blocks > 1) { +@@ -1169,7 +1169,7 @@ static int peruse_metadata(struct gfs2_sbd *sdp, uint64_t startblock) + /* Max RG size is 2GB. 2G / bsize. */ + for (blk = startblock; blk < startblock + max_rg_size; blk++) { + bh = bread(sdp, blk); +- if (gfs2_check_meta(bh, GFS2_METATYPE_DI)) { ++ if (gfs2_check_meta(bh->b_data, GFS2_METATYPE_DI)) { + brelse(bh); + continue; + } +diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c +index a334180f..4d6a2d2c 100644 +--- a/gfs2/fsck/metawalk.c ++++ b/gfs2/fsck/metawalk.c +@@ -559,7 +559,7 @@ int check_leaf(struct gfs2_inode *ip, int lindex, struct metawalk_fxns *pass, + /* Try to read in the leaf block. */ + lbh = bread(sdp, *leaf_no); + /* Make sure it's really a valid leaf block. */ +- if (gfs2_check_meta(lbh, GFS2_METATYPE_LF)) { ++ if (gfs2_check_meta(lbh->b_data, GFS2_METATYPE_LF)) { + msg = _("that is not really a leaf"); + goto bad_leaf; + } +@@ -768,7 +768,7 @@ int check_leaf_blks(struct gfs2_inode *ip, struct metawalk_fxns *pass) + if (valid_block_ip(ip, leaf_no)) { + lbh = bread(sdp, leaf_no); + /* Make sure it's really a valid leaf block. */ +- if (gfs2_check_meta(lbh, GFS2_METATYPE_LF) == 0) { ++ if (gfs2_check_meta(lbh->b_data, GFS2_METATYPE_LF) == 0) { + brelse(lbh); + first_ok_leaf = leaf_no; + break; +@@ -1268,7 +1268,7 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp, + for (tmp = prev_list->next; tmp != prev_list; tmp = tmp->next){ + bh = osi_list_entry(tmp, struct gfs2_buffer_head, + b_altlist); +- if (gfs2_check_meta(bh, iblk_type)) { ++ if (gfs2_check_meta(bh->b_data, iblk_type)) { + if (pass->invalid_meta_is_fatal) + return meta_error; + +@@ -1513,7 +1513,7 @@ static int undo_check_data(struct gfs2_inode *ip, struct metawalk_fxns *pass, + static int hdr_size(struct gfs2_buffer_head *bh, int height) + { + if (height > 1) { +- if (gfs2_check_meta(bh, GFS2_METATYPE_IN)) ++ if (gfs2_check_meta(bh->b_data, GFS2_METATYPE_IN)) + return 0; + if (bh->sdp->gfs1) + return sizeof(struct gfs_indirect); +@@ -1521,7 +1521,7 @@ static int hdr_size(struct gfs2_buffer_head *bh, int height) + return sizeof(struct gfs2_meta_header); + } + /* if this isn't really a dinode, skip it */ +- if (gfs2_check_meta(bh, GFS2_METATYPE_DI)) ++ if (gfs2_check_meta(bh->b_data, GFS2_METATYPE_DI)) + return 0; + + return sizeof(struct gfs2_dinode); +diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c +index c7de3e39..0b59971d 100644 +--- a/gfs2/fsck/pass1.c ++++ b/gfs2/fsck/pass1.c +@@ -393,7 +393,7 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block, + } + nbh = bread(ip->i_sbd, block); + +- *is_valid = (gfs2_check_meta(nbh, iblk_type) == 0); ++ *is_valid = (gfs2_check_meta(nbh->b_data, iblk_type) == 0); + + if (!(*is_valid)) { + log_err( _("Inode %lld (0x%llx) has a bad indirect block " +@@ -519,7 +519,7 @@ static int blockmap_set_as_data(struct gfs2_inode *ip, uint64_t block) + /* The bitmap says it's a dinode, but a block reference begs to differ. + So which is it? */ + bh = bread(ip->i_sbd, block); +- if (gfs2_check_meta(bh, GFS2_METATYPE_DI) != 0) ++ if (gfs2_check_meta(bh->b_data, GFS2_METATYPE_DI) != 0) + goto out; + + /* The meta header agrees it's a dinode. But it might be data in +@@ -747,7 +747,7 @@ static int check_eattr_indir(struct gfs2_inode *ip, uint64_t indirect, + handling sort it out. If it isn't, clear it but don't + count it as a duplicate. */ + *bh = bread(sdp, indirect); +- if (gfs2_check_meta(*bh, GFS2_METATYPE_IN)) { ++ if (gfs2_check_meta((*bh)->b_data, GFS2_METATYPE_IN)) { + bc->ea_count++; + if (q != GFS2_BLKST_FREE) { /* Duplicate? */ + add_duplicate_ref(ip, indirect, ref_as_ea, 0, +@@ -829,7 +829,7 @@ static int check_ealeaf_block(struct gfs2_inode *ip, uint64_t block, int btype, + really is an EA. If it is, let duplicate handling sort it out. + If it isn't, clear it but don't count it as a duplicate. */ + leaf_bh = bread(sdp, block); +- if (gfs2_check_meta(leaf_bh, btype)) { ++ if (gfs2_check_meta(leaf_bh->b_data, btype)) { + bc->ea_count++; + if (q != GFS2_BLKST_FREE) { /* Duplicate? */ + add_duplicate_ref(ip, block, ref_as_ea, 0, +@@ -1666,7 +1666,7 @@ static int check_system_inode(struct gfs2_sbd *sdp, + " (0x%llx)\n"), filename, + (unsigned long long)iblock, + (unsigned long long)iblock); +- if (gfs2_check_meta((*sysinode)->i_bh, GFS2_METATYPE_DI)) { ++ if (gfs2_check_meta((*sysinode)->i_bh->b_data, GFS2_METATYPE_DI)) { + log_err( _("Found invalid system dinode at block #" + "%llu (0x%llx)\n"), + (unsigned long long)iblock, +@@ -1935,7 +1935,7 @@ static int pass1_process_bitmap(struct gfs2_sbd *sdp, struct rgrp_tree *rgd, uin + bh = bread(sdp, block); + + is_inode = 0; +- if (gfs2_check_meta(bh, GFS2_METATYPE_DI) == 0) ++ if (gfs2_check_meta(bh->b_data, GFS2_METATYPE_DI) == 0) + is_inode = 1; + + check_magic = ((struct gfs2_meta_header *) +diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c +index abc2b960..d10b9089 100644 +--- a/gfs2/fsck/pass2.c ++++ b/gfs2/fsck/pass2.c +@@ -651,7 +651,7 @@ static int basic_dentry_checks(struct gfs2_inode *ip, struct gfs2_dirent *dent, + struct gfs2_buffer_head *tbh; + + tbh = bread(sdp, entry->no_addr); +- if (gfs2_check_meta(tbh, GFS2_METATYPE_DI)) { /* not dinode */ ++ if (gfs2_check_meta(tbh->b_data, GFS2_METATYPE_DI)) { /* not dinode */ + log_err( _("Directory entry '%s' pointing to block " + "%llu (0x%llx) in directory %llu (0x%llx) " + "is not really a GFS1 dinode.\n"), tmp_name, +@@ -1600,7 +1600,7 @@ static int check_hash_tbl_dups(struct gfs2_inode *ip, uint64_t *tbl, + continue; + + lbh = bread(ip->i_sbd, leafblk); +- if (gfs2_check_meta(lbh, GFS2_METATYPE_LF)) { /* Chked later */ ++ if (gfs2_check_meta(lbh->b_data, GFS2_METATYPE_LF)) { /* Chked later */ + brelse(lbh); + continue; + } +@@ -1794,7 +1794,7 @@ static int check_hash_tbl(struct gfs2_inode *ip, uint64_t *tbl, + proper_len, proper_len); + lbh = bread(ip->i_sbd, leafblk); + gfs2_leaf_in(&leaf, lbh); +- if (gfs2_check_meta(lbh, GFS2_METATYPE_LF) || ++ if (gfs2_check_meta(lbh->b_data, GFS2_METATYPE_LF) || + leaf.lf_depth > ip->i_di.di_depth) + leaf.lf_depth = factor; + brelse(lbh); +@@ -1895,7 +1895,7 @@ static int check_data_qc(struct gfs2_inode *ip, uint64_t metablock, + return -1; + + bh = bread(ip->i_sbd, block); +- if (gfs2_check_meta(bh, GFS2_METATYPE_QC) != 0) { ++ if (gfs2_check_meta(bh->b_data, GFS2_METATYPE_QC) != 0) { + log_crit(_("Error: quota_change block at %lld (0x%llx) is " + "the wrong metadata type.\n"), + (unsigned long long)block, (unsigned long long)block); +diff --git a/gfs2/fsck/pass5.c b/gfs2/fsck/pass5.c +index 554f39f9..6693daa5 100644 +--- a/gfs2/fsck/pass5.c ++++ b/gfs2/fsck/pass5.c +@@ -49,7 +49,7 @@ static int check_block_status(struct gfs2_sbd *sdp, struct gfs2_bmap *bl, + struct gfs2_buffer_head *bh; + + bh = bread(sdp, block); +- if (gfs2_check_meta(bh, GFS2_METATYPE_DI) == 0) ++ if (gfs2_check_meta(bh->b_data, GFS2_METATYPE_DI) == 0) + count[GFS2_BLKST_DINODE]++; + else + count[GFS1_BLKST_USEDMETA]++; +diff --git a/gfs2/fsck/rgrepair.c b/gfs2/fsck/rgrepair.c +index f397db1c..9a914615 100644 +--- a/gfs2/fsck/rgrepair.c ++++ b/gfs2/fsck/rgrepair.c +@@ -71,7 +71,7 @@ static void find_journaled_rgs(struct gfs2_sbd *sdp) + if (!dblock) + break; + bh = bread(sdp, dblock); +- if (!gfs2_check_meta(bh, GFS2_METATYPE_RG)) { ++ if (!gfs2_check_meta(bh->b_data, GFS2_METATYPE_RG)) { + /* False rgrp found at block dblock */ + false_count++; + gfs2_special_set(&false_rgrps, dblock); +@@ -128,7 +128,7 @@ static int find_shortest_rgdist(struct gfs2_sbd *sdp, uint64_t *dist_array, + is_rgrp = 0; + else { + bh = bread(sdp, blk); +- is_rgrp = (gfs2_check_meta(bh, GFS2_METATYPE_RG) == 0); ++ is_rgrp = (gfs2_check_meta(bh->b_data, GFS2_METATYPE_RG) == 0); + brelse(bh); + } + if (!is_rgrp) { +@@ -146,7 +146,7 @@ static int find_shortest_rgdist(struct gfs2_sbd *sdp, uint64_t *dist_array, + is_rgrp = 0; + } else { + bh = bread(sdp, nblk); +- is_rgrp = (((gfs2_check_meta(bh, ++ is_rgrp = (((gfs2_check_meta(bh->b_data, + GFS2_METATYPE_RG) == 0))); + brelse(bh); + } +@@ -562,7 +562,7 @@ static int gfs2_rindex_rebuild(struct gfs2_sbd *sdp, int *num_rgs, + while (blk <= sdp->device.length) { + log_debug( _("Block 0x%llx\n"), (unsigned long long)blk); + bh = bread(sdp, blk); +- rg_was_fnd = (!gfs2_check_meta(bh, GFS2_METATYPE_RG)); ++ rg_was_fnd = (!gfs2_check_meta(bh->b_data, GFS2_METATYPE_RG)); + brelse(bh); + /* Allocate a new RG and index. */ + calc_rgd = rgrp_insert(&sdp->rgcalc, blk); +@@ -594,7 +594,7 @@ static int gfs2_rindex_rebuild(struct gfs2_sbd *sdp, int *num_rgs, + for (fwd_block = blk + 1; fwd_block < sdp->device.length; fwd_block++) { + int bitmap_was_fnd; + bh = bread(sdp, fwd_block); +- bitmap_was_fnd = !gfs2_check_meta(bh, GFS2_METATYPE_RB); ++ bitmap_was_fnd = !gfs2_check_meta(bh->b_data, GFS2_METATYPE_RB); + brelse(bh); + if (bitmap_was_fnd) /* if a bitmap */ + calc_rgd->ri.ri_length++; +diff --git a/gfs2/libgfs2/fs_ops.c b/gfs2/libgfs2/fs_ops.c +index 3acfb67f..f796c763 100644 +--- a/gfs2/libgfs2/fs_ops.c ++++ b/gfs2/libgfs2/fs_ops.c +@@ -883,7 +883,7 @@ void dirent2_del(struct gfs2_inode *dip, struct gfs2_buffer_head *bh, + uint16_t cur_rec_len, prev_rec_len; + + bmodified(bh); +- if (gfs2_check_meta(bh, GFS2_METATYPE_LF) == 0) { ++ if (gfs2_check_meta(bh->b_data, GFS2_METATYPE_LF) == 0) { + struct gfs2_leaf *lf = (struct gfs2_leaf *)bh->b_data; + + lf->lf_entries = be16_to_cpu(lf->lf_entries) - 1; +@@ -1102,7 +1102,7 @@ int gfs2_get_leaf(struct gfs2_inode *dip, uint64_t leaf_no, + int error = 0; + + *bhp = bread(dip->i_sbd, leaf_no); +- error = gfs2_check_meta(*bhp, GFS2_METATYPE_LF); ++ error = gfs2_check_meta((*bhp)->b_data, GFS2_METATYPE_LF); + if(error) + brelse(*bhp); + return error; +@@ -1154,7 +1154,7 @@ static int get_next_leaf(struct gfs2_inode *dip,struct gfs2_buffer_head *bh_in, + if (*bh_out == NULL) + return -ENOENT; + /* Check for a leaf pointing to a non-leaf */ +- if (gfs2_check_meta(*bh_out, GFS2_METATYPE_LF)) { ++ if (gfs2_check_meta((*bh_out)->b_data, GFS2_METATYPE_LF)) { + brelse(*bh_out); + *bh_out = NULL; + return -ENOENT; +diff --git a/gfs2/libgfs2/libgfs2.h b/gfs2/libgfs2/libgfs2.h +index 570c89b9..228ecebd 100644 +--- a/gfs2/libgfs2/libgfs2.h ++++ b/gfs2/libgfs2/libgfs2.h +@@ -696,7 +696,7 @@ extern int build_quota(struct gfs2_sbd *sdp); + extern int build_root(struct gfs2_sbd *sdp); + extern int do_init_inum(struct gfs2_sbd *sdp); + extern int do_init_statfs(struct gfs2_sbd *sdp); +-extern int gfs2_check_meta(struct gfs2_buffer_head *bh, int type); ++extern int gfs2_check_meta(const char *buf, int type); + extern unsigned lgfs2_bm_scan(struct rgrp_tree *rgd, unsigned idx, + uint64_t *buf, uint8_t state); + extern int build_inum_range(struct gfs2_inode *per_node, unsigned int j); +diff --git a/gfs2/libgfs2/rgrp.c b/gfs2/libgfs2/rgrp.c +index bb0776aa..0040d6dc 100644 +--- a/gfs2/libgfs2/rgrp.c ++++ b/gfs2/libgfs2/rgrp.c +@@ -184,7 +184,7 @@ uint64_t gfs2_rgrp_read(struct gfs2_sbd *sdp, struct rgrp_tree *rgd) + int mtype = (x ? GFS2_METATYPE_RB : GFS2_METATYPE_RG); + + bi->bi_bh = bhs[x]; +- if (gfs2_check_meta(bi->bi_bh, mtype)) { ++ if (gfs2_check_meta(bi->bi_bh->b_data, mtype)) { + unsigned err = x; + do { + brelse(rgd->bits[x].bi_bh); +diff --git a/gfs2/libgfs2/structures.c b/gfs2/libgfs2/structures.c +index 1cc88b50..208aa5dd 100644 +--- a/gfs2/libgfs2/structures.c ++++ b/gfs2/libgfs2/structures.c +@@ -593,10 +593,10 @@ int do_init_statfs(struct gfs2_sbd *sdp) + return 0; + } + +-int gfs2_check_meta(struct gfs2_buffer_head *bh, int type) ++int gfs2_check_meta(const char *buf, int type) + { +- uint32_t check_magic = ((struct gfs2_meta_header *)(bh->b_data))->mh_magic; +- uint32_t check_type = ((struct gfs2_meta_header *)(bh->b_data))->mh_type; ++ uint32_t check_magic = ((struct gfs2_meta_header *)buf)->mh_magic; ++ uint32_t check_type = ((struct gfs2_meta_header *)buf)->mh_type; + + check_magic = be32_to_cpu(check_magic); + check_type = be32_to_cpu(check_type); +diff --git a/gfs2/libgfs2/super.c b/gfs2/libgfs2/super.c +index cc9679f5..51657543 100644 +--- a/gfs2/libgfs2/super.c ++++ b/gfs2/libgfs2/super.c +@@ -182,7 +182,7 @@ static int good_on_disk(struct gfs2_sbd *sdp, struct rgrp_tree *rgd) + int is_rgrp; + + bh = bread(sdp, rgd->ri.ri_addr); +- is_rgrp = (gfs2_check_meta(bh, GFS2_METATYPE_RG) == 0); ++ is_rgrp = (gfs2_check_meta(bh->b_data, GFS2_METATYPE_RG) == 0); + brelse(bh); + return is_rgrp; + } diff --git a/SOURCES/bz1487726-4-fsck_gfs2_Disambiguate_check_metalist.patch b/SOURCES/bz1487726-4-fsck_gfs2_Disambiguate_check_metalist.patch new file mode 100644 index 0000000..38c9107 --- /dev/null +++ b/SOURCES/bz1487726-4-fsck_gfs2_Disambiguate_check_metalist.patch @@ -0,0 +1,41 @@ +commit 9b201fd8c20a27d5802862ed63e895b5e4204b3e +Author: Andrew Price +Date: Fri Jun 14 11:41:03 2019 +0100 + + fsck.gfs2: Disambiguate check_metalist + + Rename to pass1_check_metalist + + Signed-off-by: Andrew Price + +diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c +index 0b59971d..f03078e9 100644 +--- a/gfs2/fsck/pass1.c ++++ b/gfs2/fsck/pass1.c +@@ -39,7 +39,7 @@ struct block_count { + }; + + static int p1check_leaf(struct gfs2_inode *ip, uint64_t block, void *private); +-static int check_metalist(struct gfs2_inode *ip, uint64_t block, ++static int pass1_check_metalist(struct gfs2_inode *ip, uint64_t block, + struct gfs2_buffer_head **bh, int h, int *is_valid, + int *was_duplicate, void *private); + static int undo_check_metalist(struct gfs2_inode *ip, uint64_t block, +@@ -191,7 +191,7 @@ out: + struct metawalk_fxns pass1_fxns = { + .private = NULL, + .check_leaf = p1check_leaf, +- .check_metalist = check_metalist, ++ .check_metalist = pass1_check_metalist, + .check_data = pass1_check_data, + .check_eattr_indir = check_eattr_indir, + .check_eattr_leaf = check_eattr_leaf, +@@ -344,7 +344,7 @@ static int p1check_leaf(struct gfs2_inode *ip, uint64_t block, void *private) + return 0; + } + +-static int check_metalist(struct gfs2_inode *ip, uint64_t block, ++static int pass1_check_metalist(struct gfs2_inode *ip, uint64_t block, + struct gfs2_buffer_head **bh, int h, int *is_valid, + int *was_duplicate, void *private) + { diff --git a/SOURCES/bz1487726-5-fsck_gfs2_Fix_segfault_in_build_and_check_metalist.patch b/SOURCES/bz1487726-5-fsck_gfs2_Fix_segfault_in_build_and_check_metalist.patch new file mode 100644 index 0000000..c630c90 --- /dev/null +++ b/SOURCES/bz1487726-5-fsck_gfs2_Fix_segfault_in_build_and_check_metalist.patch @@ -0,0 +1,167 @@ +commit ab1c367459b5fd71eb80ad40645f25c21b95e70d +Author: Andrew Price +Date: Fri Oct 18 16:07:44 2019 +0100 + + fsck.gfs2: Fix segfault in build_and_check_metalist + + In unlikely circumstances, indirect pointer corruption in a 'system' + inode's metadata tree can lead to the inode block state being marked as + 'free' in pass1, which causes build_and_check_metalist() to be called in + pass 2. The pass has a NULL ->check_metalist function pointer and so a + segfault occurs when build_and_check_metalist attempts to call it. + + Fix the segfault by calling ->check_metalist() only when it's not NULL. + This required some refactoring to make the extra level of if-nesting + easier to implement and read. + + Resolves: rhbz#1487726 + + Signed-off-by: Andrew Price + +diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c +index 4d6a2d2c..dbe9f1f6 100644 +--- a/gfs2/fsck/metawalk.c ++++ b/gfs2/fsck/metawalk.c +@@ -1207,6 +1207,51 @@ static void file_ra(struct gfs2_inode *ip, struct gfs2_buffer_head *bh, + extlen * sdp->bsize, POSIX_FADV_WILLNEED); + } + ++static int do_check_metalist(struct gfs2_inode *ip, uint64_t block, int height, ++ struct gfs2_buffer_head **bhp, struct metawalk_fxns *pass) ++{ ++ int was_duplicate = 0; ++ int is_valid = 1; ++ int error; ++ ++ if (pass->check_metalist == NULL) ++ return 0; ++ ++ error = pass->check_metalist(ip, block, bhp, height, &is_valid, ++ &was_duplicate, pass->private); ++ if (error == meta_error) { ++ stack; ++ log_info("\n"); ++ log_info(_("Serious metadata error on block %"PRIu64" (0x%"PRIx64").\n"), ++ block, block); ++ return error; ++ } ++ if (error == meta_skip_further) { ++ log_info("\n"); ++ log_info(_("Unrecoverable metadata error on block %"PRIu64" (0x%"PRIx64")\n"), ++ block, block); ++ log_info(_("Further metadata will be skipped.\n")); ++ return error; ++ } ++ if (!is_valid) { ++ log_debug("Skipping rejected block %"PRIu64" (0x%"PRIx64")\n", block, block); ++ if (pass->invalid_meta_is_fatal) ++ return meta_error; ++ return meta_skip_one; ++ } ++ if (was_duplicate) { ++ log_debug("Skipping duplicate %"PRIu64" (0x%"PRIx64")\n", block, block); ++ return meta_skip_one; ++ } ++ if (!valid_block_ip(ip, block)) { ++ log_debug("Skipping invalid block %"PRIu64" (0x%"PRIx64")\n", block, block); ++ if (pass->invalid_meta_is_fatal) ++ return meta_error; ++ return meta_skip_one; ++ } ++ return error; ++} ++ + /** + * build_and_check_metalist - check a bunch of indirect blocks + * This includes hash table blocks for directories +@@ -1226,8 +1271,8 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp, + osi_list_t *prev_list, *cur_list, *tmp; + int h, head_size, iblk_type; + uint64_t *ptr, block, *undoptr; +- int error, was_duplicate, is_valid; + int maxptrs; ++ int error; + + osi_list_add(&metabh->b_altlist, &mlp[0]); + +@@ -1291,65 +1336,11 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp, + continue; + + block = be64_to_cpu(*ptr); +- was_duplicate = 0; +- error = pass->check_metalist(ip, block, &nbh, +- h, &is_valid, +- &was_duplicate, +- pass->private); +- /* check_metalist should hold any buffers +- it gets with "bread". */ +- if (error == meta_error) { +- stack; +- log_info(_("\nSerious metadata " +- "error on block %llu " +- "(0x%llx).\n"), +- (unsigned long long)block, +- (unsigned long long)block); ++ error = do_check_metalist(ip, block, h, &nbh, pass); ++ if (error == meta_error || error == meta_skip_further) + goto error_undo; +- } +- if (error == meta_skip_further) { +- log_info(_("\nUnrecoverable metadata " +- "error on block %llu " +- "(0x%llx). Further metadata" +- " will be skipped.\n"), +- (unsigned long long)block, +- (unsigned long long)block); +- goto error_undo; +- } +- if (!is_valid) { +- log_debug( _("Skipping rejected block " +- "%llu (0x%llx)\n"), +- (unsigned long long)block, +- (unsigned long long)block); +- if (pass->invalid_meta_is_fatal) { +- error = meta_error; +- goto error_undo; +- } +- continue; +- } +- /* Note that there's a special case in which +- we need to process the metadata block, even +- if it was a duplicate. That's for cases +- where we deleted the last reference as +- metadata. */ +- if (was_duplicate) { +- log_debug( _("Skipping duplicate %llu " +- "(0x%llx)\n"), +- (unsigned long long)block, +- (unsigned long long)block); ++ if (error == meta_skip_one) + continue; +- } +- if (!valid_block_ip(ip, block)) { +- log_debug( _("Skipping invalid block " +- "%lld (0x%llx)\n"), +- (unsigned long long)block, +- (unsigned long long)block); +- if (pass->invalid_meta_is_fatal) { +- error = meta_error; +- goto error_undo; +- } +- continue; +- } + if (!nbh) + nbh = bread(ip->i_sbd, block); + osi_list_add_prev(&nbh->b_altlist, cur_list); +diff --git a/gfs2/fsck/metawalk.h b/gfs2/fsck/metawalk.h +index 119efeed..b5a037a3 100644 +--- a/gfs2/fsck/metawalk.h ++++ b/gfs2/fsck/metawalk.h +@@ -39,6 +39,7 @@ enum meta_check_rc { + meta_error = -1, + meta_is_good = 0, + meta_skip_further = 1, ++ meta_skip_one = 2, + }; + + /* metawalk_fxns: function pointers to check various parts of the fs diff --git a/SOURCES/bz1487726-6-fsck_gfs2_Retain_context_for_indirect_pointers_in_check_metalist.patch b/SOURCES/bz1487726-6-fsck_gfs2_Retain_context_for_indirect_pointers_in_check_metalist.patch new file mode 100644 index 0000000..d010923 --- /dev/null +++ b/SOURCES/bz1487726-6-fsck_gfs2_Retain_context_for_indirect_pointers_in_check_metalist.patch @@ -0,0 +1,423 @@ +commit 5cf083a5c231bfe0950a276aff9249dd63f708d3 +Author: Andrew Price +Date: Fri Oct 18 19:16:08 2019 +0100 + + fsck.gfs2: Retain context for indirect pointers in ->check_metalist + + When the pass->check_metalist() functions are called, the pointer is + thrown away and the function is just called with a block address, + meaning that ->check_metalist() is unable to fix the pointer itself if + it deems the block pointed to is garbage. + + Add an iptr structure which collects together the inode, the metadata + block buffer and the offset of the pointer in that buffer. The iptr is + now passed to ->check_metadata instead of the separate inode and block + address arguments. + + Resolves: rhbz#1487726 + + Signed-off-by: Andrew Price + +diff --git a/gfs2/fsck/afterpass1_common.c b/gfs2/fsck/afterpass1_common.c +index b7476408..55a6c76b 100644 +--- a/gfs2/fsck/afterpass1_common.c ++++ b/gfs2/fsck/afterpass1_common.c +@@ -175,10 +175,12 @@ int remove_dentry_from_dir(struct gfs2_sbd *sdp, uint64_t dir, + return error; + } + +-int delete_metadata(struct gfs2_inode *ip, uint64_t block, +- struct gfs2_buffer_head **bh, int h, int *is_valid, ++int delete_metadata(struct iptr iptr, struct gfs2_buffer_head **bh, int h, int *is_valid, + int *was_duplicate, void *private) + { ++ struct gfs2_inode *ip = iptr.ipt_ip; ++ uint64_t block = iptr_block(iptr); ++ + *is_valid = 1; + *was_duplicate = 0; + return delete_block_if_notdup(ip, block, bh, _("metadata"), +diff --git a/gfs2/fsck/afterpass1_common.h b/gfs2/fsck/afterpass1_common.h +index 829828f7..74b913f3 100644 +--- a/gfs2/fsck/afterpass1_common.h ++++ b/gfs2/fsck/afterpass1_common.h +@@ -2,9 +2,9 @@ + #define _AFTERPASS1_H + + #include "util.h" ++#include "metawalk.h" + +-extern int delete_metadata(struct gfs2_inode *ip, uint64_t block, +- struct gfs2_buffer_head **bh, int h, int *is_valid, ++extern int delete_metadata(struct iptr iptr, struct gfs2_buffer_head **bh, int h, int *is_valid, + 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, +diff --git a/gfs2/fsck/fs_recovery.c b/gfs2/fsck/fs_recovery.c +index 3acbb5d7..614c01ac 100644 +--- a/gfs2/fsck/fs_recovery.c ++++ b/gfs2/fsck/fs_recovery.c +@@ -636,11 +636,11 @@ static int rangecheck_jblock(struct gfs2_inode *ip, uint64_t block) + return meta_is_good; + } + +-static int rangecheck_jmeta(struct gfs2_inode *ip, uint64_t block, +- struct gfs2_buffer_head **bh, int h, +- int *is_valid, int *was_duplicate, +- void *private) ++static int rangecheck_jmeta(struct iptr iptr, struct gfs2_buffer_head **bh, int h, ++ int *is_valid, int *was_duplicate, void *private) + { ++ struct gfs2_inode *ip = iptr.ipt_ip; ++ uint64_t block = iptr_block(iptr); + int rc; + + *bh = NULL; +diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c +index dbe9f1f6..d91ed63a 100644 +--- a/gfs2/fsck/metawalk.c ++++ b/gfs2/fsck/metawalk.c +@@ -1207,9 +1207,11 @@ static void file_ra(struct gfs2_inode *ip, struct gfs2_buffer_head *bh, + extlen * sdp->bsize, POSIX_FADV_WILLNEED); + } + +-static int do_check_metalist(struct gfs2_inode *ip, uint64_t block, int height, +- struct gfs2_buffer_head **bhp, struct metawalk_fxns *pass) ++static int do_check_metalist(struct iptr iptr, int height, struct gfs2_buffer_head **bhp, ++ struct metawalk_fxns *pass) + { ++ struct gfs2_inode *ip = iptr.ipt_ip; ++ uint64_t block = iptr_block(iptr); + int was_duplicate = 0; + int is_valid = 1; + int error; +@@ -1217,7 +1219,7 @@ static int do_check_metalist(struct gfs2_inode *ip, uint64_t block, int height, + if (pass->check_metalist == NULL) + return 0; + +- error = pass->check_metalist(ip, block, bhp, height, &is_valid, ++ error = pass->check_metalist(iptr, bhp, height, &is_valid, + &was_duplicate, pass->private); + if (error == meta_error) { + stack; +@@ -1267,10 +1269,11 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp, + struct metawalk_fxns *pass) + { + uint32_t height = ip->i_di.di_height; +- struct gfs2_buffer_head *bh, *nbh, *metabh = ip->i_bh; ++ struct gfs2_buffer_head *metabh = ip->i_bh; + osi_list_t *prev_list, *cur_list, *tmp; ++ struct iptr iptr = { .ipt_ip = ip, 0}; + int h, head_size, iblk_type; +- uint64_t *ptr, block, *undoptr; ++ uint64_t *undoptr; + int maxptrs; + int error; + +@@ -1310,39 +1313,37 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp, + prev_list = &mlp[h - 1]; + cur_list = &mlp[h]; + +- for (tmp = prev_list->next; tmp != prev_list; tmp = tmp->next){ +- bh = osi_list_entry(tmp, struct gfs2_buffer_head, +- b_altlist); +- if (gfs2_check_meta(bh->b_data, iblk_type)) { ++ for (tmp = prev_list->next; tmp != prev_list; tmp = tmp->next) { ++ iptr.ipt_off = head_size; ++ iptr.ipt_bh = osi_list_entry(tmp, struct gfs2_buffer_head, b_altlist); ++ ++ if (gfs2_check_meta(iptr_buf(iptr), iblk_type)) { + if (pass->invalid_meta_is_fatal) + return meta_error; + + continue; + } +- + if (pass->readahead) +- file_ra(ip, bh, head_size, maxptrs, h); ++ file_ra(ip, iptr.ipt_bh, head_size, maxptrs, h); ++ + /* Now check the metadata itself */ +- for (ptr = (uint64_t *)(bh->b_data + head_size); +- (char *)ptr < (bh->b_data + ip->i_sbd->bsize); +- ptr++) { ++ for (; iptr.ipt_off < ip->i_sbd->bsize; iptr.ipt_off += sizeof(uint64_t)) { ++ struct gfs2_buffer_head *nbh = NULL; ++ + if (skip_this_pass || fsck_abort) { + free_metalist(ip, mlp); + return meta_is_good; + } +- nbh = NULL; +- +- if (!*ptr) ++ if (!iptr_block(iptr)) + continue; + +- block = be64_to_cpu(*ptr); +- error = do_check_metalist(ip, block, h, &nbh, pass); ++ error = do_check_metalist(iptr, h, &nbh, pass); + if (error == meta_error || error == meta_skip_further) + goto error_undo; + if (error == meta_skip_one) + continue; + if (!nbh) +- nbh = bread(ip->i_sbd, block); ++ nbh = bread(ip->i_sbd, iptr_block(iptr)); + osi_list_add_prev(&nbh->b_altlist, cur_list); + } /* for all data on the indirect block */ + } /* for blocks at that height */ +@@ -1353,16 +1354,16 @@ error_undo: /* undo what we've done so far for this block */ + if (pass->undo_check_meta == NULL) + return error; + +- log_info(_("Undoing the work we did before the error on block %llu " +- "(0x%llx).\n"), (unsigned long long)bh->b_blocknr, +- (unsigned long long)bh->b_blocknr); +- for (undoptr = (uint64_t *)(bh->b_data + head_size); undoptr < ptr && +- (char *)undoptr < (bh->b_data + ip->i_sbd->bsize); ++ log_info(_("Undoing the work we did before the error on block %"PRIu64" (0x%"PRIx64").\n"), ++ iptr.ipt_bh->b_blocknr, iptr.ipt_bh->b_blocknr); ++ for (undoptr = (uint64_t *)(iptr_buf(iptr) + head_size); ++ undoptr < iptr_ptr(iptr) && undoptr < iptr_endptr(iptr); + undoptr++) { +- if (!*undoptr) ++ uint64_t block = be64_to_cpu(*undoptr); ++ ++ if (block == 0) + continue; + +- block = be64_to_cpu(*undoptr); + pass->undo_check_meta(ip, block, h, pass->private); + } + return error; +diff --git a/gfs2/fsck/metawalk.h b/gfs2/fsck/metawalk.h +index b5a037a3..592479df 100644 +--- a/gfs2/fsck/metawalk.h ++++ b/gfs2/fsck/metawalk.h +@@ -42,6 +42,17 @@ enum meta_check_rc { + meta_skip_one = 2, + }; + ++struct iptr { ++ struct gfs2_inode *ipt_ip; ++ struct gfs2_buffer_head *ipt_bh; ++ unsigned ipt_off; ++}; ++ ++#define iptr_ptr(i) ((uint64_t *)(i.ipt_bh->b_data + i.ipt_off)) ++#define iptr_block(i) be64_to_cpu(*iptr_ptr(i)) ++#define iptr_endptr(i) ((uint64_t *)(iptr.ipt_bh->b_data + i.ipt_ip->i_sbd->bsize)) ++#define iptr_buf(i) (i.ipt_bh->b_data) ++ + /* metawalk_fxns: function pointers to check various parts of the fs + * + * The functions should return -1 on fatal errors, 1 if the block +@@ -66,7 +77,7 @@ struct metawalk_fxns { + int (*check_leaf) (struct gfs2_inode *ip, uint64_t block, + void *private); + /* parameters to the check_metalist sub-functions: +- ip: incore inode pointer ++ iptr: reference to the inode and its indirect pointer that we're analyzing + block: block number of the metadata block to be checked + bh: buffer_head to be returned + h: height +@@ -79,7 +90,7 @@ struct metawalk_fxns { + returns: 0 - everything is good, but there may be duplicates + 1 - skip further processing + */ +- int (*check_metalist) (struct gfs2_inode *ip, uint64_t block, ++ int (*check_metalist) (struct iptr iptr, + struct gfs2_buffer_head **bh, int h, + int *is_valid, int *was_duplicate, + void *private); +diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c +index f03078e9..66cf6dc6 100644 +--- a/gfs2/fsck/pass1.c ++++ b/gfs2/fsck/pass1.c +@@ -39,9 +39,8 @@ struct block_count { + }; + + static int p1check_leaf(struct gfs2_inode *ip, uint64_t block, void *private); +-static int pass1_check_metalist(struct gfs2_inode *ip, uint64_t block, +- struct gfs2_buffer_head **bh, int h, int *is_valid, +- int *was_duplicate, void *private); ++static int pass1_check_metalist(struct iptr iptr, struct gfs2_buffer_head **bh, int h, ++ int *is_valid, int *was_duplicate, void *private); + static int undo_check_metalist(struct gfs2_inode *ip, uint64_t block, + int h, void *private); + static int pass1_check_data(struct gfs2_inode *ip, uint64_t metablock, +@@ -69,10 +68,8 @@ static int check_extended_leaf_eattr(struct gfs2_inode *ip, int i, + 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, +- struct gfs2_buffer_head **bh, int h, +- int *is_valid, int *was_duplicate, +- void *private); ++static int invalidate_metadata(struct iptr iptr, struct gfs2_buffer_head **bh, int h, ++ int *is_valid, int *was_duplicate, void *private); + static int invalidate_leaf(struct gfs2_inode *ip, uint64_t block, + void *private); + static int invalidate_data(struct gfs2_inode *ip, uint64_t metablock, +@@ -223,12 +220,12 @@ struct metawalk_fxns invalidate_fxns = { + * marked "in use" by the bitmap. You don't want root's indirect blocks + * deleted, do you? Or worse, reused for lost+found. + */ +-static int resuscitate_metalist(struct gfs2_inode *ip, uint64_t block, +- struct gfs2_buffer_head **bh, int h, +- int *is_valid, int *was_duplicate, +- void *private) ++static int resuscitate_metalist(struct iptr iptr, struct gfs2_buffer_head **bh, int h, ++ int *is_valid, int *was_duplicate, void *private) + { + struct block_count *bc = (struct block_count *)private; ++ struct gfs2_inode *ip = iptr.ipt_ip; ++ uint64_t block = iptr_block(iptr); + + *is_valid = 1; + *was_duplicate = 0; +@@ -344,15 +341,16 @@ static int p1check_leaf(struct gfs2_inode *ip, uint64_t block, void *private) + return 0; + } + +-static int pass1_check_metalist(struct gfs2_inode *ip, uint64_t block, +- struct gfs2_buffer_head **bh, int h, int *is_valid, +- int *was_duplicate, void *private) ++static int pass1_check_metalist(struct iptr iptr, struct gfs2_buffer_head **bh, int h, ++ int *is_valid, int *was_duplicate, void *private) + { +- int q; +- int iblk_type; +- struct gfs2_buffer_head *nbh; + struct block_count *bc = (struct block_count *)private; ++ struct gfs2_inode *ip = iptr.ipt_ip; ++ uint64_t block = iptr_block(iptr); ++ struct gfs2_buffer_head *nbh; + const char *blktypedesc; ++ int iblk_type; ++ int q; + + *bh = NULL; + +@@ -1111,11 +1109,12 @@ static int mark_block_invalid(struct gfs2_inode *ip, uint64_t block, + return meta_is_good; + } + +-static int invalidate_metadata(struct gfs2_inode *ip, uint64_t block, +- struct gfs2_buffer_head **bh, int h, +- int *is_valid, int *was_duplicate, +- void *private) ++static int invalidate_metadata(struct iptr iptr, struct gfs2_buffer_head **bh, int h, ++ int *is_valid, int *was_duplicate, void *private) + { ++ struct gfs2_inode *ip = iptr.ipt_ip; ++ uint64_t block = iptr_block(iptr); ++ + *is_valid = 1; + *was_duplicate = 0; + return mark_block_invalid(ip, block, ref_as_meta, _("metadata"), +@@ -1214,11 +1213,12 @@ static int rangecheck_block(struct gfs2_inode *ip, uint64_t block, + return meta_is_good; + } + +-static int rangecheck_metadata(struct gfs2_inode *ip, uint64_t block, +- struct gfs2_buffer_head **bh, int h, +- int *is_valid, int *was_duplicate, +- void *private) ++static int rangecheck_metadata(struct iptr iptr, struct gfs2_buffer_head **bh, int h, ++ int *is_valid, int *was_duplicate, void *private) + { ++ struct gfs2_inode *ip = iptr.ipt_ip; ++ uint64_t block = iptr_block(iptr); ++ + *is_valid = 1; + *was_duplicate = 0; + return rangecheck_block(ip, block, bh, btype_meta, private); +@@ -1317,12 +1317,13 @@ static int set_ip_blockmap(struct gfs2_inode *ip) + return 0; + } + +-static int alloc_metalist(struct gfs2_inode *ip, uint64_t block, +- struct gfs2_buffer_head **bh, int h, int *is_valid, +- int *was_duplicate, void *private) ++static int alloc_metalist(struct iptr iptr, struct gfs2_buffer_head **bh, int h, ++ int *is_valid, int *was_duplicate, void *private) + { +- int q; + const char *desc = (const char *)private; ++ struct gfs2_inode *ip = iptr.ipt_ip; ++ uint64_t block = iptr_block(iptr); ++ int q; + + /* No need to range_check here--if it was added, it's in range. */ + /* We can't check the bitmap here because this function is called +diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c +index 62686fee..350902b4 100644 +--- a/gfs2/fsck/pass1b.c ++++ b/gfs2/fsck/pass1b.c +@@ -69,9 +69,8 @@ static void log_inode_reference(struct duptree *dt, osi_list_t *tmp, int inval) + (unsigned long long)dt->block, reftypestring); + } + +-static int findref_meta(struct gfs2_inode *ip, uint64_t block, +- struct gfs2_buffer_head **bh, int h, +- int *is_valid, int *was_duplicate, void *private) ++static int findref_meta(struct iptr iptr, struct gfs2_buffer_head **bh, int h, ++ int *is_valid, int *was_duplicate, void *private) + { + *is_valid = 1; + *was_duplicate = 0; +@@ -393,10 +392,12 @@ static void resolve_dup_references(struct gfs2_sbd *sdp, struct duptree *dt, + return; + } + +-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) ++static int clone_check_meta(struct iptr iptr, struct gfs2_buffer_head **bh, int h, ++ int *is_valid, int *was_duplicate, void *private) + { ++ struct gfs2_inode *ip = iptr.ipt_ip; ++ uint64_t block = iptr_block(iptr); ++ + *was_duplicate = 0; + *is_valid = 1; + *bh = bread(ip->i_sbd, block); +@@ -788,11 +789,12 @@ static int check_leaf_refs(struct gfs2_inode *ip, uint64_t block, + return add_duplicate_ref(ip, block, ref_as_meta, 1, INODE_VALID); + } + +-static int check_metalist_refs(struct gfs2_inode *ip, uint64_t block, +- struct gfs2_buffer_head **bh, int h, +- int *is_valid, int *was_duplicate, +- void *private) ++static int check_metalist_refs(struct iptr iptr, struct gfs2_buffer_head **bh, int h, ++ int *is_valid, int *was_duplicate, void *private) + { ++ struct gfs2_inode *ip = iptr.ipt_ip; ++ uint64_t block = iptr_block(iptr); ++ + *was_duplicate = 0; + *is_valid = 1; + return add_duplicate_ref(ip, block, ref_as_meta, 1, INODE_VALID); +diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c +index d10b9089..d80f3063 100644 +--- a/gfs2/fsck/pass2.c ++++ b/gfs2/fsck/pass2.c +@@ -1873,10 +1873,12 @@ struct metawalk_fxns pass2_fxns = { + .repair_leaf = pass2_repair_leaf, + }; + +-static int check_metalist_qc(struct gfs2_inode *ip, uint64_t block, +- struct gfs2_buffer_head **bh, int h, +- int *is_valid, int *was_duplicate, void *private) ++static int check_metalist_qc(struct iptr iptr, struct gfs2_buffer_head **bh, int h, ++ int *is_valid, int *was_duplicate, void *private) + { ++ struct gfs2_inode *ip = iptr.ipt_ip; ++ uint64_t block = iptr_block(iptr); ++ + *was_duplicate = 0; + *is_valid = 1; + *bh = bread(ip->i_sbd, block); diff --git a/SOURCES/bz1487726-7-fsck_gfs2_Clear_bad_indirect_block_pointers_when_bitmap_meets_expectations.patch b/SOURCES/bz1487726-7-fsck_gfs2_Clear_bad_indirect_block_pointers_when_bitmap_meets_expectations.patch new file mode 100644 index 0000000..21ed09e --- /dev/null +++ b/SOURCES/bz1487726-7-fsck_gfs2_Clear_bad_indirect_block_pointers_when_bitmap_meets_expectations.patch @@ -0,0 +1,51 @@ +commit 4707be4ee1e214cc420679650e1897b3b0817638 +Author: Andrew Price +Date: Fri Oct 18 19:43:48 2019 +0100 + + fsck.gfs2: Clear bad indirect block pointers when bitmap meets expectations + + This issue only occurs when an indirect pointer of a 'system' directory + points to an invalid block but the block's bitmap state is as expected. + If the block's state is not as expected, the corruption is fixed by an + earlier check. + + In this scenario, pass1_check_metalist() checks the type of a block and + compares it with what it expected the indirect pointer to point to. If + there is a metadata mismatch a bad indirect pointer is reported but the + entire inode is considered invalid, causing it to be removed later, or + rebuilt in the case of protected structures such as the root inode. + This is heavy-handed and the right thing to do is to zero the indirect + block pointer. + + Previously we had no access to the pointer block itself to update it in + pass1_check_metalist() but now that an iptr is passed in, it's just a + case of zeroing the pointer at the correct offset and marking the bh as + modified. This means that fsck.gfs2 can now fix bad indirect pointers of + the root directory without throwing away the entire directory tree. + + Resolves: rhbz#1487726 + + Signed-off-by: Andrew Price + +diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c +index 66cf6dc6..deef1425 100644 +--- a/gfs2/fsck/pass1.c ++++ b/gfs2/fsck/pass1.c +@@ -401,8 +401,15 @@ static int pass1_check_metalist(struct iptr iptr, struct gfs2_buffer_head **bh, + (unsigned long long)ip->i_di.di_num.no_addr, + (unsigned long long)block, + (unsigned long long)block, blktypedesc); +- brelse(nbh); +- return meta_skip_further; ++ if (query(_("Zero the indirect block pointer? (y/n) "))){ ++ *iptr_ptr(iptr) = 0; ++ bmodified(iptr.ipt_bh); ++ *is_valid = 1; ++ return meta_skip_one; ++ } else { ++ brelse(nbh); ++ return meta_skip_further; ++ } + } + + bc->indir_count++; diff --git a/SOURCES/bz1837640-1-gfs2_jadd_Handle_out_of_space_issues.patch b/SOURCES/bz1837640-1-gfs2_jadd_Handle_out_of_space_issues.patch new file mode 100644 index 0000000..8115fa0 --- /dev/null +++ b/SOURCES/bz1837640-1-gfs2_jadd_Handle_out_of_space_issues.patch @@ -0,0 +1,113 @@ +commit f65ec019aebc11d6a30cf9d4eb5f7a1fce4db3d3 +Author: Abhi Das +Date: Mon May 11 09:22:31 2020 -0500 + + gfs2_jadd: Handle out-of-space issues + + If gfs2_jadd runs out of disk space while adding journals, it does + not exit gracefully. It partially does its job and bails out when + it hits -ENOSPC. This leaves the metafs mounted and most likely a + corrupted filesystem that even fsck.gfs2 can't fix. + + This patch adds a pre-check that ensures that the journals requested + will fit in the available space before proceeding. Note that this is + not foolproof because gfs2_jadd operates on a mounted filesystem. + While it is required that the filesystem be idle (and mounted on only + one node) while gfs2_jadd is being run, there is nothing stopping a + user from having some I/O process competing with gfs2_jadd for disk + blocks and consequently crashing it. + + Resolves: rhbz#1837640 + + Signed-off-by: Abhi Das + +diff --git a/gfs2/mkfs/main_jadd.c b/gfs2/mkfs/main_jadd.c +index de5d9c53..948f67a1 100644 +--- a/gfs2/mkfs/main_jadd.c ++++ b/gfs2/mkfs/main_jadd.c +@@ -390,6 +390,8 @@ static void gather_info(struct gfs2_sbd *sdp, struct jadd_opts *opts) + exit(EXIT_FAILURE); + } + sdp->bsize = statbuf.f_bsize; ++ sdp->blks_total = statbuf.f_blocks; ++ sdp->blks_alloced = sdp->blks_total - statbuf.f_bfree; + } + + static void find_current_journals(struct jadd_opts *opts) +@@ -489,13 +491,43 @@ static void add_j(struct gfs2_sbd *sdp, struct jadd_opts *opts) + } + } + ++static int check_fit(struct gfs2_sbd *sdp, struct jadd_opts *opts) ++{ ++ /* Compute how much space we'll need for the new journals ++ * Number of blocks needed per added journal: ++ * 1 block for the ir inode ++ * 1 block for the sc inode ++ * for sizes of the qc and journal inodes, use lgfs2_space_for_data() ++ * to calculate. ++ */ ++ uint64_t blks_per_j, total_blks; ++ ++ blks_per_j = 1 + 1 + ++ lgfs2_space_for_data(sdp, sdp->bsize, sdp->qcsize << 20) + ++ lgfs2_space_for_data(sdp, sdp->bsize, sdp->jsize << 20); ++ total_blks = opts->journals * blks_per_j; ++ ++ if (total_blks > (sdp->blks_total - sdp->blks_alloced)) { ++ printf( _("\nInsufficient space on the device to add %u %uMB " ++ "journals (%uMB QC size)\n\n"), ++ opts->journals, sdp->jsize, sdp->qcsize); ++ printf( _("Required space : %*lu blks (%lu blks per " ++ "journal)\n"), 10, total_blks, blks_per_j); ++ printf( _("Available space : %*lu blks\n\n"), 10, ++ sdp->blks_total - sdp->blks_alloced); ++ errno = ENOSPC; ++ return 1; ++ } ++ return 0; ++} ++ + int main(int argc, char *argv[]) + { + struct jadd_opts opts = {0}; + struct gfs2_sbd sbd, *sdp = &sbd; + struct metafs mfs = {0}; + struct mntent *mnt; +- unsigned int total; ++ unsigned int total, ret = 0; + + setlocale(LC_ALL, ""); + textdomain("gfs2-utils"); +@@ -536,6 +568,12 @@ int main(int argc, char *argv[]) + } + find_current_journals(&opts); + ++ ret = check_fit(sdp, &opts); ++ if (ret) { ++ perror(_("Failed to add journals")); ++ goto out; ++ } ++ + total = opts.orig_journals + opts.journals; + for (opts.journals = opts.orig_journals; + opts.journals < total; +@@ -550,13 +588,16 @@ int main(int argc, char *argv[]) + add_j(sdp, &opts); + } + ++out: + free(opts.new_inode); + free(opts.per_node); + free(opts.jindex); + close(sdp->path_fd); + cleanup_metafs(&mfs); + sync(); +- print_results(&opts); + +- return 0; ++ if (!ret) ++ print_results(&opts); ++ ++ return ret; + } diff --git a/SOURCES/bz1837640-2-gfs2_jadd_error_handling_overhaul.patch b/SOURCES/bz1837640-2-gfs2_jadd_error_handling_overhaul.patch new file mode 100644 index 0000000..fdc09dc --- /dev/null +++ b/SOURCES/bz1837640-2-gfs2_jadd_error_handling_overhaul.patch @@ -0,0 +1,513 @@ +commit d4fd26e60017a3a13391364f938588a3096b0971 +Author: Abhi Das +Date: Mon May 11 14:41:06 2020 -0500 + + gfs2_jadd: error handling overhaul + + Handle error conditions better and fail gracefully. + + Resolves: rhbz#1837640 + + Signed-off-by: Abhi Das + +diff --git a/gfs2/mkfs/main_jadd.c b/gfs2/mkfs/main_jadd.c +index 948f67a1..12325be3 100644 +--- a/gfs2/mkfs/main_jadd.c ++++ b/gfs2/mkfs/main_jadd.c +@@ -40,15 +40,13 @@ struct jadd_opts { + + #define JA_FL_SET 0 + #define JA_FL_CLEAR 1 +-static void set_flags(int fd, int op, uint32_t flags) ++static int set_flags(int fd, int op, uint32_t flags) + { +- int err; + uint32_t val; + +- err = ioctl(fd, FS_IOC_GETFLAGS, &val); +- if (err) { ++ if (ioctl(fd, FS_IOC_GETFLAGS, &val)) { + perror("GETFLAGS"); +- exit(EXIT_FAILURE); ++ return -1; + } + + if (op == JA_FL_SET) +@@ -56,11 +54,11 @@ static void set_flags(int fd, int op, uint32_t flags) + else if (op == JA_FL_CLEAR) + val &= ~flags; + +- err = ioctl(fd, FS_IOC_SETFLAGS, &val); +- if (err) { ++ if (ioctl(fd, FS_IOC_SETFLAGS, &val)) { + perror("SETFLAGS"); +- exit(EXIT_FAILURE); ++ return -1; + } ++ return 0; + } + + static int rename2system(struct jadd_opts *opts, const char *new_dir, const char *new_name) +@@ -242,115 +240,126 @@ static int create_new_inode(struct jadd_opts *opts) + { + char *name = opts->new_inode; + int fd; +- int error; + + for (;;) { + fd = open(name, O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW | O_CLOEXEC, 0600); + if (fd >= 0) + break; + if (errno == EEXIST) { +- error = unlink(name); +- if (error){ ++ if (unlink(name)) { + perror("unlink"); +- exit(EXIT_FAILURE); ++ return -1; + } +- } else{ +- perror("create"); +- exit(EXIT_FAILURE); ++ continue; + } ++ perror("create"); ++ return -1; + } + + return fd; + } + +-static void add_ir(struct jadd_opts *opts) ++static int add_ir(struct jadd_opts *opts) + { +- int fd; ++ int fd, error = 0; + char new_name[256]; +- int error; ++ struct gfs2_inum_range ir; + +- fd = create_new_inode(opts); ++ if ((fd = create_new_inode(opts)) < 0) ++ return fd; + +- { +- struct gfs2_inum_range ir; ++ if ((error = set_flags(fd, JA_FL_SET, FS_JOURNAL_DATA_FL))) ++ goto close_fd; + +- set_flags(fd, JA_FL_SET, FS_JOURNAL_DATA_FL); + memset(&ir, 0, sizeof(struct gfs2_inum_range)); + if (write(fd, (void*)&ir, sizeof(struct gfs2_inum_range)) != + sizeof(struct gfs2_inum_range)) { +- perror("add_ir"); +- exit(EXIT_FAILURE); +- } ++ perror("add_ir write"); ++ error = -1; ++ goto close_fd; + } + +- close(fd); ++ if ((error = fsync(fd))) { ++ perror("add_ir fsync"); ++ goto close_fd; ++ } + + sprintf(new_name, "inum_range%u", opts->journals); + error = rename2system(opts, opts->per_node, new_name); + if (error < 0 && errno != EEXIST){ + perror("add_ir rename2system"); +- exit(EXIT_FAILURE); ++ goto close_fd; + } ++close_fd: ++ return close(fd) || error; + } + +-static void add_sc(struct jadd_opts *opts) ++static int add_sc(struct jadd_opts *opts) + { +- int fd; ++ int fd, error = 0; + char new_name[256]; +- int error; ++ struct gfs2_statfs_change sc; + +- fd = create_new_inode(opts); ++ if ((fd = create_new_inode(opts)) < 0) ++ return fd; + +- { +- struct gfs2_statfs_change sc; +- set_flags(fd, JA_FL_SET, FS_JOURNAL_DATA_FL); ++ if ((error = set_flags(fd, JA_FL_SET, FS_JOURNAL_DATA_FL))) ++ goto close_fd; + + memset(&sc, 0, sizeof(struct gfs2_statfs_change)); + if (write(fd, (void*)&sc, sizeof(struct gfs2_statfs_change)) != + sizeof(struct gfs2_statfs_change)) { +- perror("add_sc"); +- exit(EXIT_FAILURE); +- } ++ perror("add_sc write"); ++ error = -1; ++ goto close_fd; + } + +- close(fd); ++ if ((error = fsync(fd))) { ++ perror("add_sc fsync"); ++ goto close_fd; ++ } + + sprintf(new_name, "statfs_change%u", opts->journals); + error = rename2system(opts, opts->per_node, new_name); + if (error < 0 && errno != EEXIST){ + perror("add_sc rename2system"); +- exit(EXIT_FAILURE); ++ goto close_fd; + } ++close_fd: ++ return close(fd) || error; + } + +-static void add_qc(struct gfs2_sbd *sdp, struct jadd_opts *opts) +-{ +- int fd; +- char new_name[256]; +- int error; +- +- fd = create_new_inode(opts); +- ++static int add_qc(struct gfs2_sbd *sdp, struct jadd_opts *opts) + { +- char buf[sdp->bsize]; ++ int fd, error = 0; ++ char new_name[256], buf[sdp->bsize]; + unsigned int blocks = + sdp->qcsize << (20 - sdp->sd_sb.sb_bsize_shift); + unsigned int x; + struct gfs2_meta_header mh; + struct gfs2_buffer_head dummy_bh; + ++ if ((fd = create_new_inode(opts)) < 0) ++ return fd; ++ + dummy_bh.b_data = buf; +- set_flags(fd, JA_FL_CLEAR, FS_JOURNAL_DATA_FL); +- memset(buf, 0, sdp->bsize); + ++ if ((error = set_flags(fd, JA_FL_CLEAR, FS_JOURNAL_DATA_FL))) ++ goto close_fd; ++ ++ memset(buf, 0, sdp->bsize); + for (x=0; xbsize) != sdp->bsize) { +- perror("add_qc"); +- exit(EXIT_FAILURE); ++ perror("add_qc write"); ++ error = -1; ++ goto close_fd; + } + } + +- lseek(fd, 0, SEEK_SET); ++ if ((error = lseek(fd, 0, SEEK_SET)) < 0) { ++ perror("add_qc lseek"); ++ goto close_fd; ++ } + + memset(&mh, 0, sizeof(struct gfs2_meta_header)); + mh.mh_magic = GFS2_MAGIC; +@@ -360,100 +369,114 @@ static void add_qc(struct gfs2_sbd *sdp, struct jadd_opts *opts) + + for (x=0; xbsize) != sdp->bsize) { +- perror("add_qc"); +- exit(EXIT_FAILURE); +- } ++ perror("add_qc write"); ++ error = -1; ++ goto close_fd; + } + +- error = fsync(fd); +- if (error){ ++ if ((error = fsync(fd))) { + perror("add_qc fsync"); +- exit(EXIT_FAILURE); ++ goto close_fd; + } + } + +- close(fd); +- + sprintf(new_name, "quota_change%u", opts->journals); + error = rename2system(opts, opts->per_node, new_name); + if (error < 0 && errno != EEXIST){ + perror("add_qc rename2system"); +- exit(EXIT_FAILURE); ++ goto close_fd; + } ++close_fd: ++ return close(fd) || error; + } + +-static void gather_info(struct gfs2_sbd *sdp, struct jadd_opts *opts) ++static int gather_info(struct gfs2_sbd *sdp, struct jadd_opts *opts) + { + struct statfs statbuf; ++ + if (statfs(opts->path, &statbuf) < 0) { + perror(opts->path); +- exit(EXIT_FAILURE); ++ return -1; + } ++ + sdp->bsize = statbuf.f_bsize; + sdp->blks_total = statbuf.f_blocks; + sdp->blks_alloced = sdp->blks_total - statbuf.f_bfree; ++ ++ return 0; + } + +-static void find_current_journals(struct jadd_opts *opts) ++static int find_current_journals(struct jadd_opts *opts) + { + struct dirent *dp; + DIR *dirp; + unsigned existing_journals = 0; ++ int ret = 0; + + dirp = opendir(opts->jindex); + if (!dirp) { + perror("jindex"); +- exit(EXIT_FAILURE); ++ ret = -1; ++ goto out; + } + while (dirp) { + if ((dp = readdir(dirp)) != NULL) { + if (strncmp(dp->d_name, "journal", 7) == 0) + existing_journals++; + } else +- goto close; ++ goto close_fd; + } +-close: +- closedir(dirp); ++close_fd: ++ if ((ret = closedir(dirp))) ++ goto out; ++ + if (existing_journals == 0) { +- die( _("No journals found. Did you run mkfs.gfs2 correctly?\n")); ++ errno = EINVAL; ++ perror("No journals found. Did you run mkfs.gfs2 correctly?\n"); ++ ret = -1; ++ goto out; + } + + opts->orig_journals = existing_journals; ++out: ++ return ret; + } + +-static void add_j(struct gfs2_sbd *sdp, struct jadd_opts *opts) +-{ +- int fd; +- char new_name[256]; +- int error; +- +- fd = create_new_inode(opts); +- ++static int add_j(struct gfs2_sbd *sdp, struct jadd_opts *opts) + { +- char buf[sdp->bsize]; ++ int fd, error = 0; ++ char new_name[256], buf[sdp->bsize]; + unsigned int blocks = + sdp->jsize << (20 - sdp->sd_sb.sb_bsize_shift); + unsigned int x; + struct gfs2_log_header lh; +- uint64_t seq = RANDOM(blocks); ++ uint64_t seq = RANDOM(blocks);; ++ ++ if ((fd = create_new_inode(opts)) < 0) ++ return fd; ++ ++ if ((error = set_flags(fd, JA_FL_CLEAR, FS_JOURNAL_DATA_FL))) ++ goto close_fd; + +- set_flags(fd, JA_FL_CLEAR, FS_JOURNAL_DATA_FL); + memset(buf, 0, sdp->bsize); + for (x=0; xbsize) != sdp->bsize) { +- perror("add_j"); +- exit(EXIT_FAILURE); ++ perror("add_j write"); ++ error = -1; ++ goto close_fd; + } + } + +- lseek(fd, 0, SEEK_SET); ++ if ((error = lseek(fd, 0, SEEK_SET)) < 0) { ++ perror("add_j lseek"); ++ goto close_fd; ++ } + + memset(&lh, 0, sizeof(struct gfs2_log_header)); + lh.lh_header.mh_magic = GFS2_MAGIC; + lh.lh_header.mh_type = GFS2_METATYPE_LH; + lh.lh_header.mh_format = GFS2_FORMAT_LH; + lh.lh_flags = GFS2_LOG_HEAD_UNMOUNT; +- + for (x=0; xbsize) != sdp->bsize) { + perror("add_j"); +- exit(EXIT_FAILURE); ++ error = -1; ++ goto close_fd; + } + + if (++seq == blocks) + seq = 0; +- } + +- error = fsync(fd); +- if (error){ ++ if ((error = fsync(fd))){ + perror("add_j fsync"); +- exit(EXIT_FAILURE); ++ goto close_fd; + } + } + +- close(fd); +- + sprintf(new_name, "journal%u", opts->journals); + error = rename2system(opts, opts->jindex, new_name); + if (error < 0 && errno != EEXIST){ + perror("add_j rename2system"); +- exit(EXIT_FAILURE); ++ goto close_fd; + } ++close_fd: ++ return close(fd) || error; + } + + static int check_fit(struct gfs2_sbd *sdp, struct jadd_opts *opts) +@@ -516,7 +538,7 @@ static int check_fit(struct gfs2_sbd *sdp, struct jadd_opts *opts) + printf( _("Available space : %*lu blks\n\n"), 10, + sdp->blks_total - sdp->blks_alloced); + errno = ENOSPC; +- return 1; ++ return -1; + } + return 0; + } +@@ -543,35 +565,43 @@ int main(int argc, char *argv[]) + + sbd.path_fd = lgfs2_open_mnt_dir(opts.path, O_RDONLY|O_CLOEXEC, &mnt); + if (sbd.path_fd < 0) { +- fprintf(stderr, _("Error looking up mount '%s': %s\n"), opts.path, strerror(errno)); +- exit(EXIT_FAILURE); ++ fprintf(stderr, "Error looking up mount '%s': %s\n", ++ opts.path, strerror(errno)); ++ ret = -1; ++ goto out; + } + if (mnt == NULL) { +- fprintf(stderr, _("%s: not a mounted gfs2 file system\n"), opts.path); +- exit(EXIT_FAILURE); ++ fprintf(stderr, "%s: not a mounted gfs2 file system: %s\n", ++ opts.path, strerror(EINVAL)); ++ ret = -1; ++ goto close_sb; + } +- gather_info(sdp, &opts); ++ ++ if ((ret = gather_info(sdp, &opts))) ++ goto close_sb; ++ + mfs.context = copy_context_opt(mnt); +- if (mount_gfs2_meta(&mfs, mnt->mnt_dir, opts.debug)) { ++ if ((ret = mount_gfs2_meta(&mfs, mnt->mnt_dir, opts.debug))) { + perror("GFS2 metafs"); +- exit(EXIT_FAILURE); ++ goto close_sb; + } + +- if (build_paths(mfs.path, &opts)) { ++ if ((ret = build_paths(mfs.path, &opts))) { + perror(_("Failed to build paths")); +- exit(EXIT_FAILURE); ++ goto umount_meta; + } + +- if (compute_constants(sdp)) { ++ if ((ret = compute_constants(sdp))) { + perror(_("Failed to compute file system constants")); +- exit(EXIT_FAILURE); ++ goto free_paths; + } +- find_current_journals(&opts); + +- ret = check_fit(sdp, &opts); +- if (ret) { ++ if ((ret = find_current_journals(&opts))) ++ goto free_paths; ++ ++ if ((ret = check_fit(sdp, &opts))) { + perror(_("Failed to add journals")); +- goto out; ++ goto free_paths; + } + + total = opts.orig_journals + opts.journals; +@@ -579,23 +609,29 @@ int main(int argc, char *argv[]) + opts.journals < total; + opts.journals++) { + if (metafs_interrupted) { +- cleanup_metafs(&mfs); +- exit(130); ++ errno = 130; ++ goto free_paths; + } +- add_ir(&opts); +- add_sc(&opts); +- add_qc(sdp, &opts); +- add_j(sdp, &opts); ++ if ((ret = add_ir(&opts))) ++ goto free_paths; ++ if ((ret = add_sc(&opts))) ++ goto free_paths; ++ if ((ret = add_qc(sdp, &opts))) ++ goto free_paths; ++ if ((ret = add_j(sdp, &opts))) ++ goto free_paths; + } + +-out: ++free_paths: + free(opts.new_inode); + free(opts.per_node); + free(opts.jindex); +- close(sdp->path_fd); +- cleanup_metafs(&mfs); ++umount_meta: + sync(); +- ++ cleanup_metafs(&mfs); ++close_sb: ++ close(sdp->path_fd); ++out: + if (!ret) + print_results(&opts); + diff --git a/SPECS/gfs2-utils.spec b/SPECS/gfs2-utils.spec index 24a5d8d..aae8528 100644 --- a/SPECS/gfs2-utils.spec +++ b/SPECS/gfs2-utils.spec @@ -12,7 +12,7 @@ Name: gfs2-utils Version: 3.1.10 -Release: 9%{?dist} +Release: 11%{?dist} License: GPLv2+ and LGPLv2+ Group: System Environment/Kernel Summary: Utilities for managing the global file system (GFS2) @@ -54,6 +54,16 @@ Patch8: bz1498068-mkfs_gfs2_Scale_down_journal_size_for_smaller_devices.patch Patch9: bz1544944-glocktop_Remove_a_non_existent_flag_from_the_usage_string.patch Patch10: bz1616389-1-fsck_gfs2_Don_t_check_fs_formats_we_don_t_recognise.patch Patch11: bz1616389-2-libgfs2_Fix_pointer_cast_byte_order_issue.patch +Patch12: bz1487726-1-libgfs2_Use_sizeof_for_reserved_fields_in_ondisk_c.patch +Patch13: bz1487726-2-fsck_gfs2_Disambiguate_check_data.patch +Patch14: bz1487726-3-gfs2_utils_Accept_a_char_instead_of_a_buffer_head_in_gfs2_check_meta.patch +Patch15: bz1487726-4-fsck_gfs2_Disambiguate_check_metalist.patch +Patch16: bz1487726-5-fsck_gfs2_Fix_segfault_in_build_and_check_metalist.patch +Patch17: bz1487726-6-fsck_gfs2_Retain_context_for_indirect_pointers_in_check_metalist.patch +Patch18: bz1487726-7-fsck_gfs2_Clear_bad_indirect_block_pointers_when_bitmap_meets_expectations.patch +Patch19: bz1837640-1-gfs2_jadd_Handle_out_of_space_issues.patch +Patch20: bz1837640-2-gfs2_jadd_error_handling_overhaul.patch + BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) @@ -71,6 +81,15 @@ BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) %patch9 -p1 -b .bz1544944-glocktop_Remove_a_non_existent_flag_from_the_usage_string %patch10 -p1 -b .bz1616389-1-fsck_gfs2_Don_t_check_fs_formats_we_don_t_recognise %patch11 -p1 -b .bz1616389-2-libgfs2_Fix_pointer_cast_byte_order_issue +%patch12 -p1 -b .bz1487726-1-libgfs2_Use_sizeof_for_reserved_fields_in_ondisk_c +%patch13 -p1 -b .bz1487726-2-fsck_gfs2_Disambiguate_check_data +%patch14 -p1 -b .bz1487726-3-gfs2_utils_Accept_a_char_instead_of_a_buffer_head_in_gfs2_check_meta +%patch15 -p1 -b .bz1487726-4-fsck_gfs2_Disambiguate_check_metalist +%patch16 -p1 -b .bz1487726-5-fsck_gfs2_Fix_segfault_in_build_and_check_metalist +%patch17 -p1 -b .bz1487726-6-fsck_gfs2_Retain_context_for_indirect_pointers_in_check_metalist +%patch18 -p1 -b .bz1487726-7-fsck_gfs2_Clear_bad_indirect_block_pointers_when_bitmap_meets_expectations +%patch19 -p1 -b .bz1837640-1-gfs2_jadd_Handle_out_of_space_issues +%patch20 -p1 -b .bz1837640-2-gfs2_jadd_error_handling_overhaul %build ./autogen.sh @@ -116,6 +135,21 @@ file systems. %{_prefix}/lib/udev/rules.d/82-gfs2-withdraw.rules %changelog +* Mon Jun 08 2020 Andrew Price - 3.1.10-11 +- gfs2_jadd: Handle out-of-space issues +- gfs2_jadd: error handling overhaul + Resolves: rhbz#1837640 + +* Tue Apr 28 2020 Andrew Price - 3.1.10-10 +- libgfs2: Use sizeof for 'reserved' fields in ondisk.c +- fsck.gfs2: Disambiguate 'check_data' +- gfs2-utils: Accept a char* instead of a buffer head in gfs2_check_meta +- fsck.gfs2: Disambiguate check_metalist +- fsck.gfs2: Fix segfault in build_and_check_metalist +- fsck.gfs2: Retain context for indirect pointers in ->check_metalist +- fsck.gfs2: Clear bad indirect block pointers when bitmap meets expectations + Resolves: rhbz#1487726 + * Thu Sep 06 2018 Andrew Price - 3.1.10-9 - fsck.gfs2: Don't check fs formats we don't recognise - libgfs2: Fix pointer cast byte order issue