gfs2-utils: master - fsck.gfs2: rgrp block count reform
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=612adec3...
Commit: 612adec361e2ad53cb7cfa4f5b9b197e84c39caf
Parent: 13206080308286fa6f801221eaca96c6a47b61b1
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Tue Jan 13 13:18:01 2015 -0600
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Thu Jan 22 14:19:16 2015 -0600
fsck.gfs2: rgrp block count reform
In the past, pass5 has kept track of different counts for the different
metadata types, but the counts did not correspond to the type in the
bitmap. This patch changes pass5 so that it makes a little more sense.
There should be a straightforward blockmap-to-bitmap conversion, and
the counts should be based on the bitmap type. For example, before the
patch, the rgrp's inode count would be kept in count[1], but in the
bitmap, dinodes are of type 3. So this patch reworks that system so
that the count of dinodes is kept in count[3] and so forth, and it
uses a simple blockmap-to-bitmap to figure out the index to "count".
This breaks down for GFS1 which keeps a few extra numbers in the rgrp,
however this patch compensates for that. This patch is being done
as a precursor to another patch that reduces fsck's memory requirements
by using a blockmap that's 1:1 with the bitmaps rather than today's
blockmap that's 4:1.
---
gfs2/fsck/pass5.c | 167 ++++++++++++++---------------------------------------
1 files changed, 44 insertions(+), 123 deletions(-)
diff --git a/gfs2/fsck/pass5.c b/gfs2/fsck/pass5.c
index b2e8adf..2b8536d 100644
--- a/gfs2/fsck/pass5.c
+++ b/gfs2/fsck/pass5.c
@@ -12,94 +12,6 @@
#include "fsck.h"
#include "util.h"
-static int gfs1_convert_mark(uint8_t q, uint32_t *count)
-{
- switch(q) {
-
- case gfs2_meta_inval:
- case gfs2_inode_invalid:
- /* Convert invalid metadata to free blocks */
- case gfs2_block_free:
- count[0]++;
- return GFS2_BLKST_FREE;
-
- case gfs2_block_used:
- count[2]++;
- return GFS2_BLKST_USED;
-
- case gfs2_inode_dir:
- case gfs2_inode_file:
- case gfs2_inode_lnk:
- case gfs2_inode_device:
- case gfs2_inode_fifo:
- case gfs2_inode_sock:
- count[1]++;
- return GFS2_BLKST_DINODE;
-
- case gfs2_indir_blk:
- case gfs2_leaf_blk:
- /*case gfs2_meta_rgrp:*/
- case gfs2_jdata: /* gfs1 jdata blocks count as "metadata" and gfs1
- metadata is marked the same as gfs2 inode in the
- bitmap. */
- case gfs2_meta_eattr:
- count[3]++;
- return GFS2_BLKST_DINODE;
-
- case gfs2_freemeta:
- count[4]++;
- return GFS2_BLKST_UNLINKED;
-
- default:
- log_err( _("Invalid block type %d found\n"), q);
- }
- return -1;
-}
-
-static int gfs2_convert_mark(uint8_t q, uint32_t *count)
-{
- switch(q) {
-
- case gfs2_meta_inval:
- case gfs2_inode_invalid:
- /* Convert invalid metadata to free blocks */
- case gfs2_block_free:
- count[0]++;
- return GFS2_BLKST_FREE;
-
- case gfs2_block_used:
- count[2]++;
- return GFS2_BLKST_USED;
-
- case gfs2_inode_dir:
- case gfs2_inode_file:
- case gfs2_inode_lnk:
- case gfs2_inode_device:
- case gfs2_jdata: /* gfs1 jdata blocks count as "metadata" and gfs1
- metadata is marked the same as gfs2 inode in the
- bitmap. */
- case gfs2_inode_fifo:
- case gfs2_inode_sock:
- count[1]++;
- return GFS2_BLKST_DINODE;
-
- case gfs2_indir_blk:
- case gfs2_leaf_blk:
- case gfs2_meta_eattr:
- count[2]++;
- return GFS2_BLKST_USED;
-
- case gfs2_freemeta:
- log_err( _("Invalid freemeta type %d found\n"), q);
- count[4]++;
- return -1;
-
- default:
- log_err( _("Invalid block type %d found\n"), q);
- }
- return -1;
-}
-
static int check_block_status(struct gfs2_sbd *sdp, char *buffer,
unsigned int buflen, uint64_t *rg_block,
uint64_t rg_data, uint32_t *count)
@@ -107,7 +19,6 @@ static int check_block_status(struct gfs2_sbd *sdp, char *buffer,
unsigned char *byte, *end;
unsigned int bit;
unsigned char rg_status;
- int block_status;
uint8_t q;
uint64_t block;
@@ -123,26 +34,33 @@ static int check_block_status(struct gfs2_sbd *sdp, char *buffer,
if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
return 0;
- q = block_type(block);
-
- if (sdp->gfs1)
- block_status = gfs1_convert_mark(q, count);
- else
- block_status = gfs2_convert_mark(q, count);
-
- if (block_status < 0) {
- log_err( _("Invalid status for block %llu (0x%llx).\n"),
- (unsigned long long)block,
- (unsigned long long)block);
- return block_status;
+ q = blockmap_to_bitmap(block_type(block), sdp->gfs1);
+ /* GFS1 file systems will have to suffer from slower fsck run
+ * times because in GFS, there's no 1:1 relationship between
+ * bits and counts. If a bit is marked "dinode" in GFS1, it
+ * may be dinode -OR- any kind of metadata. I consider GFS1 to
+ * be a rare exception, so acceptable loss at this point. So
+ * we must determine whether it's really a dinode or other
+ * metadata by reading it in. */
+ if (sdp->gfs1 && q == GFS2_BLKST_DINODE) {
+ struct gfs2_buffer_head *bh;
+
+ bh = bread(sdp, block);
+ if (gfs2_check_meta(bh, GFS2_METATYPE_DI) == 0)
+ count[GFS2_BLKST_DINODE]++;
+ else
+ count[GFS2_BLKST_USED]++;
+ brelse(bh);
+ } else {
+ count[q]++;
}
+
/* If one node opens a file and another node deletes it, we
may be left with a block that appears to be "unlinked" in
the bitmap, but nothing links to it. This is a valid case
and should be cleaned up by the file system eventually.
So we ignore it. */
- if (rg_status == GFS2_BLKST_UNLINKED &&
- block_status == GFS2_BLKST_FREE) {
+ if (q == GFS2_BLKST_UNLINKED) {
log_err( _("Unlinked inode found at block %llu "
"(0x%llx).\n"),
(unsigned long long)block,
@@ -150,33 +68,33 @@ static int check_block_status(struct gfs2_sbd *sdp, char *buffer,
if (query(_("Do you want to reclaim the block? "
"(y/n) "))) {
lgfs2_rgrp_t rg = gfs2_blk2rgrpd(sdp, block);
- if (gfs2_set_bitmap(rg, block, block_status))
+ if (gfs2_set_bitmap(rg, block, GFS2_BLKST_FREE))
log_err(_("Unlinked block %llu "
"(0x%llx) bitmap not fixed."
"\n"),
(unsigned long long)block,
(unsigned long long)block);
- else
+ else {
log_err(_("Unlinked block %llu "
"(0x%llx) bitmap fixed.\n"),
(unsigned long long)block,
(unsigned long long)block);
+ count[GFS2_BLKST_UNLINKED]--;
+ count[GFS2_BLKST_FREE]++;
+ }
} else {
log_info( _("Unlinked block found at block %llu"
" (0x%llx), left unchanged.\n"),
(unsigned long long)block,
(unsigned long long)block);
}
- } else if (rg_status != block_status) {
- const char *blockstatus[] = {"Free", "Data",
- "Unlinked", "inode"};
-
+ } else if (rg_status != q) {
log_err( _("Block %llu (0x%llx) bitmap says %u (%s) "
"but FSCK saw %u (%s)\n"),
(unsigned long long)block,
(unsigned long long)block, rg_status,
- blockstatus[rg_status], block_status,
- blockstatus[block_status]);
+ block_type_string(rg_status), q,
+ block_type_string(q));
if (q) /* Don't print redundant "free" */
log_err( _("Metadata type is %u (%s)\n"), q,
block_type_string(q));
@@ -185,7 +103,7 @@ static int check_block_status(struct gfs2_sbd *sdp, char *buffer,
(unsigned long long)block,
(unsigned long long)block)) {
lgfs2_rgrp_t rg = gfs2_blk2rgrpd(sdp, block);
- if (gfs2_set_bitmap(rg, block, block_status))
+ if (gfs2_set_bitmap(rg, block, q))
log_err( _("Repair failed.\n"));
else
log_err( _("Fixed.\n"));
@@ -235,38 +153,41 @@ static void update_rgrp(struct gfs2_sbd *sdp, struct rgrp_tree *rgp,
rgp->rg.rg_free = count[0];
update = 1;
}
- if (rgp->rg.rg_dinodes != count[1]) {
+ if (rgp->rg.rg_dinodes != count[3]) {
log_err( _("RG #%llu (0x%llx) Inode count inconsistent: is "
"%u should be %u\n"),
(unsigned long long)rgp->ri.ri_addr,
(unsigned long long)rgp->ri.ri_addr,
- rgp->rg.rg_dinodes, count[1]);
- rgp->rg.rg_dinodes = count[1];
+ rgp->rg.rg_dinodes, count[3]);
+ rgp->rg.rg_dinodes = count[3];
update = 1;
}
- if (sdp->gfs1 && gfs1rg->rg_usedmeta != count[3]) {
+ if (sdp->gfs1 && gfs1rg->rg_usedmeta != count[1]) {
log_err( _("RG #%llu (0x%llx) Used metadata count "
"inconsistent: is %u should be %u\n"),
(unsigned long long)rgp->ri.ri_addr,
(unsigned long long)rgp->ri.ri_addr,
- gfs1rg->rg_usedmeta, count[3]);
- gfs1rg->rg_usedmeta = count[3];
+ gfs1rg->rg_usedmeta, count[1]);
+ gfs1rg->rg_usedmeta = count[1];
update = 1;
}
- if (sdp->gfs1 && gfs1rg->rg_freemeta != count[4]) {
+ if (sdp->gfs1 && gfs1rg->rg_freemeta != count[2]) {
log_err( _("RG #%llu (0x%llx) Free metadata count "
"inconsistent: is %u should be %u\n"),
(unsigned long long)rgp->ri.ri_addr,
(unsigned long long)rgp->ri.ri_addr,
- gfs1rg->rg_freemeta, count[4]);
- gfs1rg->rg_freemeta = count[4];
+ gfs1rg->rg_freemeta, count[2]);
+ gfs1rg->rg_freemeta = count[2];
update = 1;
}
- if (!sdp->gfs1 && (rgp->ri.ri_data - count[0] - count[1]) != count[2]) {
+ if (!sdp->gfs1 && (rgp->ri.ri_data != count[0] + count[1] +
+ count[2] + count[3])) {
/* FIXME not sure how to handle this case ATM - it
* means that the total number of blocks we've counted
* exceeds the blocks in the rg */
- log_err( _("Internal fsck error - AAHHH!\n"));
+ log_err( _("Internal fsck error: %u != %u + %u + %u + %u\n"),
+ rgp->ri.ri_data, count[0], count[1], count[2],
+ count[3]);
exit(FSCK_ERROR);
}
if (update) {
9 years, 3 months
gfs2-utils: master - fsck.gfs2: Check the integrity of the journal index
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=13206080...
Commit: 13206080308286fa6f801221eaca96c6a47b61b1
Parent: aaf46833cb46dc1bbfaf59041b0a8ca87ca916ab
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Mon Jan 12 15:10:08 2015 -0600
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Thu Jan 22 14:18:33 2015 -0600
fsck.gfs2: Check the integrity of the journal index
This patch checks the jindex system directory to make sure the entries
all start with "journal" and so forth. If not, the jindex is deleted
and rebuilt. As part of this patch, I moved where we read in the rindex
file and rgrps to an earlier point in time, before the journals are
replayed. This allows us to remove a dummied-up rgrp kludge in the code.
However, if the replayed journal block is part of an rgrp, we need to
refresh the rgrp based on the values rewritten from the journal.
---
gfs2/fsck/fs_recovery.c | 53 ++++++++------
gfs2/fsck/initialize.c | 171 ++++++++++++++++++++++++++++++++++++-----------
gfs2/fsck/metawalk.c | 17 +++--
gfs2/fsck/metawalk.h | 1 +
gfs2/fsck/pass1.c | 8 +-
5 files changed, 176 insertions(+), 74 deletions(-)
diff --git a/gfs2/fsck/fs_recovery.c b/gfs2/fsck/fs_recovery.c
index 095d118..abb8187 100644
--- a/gfs2/fsck/fs_recovery.c
+++ b/gfs2/fsck/fs_recovery.c
@@ -96,6 +96,30 @@ void gfs2_revoke_clean(struct gfs2_sbd *sdp)
}
}
+static void refresh_rgrp(struct gfs2_sbd *sdp, struct rgrp_tree *rgd,
+ struct gfs2_buffer_head *bh, uint64_t blkno)
+{
+ int i;
+
+ log_debug(_("Block is part of rgrp 0x%llx; refreshing the rgrp.\n"),
+ (unsigned long long)rgd->ri.ri_addr);
+ for (i = 0; i < rgd->ri.ri_length; i++) {
+ if (rgd->bits[i].bi_bh->b_blocknr != blkno)
+ continue;
+
+ memcpy(rgd->bits[i].bi_bh->b_data, bh->b_data, sdp->bsize);
+ bmodified(rgd->bits[i].bi_bh);
+ if (i == 0) { /* this is the rgrp itself */
+ if (sdp->gfs1)
+ gfs_rgrp_in((struct gfs_rgrp *)&rgd->rg,
+ rgd->bits[0].bi_bh);
+ else
+ gfs2_rgrp_in(&rgd->rg, rgd->bits[0].bi_bh);
+ }
+ break;
+ }
+}
+
static int buf_lo_scan_elements(struct gfs2_inode *ip, unsigned int start,
struct gfs2_log_descriptor *ld, __be64 *ptr,
int pass)
@@ -105,6 +129,7 @@ static int buf_lo_scan_elements(struct gfs2_inode *ip, unsigned int start,
struct gfs2_buffer_head *bh_log, *bh_ip;
uint64_t blkno;
int error = 0;
+ struct rgrp_tree *rgd;
if (pass != 1 || be32_to_cpu(ld->ld_type) != GFS2_LOG_DESC_METADATA)
return 0;
@@ -147,6 +172,9 @@ static int buf_lo_scan_elements(struct gfs2_inode *ip, unsigned int start,
error = -EIO;
} else {
bmodified(bh_ip);
+ rgd = gfs2_blk2rgrpd(sdp, blkno);
+ if (rgd && blkno < rgd->ri.ri_data0)
+ refresh_rgrp(sdp, rgd, bh_ip, blkno);
}
brelse(bh_log);
@@ -676,28 +704,8 @@ int replay_journals(struct gfs2_sbd *sdp, int preen, int force_check,
for(i = 0; i < sdp->md.journals; i++) {
if (sdp->md.journal[i]) {
- struct rgrp_tree rgd;
- struct gfs2_bitmap bits;
-
- /* The real rgrp tree hasn't been built at this point,
- * so we need to dummy one up that covers the whole
- * file system so basic functions in check_metatree
- * don't segfault. */
- rgd.start = sdp->sb_addr + 1;
- rgd.length = 1;
- bits.bi_bh = NULL;
- bits.bi_start = 0;
- bits.bi_len = sdp->fssize / GFS2_NBBY;
- rgd.bits = &bits;
- rgd.ri.ri_addr = sdp->sb_addr + 1;
- rgd.ri.ri_length = 1;
- rgd.ri.ri_data0 = sdp->sb_addr + 2;
- rgd.ri.ri_data = sdp->fssize - (sdp->sb_addr + 2);
-
- sdp->rgtree.osi_node = (struct osi_node *)&rgd;
error = check_metatree(sdp->md.journal[i],
&rangecheck_journal);
- sdp->rgtree.osi_node = NULL;
if (error)
/* Don't use fsck_inode_put here because it's a
system file and we need to dismantle it. */
@@ -707,8 +715,7 @@ int replay_journals(struct gfs2_sbd *sdp, int preen, int force_check,
if (!sdp->md.journal[i]) {
log_err(_("File system journal \"journal%d\" is "
"missing or corrupt: pass1 will try to "
- "recreate it.\n"),
- i);
+ "recreate it.\n"), i);
continue;
}
if (!error) {
@@ -755,7 +762,7 @@ int ji_update(struct gfs2_sbd *sdp)
struct gfs_jindex ji;
if (!ip) {
- log_crit("Journal index inode not found.\n");
+ log_crit(_("Journal index inode not found.\n"));
return -1;
}
diff --git a/gfs2/fsck/initialize.c b/gfs2/fsck/initialize.c
index 4e52262..1ab078b 100644
--- a/gfs2/fsck/initialize.c
+++ b/gfs2/fsck/initialize.c
@@ -142,7 +142,7 @@ static int set_block_ranges(struct gfs2_sbd *sdp)
uint64_t rmin = 0;
int error;
- log_info( _("Setting block ranges...\n"));
+ log_info( _("Setting block ranges..."));
for (n = osi_first(&sdp->rgtree); n; n = next) {
next = osi_next(n);
@@ -184,9 +184,12 @@ static int set_block_ranges(struct gfs2_sbd *sdp)
goto fail;
}
+ log_info(_("0x%llx to 0x%llx\n"), (unsigned long long)first_data_block,
+ (unsigned long long)last_data_block);
return 0;
fail:
+ log_info( _("Error\n"));
return -1;
}
@@ -685,10 +688,6 @@ static int init_system_inodes(struct gfs2_sbd *sdp)
if (sdp->md.rooti == NULL)
return -1;
- err = fetch_rgrps(sdp);
- if (err)
- return err;
-
/*******************************************************************
***************** Initialize more system inodes *****************
*******************************************************************/
@@ -711,8 +710,8 @@ static int init_system_inodes(struct gfs2_sbd *sdp)
gfs2_lookupi(sdp->master_dir, "inum", 4,
&sdp->md.inum);
if (!sdp->md.inum) {
- log_crit("System inum inode was not rebuilt. "
- "Aborting.\n");
+ log_crit(_("System inum inode was not rebuilt."
+ " Aborting.\n"));
goto fail;
}
}
@@ -811,8 +810,8 @@ static int init_system_inodes(struct gfs2_sbd *sdp)
if (!sdp->gfs1 && !sdp->md.qinode) {
if (!query( _("The gfs2 system quota inode is missing. "
"Okay to rebuild it? (y/n) "))) {
- log_crit("System quota inode was not "
- "rebuilt. Aborting.\n");
+ log_crit(_("System quota inode was not "
+ "rebuilt. Aborting.\n"));
goto fail;
}
err = build_quota(sdp);
@@ -822,8 +821,8 @@ static int init_system_inodes(struct gfs2_sbd *sdp)
}
gfs2_lookupi(sdp->master_dir, "quota", 5, &sdp->md.qinode);
if (!sdp->md.qinode) {
- log_crit("Unable to rebuild system quota file "
- "inode. Aborting.\n");
+ log_crit(_("Unable to rebuild system quota file "
+ "inode. Aborting.\n"));
goto fail;
}
}
@@ -1357,7 +1356,7 @@ static int reconstruct_single_journal(struct gfs2_sbd *sdp, int jnum,
srandom(time(NULL));
sequence = ji_nsegment / (RAND_MAX + 1.0) * random();
- log_info("Clearing journal %d\n", jnum);
+ log_info(_("Clearing journal %d\n"), jnum);
for (seg = 0; seg < ji_nsegment; seg++){
memset(&lh, 0, sizeof(struct gfs_log_header));
@@ -1512,6 +1511,66 @@ static int init_rindex(struct gfs2_sbd *sdp)
return 0;
}
+static void bad_journalname(const char *filename, int len)
+{
+ char tmp_name[64];
+
+ if (len >= 64)
+ len = 63;
+ strncpy(tmp_name, filename, len);
+ tmp_name[len] = '\0';
+ log_debug(_("Journal index entry '%s' has an invalid filename.\n"),
+ tmp_name);
+}
+
+/**
+ * check_jindex_dent - check the jindex directory entries
+ *
+ * This function makes sure the directory entries of the jindex are valid.
+ * If they're not '.' or '..' they better have the form journalXXX.
+ */
+static int check_jindex_dent(struct gfs2_inode *ip, struct gfs2_dirent *dent,
+ struct gfs2_dirent *prev_de,
+ struct gfs2_buffer_head *bh, char *filename,
+ uint32_t *count, int *lindex, void *priv)
+{
+ struct gfs2_dirent dentry, *de;
+ int i;
+
+ memset(&dentry, 0, sizeof(struct gfs2_dirent));
+ gfs2_dirent_in(&dentry, (char *)dent);
+ de = &dentry;
+
+ if (de->de_name_len == 1 && filename[0] == '.')
+ goto dirent_good;
+ if (de->de_name_len == 2 && filename[0] == '.' && filename[1] == '.')
+ goto dirent_good;
+
+ if ((de->de_name_len >= 11) || /* "journal9999" */
+ (de->de_name_len <= 7) ||
+ (strncmp(filename, "journal", 7))) {
+ bad_journalname(filename, de->de_name_len);
+ return -1;
+ }
+ for (i = 7; i < de->de_name_len; i++) {
+ if (filename[i] < '0' || filename[i] > '9') {
+ bad_journalname(filename, de->de_name_len);
+ return -2;
+ }
+ }
+
+dirent_good:
+ /* Return the number of leaf entries so metawalk doesn't flag this
+ leaf as having none. */
+ *count = be16_to_cpu(((struct gfs2_leaf *)bh->b_data)->lf_entries);
+ return 0;
+}
+
+struct metawalk_fxns jindex_check_fxns = {
+ .private = NULL,
+ .check_dentry = check_jindex_dent,
+};
+
/**
* init_jindex - read in the rindex file
*/
@@ -1521,6 +1580,7 @@ static int init_jindex(struct gfs2_sbd *sdp)
****************** Fill in journal information ******************
*******************************************************************/
+ log_debug(_("Validating the journal index.\n"));
/* rgrepair requires the journals be read in in order to distinguish
"real" rgrps from rgrps that are just copies left in journals. */
if (sdp->gfs1)
@@ -1537,24 +1597,52 @@ static int init_jindex(struct gfs2_sbd *sdp)
"jindex file.\n"));
return -1;
}
- /* In order to rebuild jindex, we need some valid
- rgrps in memory. Temporarily read those in. */
- err = fetch_rgrps(sdp);
- if (err)
- return err;
err = build_jindex(sdp);
- /* Free rgrps read in earlier (re-read them later) */
- gfs2_rgrp_free(&sdp->rgtree);
if (err) {
log_crit(_("Error %d rebuilding jindex\n"), err);
return err;
}
+ gfs2_lookupi(sdp->master_dir, "jindex", 6, &sdp->md.jiinode);
+ }
+
+ /* check for irrelevant entries in jindex. Can't use check_dir because
+ that creates and destroys the inode, which we don't want. */
+ if (!sdp->gfs1) {
+ int error;
+
+ log_debug(_("Checking the integrity of the journal index.\n"));
+ if (sdp->md.jiinode->i_di.di_flags & GFS2_DIF_EXHASH)
+ error = check_leaf_blks(sdp->md.jiinode,
+ &jindex_check_fxns);
+ else
+ error = check_linear_dir(sdp->md.jiinode,
+ sdp->md.jiinode->i_bh,
+ &jindex_check_fxns);
+ if (error) {
+ log_err(_("The system journal index is damaged.\n"));
+ if (!query( _("Okay to rebuild it? (y/n) "))) {
+ log_crit(_("Error: cannot proceed without a "
+ "valid jindex file.\n"));
+ return -1;
+ }
+ inode_put(&sdp->md.jiinode);
+ gfs2_dirent_del(sdp->master_dir, "jindex", 6);
+ log_err(_("Corrupt journal index was removed.\n"));
+ error = build_jindex(sdp);
+ if (error) {
+ log_err(_("Error rebuilding journal "
+ "index: Cannot continue.\n"));
+ return error;
+ }
+ gfs2_lookupi(sdp->master_dir, "jindex", 6,
+ &sdp->md.jiinode);
+ }
}
/* read in the ji data */
if (ji_update(sdp)){
- log_err( _("Unable to read in jindex inode.\n"));
+ log_err( _("Unable to read jindex inode.\n"));
return -1;
}
return 0;
@@ -1655,31 +1743,34 @@ int initialize(struct gfs2_sbd *sdp, int force_check, int preen,
if (init_rindex(sdp))
return FSCK_ERROR;
- /* We need to read in jindex in order to replay the journals */
- if (init_jindex(sdp))
+ if (fetch_rgrps(sdp))
return FSCK_ERROR;
- /* If GFS, rebuild the journals. If GFS2, replay them. We don't have
- the smarts to replay GFS1 journals (neither did gfs_fsck). */
-
- if (sdp->gfs1) {
- if (reconstruct_journals(sdp))
+ /* We need to read in jindex in order to replay the journals. If
+ there's an error, we may proceed and let init_system_inodes
+ try to rebuild it. */
+ if (init_jindex(sdp) == 0) {
+ /* If GFS, rebuild the journals. If GFS2, replay them. We don't
+ have the smarts to replay GFS1 journals (neither did
+ gfs_fsck). */
+ if (sdp->gfs1) {
+ if (reconstruct_journals(sdp))
+ return FSCK_ERROR;
+ } else if (replay_journals(sdp, preen, force_check,
+ &clean_journals)) {
+ if (!opts.no && preen_is_safe(sdp, preen, force_check))
+ block_mounters(sdp, 0);
+ stack;
return FSCK_ERROR;
- } else if (replay_journals(sdp, preen, force_check, &clean_journals)) {
- if (!opts.no && preen_is_safe(sdp, preen, force_check))
- block_mounters(sdp, 0);
- stack;
- return FSCK_ERROR;
- }
- if (sdp->md.journals == clean_journals)
- *all_clean = 1;
- else {
- if (force_check || !preen)
+ }
+ if (sdp->md.journals == clean_journals)
+ *all_clean = 1;
+ else if (force_check || !preen)
log_notice( _("\nJournal recovery complete.\n"));
- }
- if (!force_check && *all_clean && preen)
- return FSCK_OK;
+ if (!force_check && *all_clean && preen)
+ return FSCK_OK;
+ }
if (init_system_inodes(sdp))
return FSCK_ERROR;
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 5f432d6..b771b9e 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -368,14 +368,11 @@ static int check_entries(struct gfs2_inode *ip, struct gfs2_buffer_head *bh,
if (type == DIR_LINEAR) {
dent = (struct gfs2_dirent *)(bh->b_data + sizeof(struct gfs2_dinode));
- } else if (type == DIR_EXHASH) {
+ } else {
dent = (struct gfs2_dirent *)(bh->b_data + sizeof(struct gfs2_leaf));
log_debug( _("Checking leaf %llu (0x%llx)\n"),
(unsigned long long)bh->b_blocknr,
(unsigned long long)bh->b_blocknr);
- } else {
- log_err( _("Invalid directory type %d specified\n"), type);
- return -1;
}
prev = NULL;
@@ -465,7 +462,7 @@ static int check_entries(struct gfs2_inode *ip, struct gfs2_buffer_head *bh,
pass->private);
if (error < 0) {
stack;
- return -1;
+ return error;
}
}
}
@@ -529,7 +526,7 @@ int check_leaf(struct gfs2_inode *ip, int lindex, struct metawalk_fxns *pass,
if (pass->check_leaf_depth)
error = pass->check_leaf_depth(ip, *leaf_no, *ref_count, lbh);
- if (pass->check_leaf) {
+ if (error >= 0 && pass->check_leaf) {
error = pass->check_leaf(ip, *leaf_no, pass->private);
if (error == -EEXIST) {
log_info(_("Previous reference to leaf %lld (0x%llx) "
@@ -616,6 +613,8 @@ out:
(*ref_count) <<= (ip->i_di.di_depth - di_depth);
}
brelse(lbh);
+ if (error < 0)
+ return error;
return 0;
bad_leaf:
@@ -674,7 +673,7 @@ static void dir_leaf_reada(struct gfs2_inode *ip, uint64_t *tbl, unsigned hsize)
}
/* Checks exhash directory entries */
-static int check_leaf_blks(struct gfs2_inode *ip, struct metawalk_fxns *pass)
+int check_leaf_blks(struct gfs2_inode *ip, struct metawalk_fxns *pass)
{
int error = 0;
unsigned hsize = (1 << ip->i_di.di_depth);
@@ -801,6 +800,10 @@ static int check_leaf_blks(struct gfs2_inode *ip, struct metawalk_fxns *pass)
orig_ref_count, ref_count);
tbl_valid = 0;
}
+ if (error < 0) {
+ free(tbl);
+ return error;
+ }
if (!leaf.lf_next || error)
break;
leaf_no = leaf.lf_next;
diff --git a/gfs2/fsck/metawalk.h b/gfs2/fsck/metawalk.h
index aae9121..06345c3 100644
--- a/gfs2/fsck/metawalk.h
+++ b/gfs2/fsck/metawalk.h
@@ -11,6 +11,7 @@ struct metawalk_fxns;
extern int check_inode_eattr(struct gfs2_inode *ip,
struct metawalk_fxns *pass);
extern int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass);
+extern int check_leaf_blks(struct gfs2_inode *ip, struct metawalk_fxns *pass);
extern int check_dir(struct gfs2_sbd *sdp, uint64_t block,
struct metawalk_fxns *pass);
extern int check_linear_dir(struct gfs2_inode *ip, struct gfs2_buffer_head *bh,
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index 4348683..5342701 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -238,7 +238,7 @@ static int p1check_leaf(struct gfs2_inode *ip, uint64_t block, void *private)
if (q == gfs2_leaf_blk) /* If the previous reference also saw
this as a leaf, it was already
checked, so don't check again. */
- return -EEXIST;
+ return EEXIST; /* non-fatal */
}
fsck_blockmap_set(ip, block, _("directory leaf"), gfs2_leaf_blk);
return 0;
@@ -1532,9 +1532,9 @@ static int pass1_process_bitmap(struct gfs2_sbd *sdp, struct rgrp_tree *rgd, uin
if (q != gfs2_block_free) {
if (be32_to_cpu(check_magic) == GFS2_MAGIC &&
sdp->gfs1 && !is_inode) {
- log_debug("Block 0x%llx assumed to be "
- "previously processed GFS1 "
- "non-dinode metadata.\n",
+ log_debug(_("Block 0x%llx assumed to be "
+ "previously processed GFS1 "
+ "non-dinode metadata.\n"),
(unsigned long long)block);
brelse(bh);
continue;
9 years, 3 months
gfs2-utils: master - fsck.gfs2: Rebuild system files if they don't have the SYS bit set
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=aaf46833...
Commit: aaf46833cb46dc1bbfaf59041b0a8ca87ca916ab
Parent: fadb42f8f3c97b5a4106682abef660c2ea2e0b73
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Fri Jan 9 12:27:57 2015 -0600
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Thu Jan 22 14:12:08 2015 -0600
fsck.gfs2: Rebuild system files if they don't have the SYS bit set
This patch checks for the GFS2_DIF_SYSTEM bit on system dinodes. If the
bit is not set, the dinode is assumed to be corrupt and rebuilt.
If the jindex is rebuilt, it needs to be re-read.
---
gfs2/fsck/pass1.c | 55 +++++++++++++++++++++++++++++++++++++++-------------
1 files changed, 41 insertions(+), 14 deletions(-)
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index 2841b8c..4348683 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -27,6 +27,7 @@
#include "util.h"
#include "link.h"
#include "metawalk.h"
+#include "fs_recovery.h"
struct special_blocks gfs1_rindex_blks;
@@ -1241,7 +1242,8 @@ static int check_system_inode(struct gfs2_sbd *sdp,
struct gfs2_inode **sysinode,
const char *filename,
int builder(struct gfs2_sbd *sdp),
- enum gfs2_mark_block mark)
+ enum gfs2_mark_block mark,
+ struct gfs2_inode *sysdir, int needs_sysbit)
{
uint64_t iblock = 0;
struct dir_status ds = {0};
@@ -1282,6 +1284,24 @@ static int check_system_inode(struct gfs2_sbd *sdp,
if (mark == gfs2_inode_dir)
dirtree_insert((*sysinode)->i_di.di_num);
}
+ /* Make sure it's marked as a system file/directory */
+ if (needs_sysbit &&
+ !((*sysinode)->i_di.di_flags & GFS2_DIF_SYSTEM)) {
+ log_err( _("System inode %s is missing the 'system' "
+ "flag. It should be rebuilt.\n"), filename);
+ if (sysdir && query(_("Delete the corrupt %s system "
+ "inode? (y/n) "), filename)) {
+ inode_put(sysinode);
+ gfs2_dirent_del(sysdir, filename,
+ strlen(filename));
+ /* Set the blockmap (but not bitmap) back to
+ 'free' so that it gets checked like any
+ normal dinode. */
+ gfs2_blockmap_set(bl, iblock, gfs2_block_free);
+ log_err( _("Removed system inode \"%s\".\n"),
+ filename);
+ }
+ }
} else
log_info( _("System inode for '%s' is corrupt or missing.\n"),
filename);
@@ -1290,18 +1310,22 @@ static int check_system_inode(struct gfs2_sbd *sdp,
lost+found then, but we *need* our system inodes before we can
do any of that. */
if (!(*sysinode) || ds.q != mark) {
- log_err( _("Invalid or missing %s system inode (should be %d, "
- "is %d).\n"), filename, mark, ds.q);
+ log_err( _("Invalid or missing %s system inode (should be "
+ "'%s', is '%s').\n"), filename,
+ block_type_string(mark),
+ block_type_string(ds.q));
if (query(_("Create new %s system inode? (y/n) "), filename)) {
log_err( _("Rebuilding system file \"%s\"\n"),
filename);
error = builder(sdp);
if (error) {
- log_err( _("Error trying to rebuild system "
- "file %s: Cannot continue\n"),
+ log_err( _("Error rebuilding system "
+ "inode %s: Cannot continue\n"),
filename);
return error;
}
+ if (*sysinode == sdp->md.jiinode)
+ ji_update(sdp);
fsck_blockmap_set(*sysinode,
(*sysinode)->i_di.di_num.no_addr,
filename, mark);
@@ -1367,7 +1391,8 @@ static int check_system_inodes(struct gfs2_sbd *sdp)
sdp->master_dir->i_di.di_num.no_addr,
"master", gfs2_inode_dir);
if (check_system_inode(sdp, &sdp->master_dir, "master",
- build_master, gfs2_inode_dir)) {
+ build_master, gfs2_inode_dir,
+ NULL, 1)) {
stack;
return -1;
}
@@ -1377,39 +1402,41 @@ static int check_system_inodes(struct gfs2_sbd *sdp)
fsck_blockmap_set(sdp->md.rooti, sdp->md.rooti->i_di.di_num.no_addr,
"root", gfs2_inode_dir);
if (check_system_inode(sdp, &sdp->md.rooti, "root", build_root,
- gfs2_inode_dir)) {
+ gfs2_inode_dir, NULL, 0)) {
stack;
return -1;
}
if (!sdp->gfs1 &&
check_system_inode(sdp, &sdp->md.inum, "inum", build_inum,
- gfs2_inode_file)) {
+ gfs2_inode_file, sdp->master_dir, 1)) {
stack;
return -1;
}
if (check_system_inode(sdp, &sdp->md.statfs, "statfs", build_statfs,
- gfs2_inode_file)) {
+ gfs2_inode_file, sdp->master_dir, !sdp->gfs1)) {
stack;
return -1;
}
if (check_system_inode(sdp, &sdp->md.jiinode, "jindex", build_jindex,
- (sdp->gfs1 ? gfs2_inode_file : gfs2_inode_dir))) {
+ (sdp->gfs1 ? gfs2_inode_file : gfs2_inode_dir),
+ sdp->master_dir, !sdp->gfs1)) {
stack;
return -1;
}
if (check_system_inode(sdp, &sdp->md.riinode, "rindex", build_rindex,
- gfs2_inode_file)) {
+ gfs2_inode_file, sdp->master_dir, !sdp->gfs1)) {
stack;
return -1;
}
if (check_system_inode(sdp, &sdp->md.qinode, "quota", build_quota,
- gfs2_inode_file)) {
+ gfs2_inode_file, sdp->master_dir, !sdp->gfs1)) {
stack;
return -1;
}
if (!sdp->gfs1 &&
check_system_inode(sdp, &sdp->md.pinode, "per_node",
- build_per_node, gfs2_inode_dir)) {
+ build_per_node, gfs2_inode_dir,
+ sdp->master_dir, 1)) {
stack;
return -1;
}
@@ -1438,7 +1465,7 @@ static int check_system_inodes(struct gfs2_sbd *sdp)
sprintf(jname, "journal%d", sdp->md.journals);
if (check_system_inode(sdp, &sdp->md.journal[sdp->md.journals],
jname, build_a_journal,
- gfs2_inode_file)) {
+ gfs2_inode_file, sdp->md.jiinode, 1)) {
stack;
return -1;
}
9 years, 3 months
gfs2-utils: master - gfs2-utils tests: Document usage of convenience macros
by Andrew Price
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=fadb42f8...
Commit: fadb42f8f3c97b5a4106682abef660c2ea2e0b73
Parent: 0352f73791b80745c17f651f55faf7ce3a28d435
Author: Andrew Price <anprice(a)redhat.com>
AuthorDate: Wed Jan 14 15:21:06 2015 +0000
Committer: Andrew Price <anprice(a)redhat.com>
CommitterDate: Fri Jan 16 12:04:26 2015 +0000
gfs2-utils tests: Document usage of convenience macros
Lower the barrier to writing tests by adding some docs to clarify the m4
convenience macros in testsuite.at.
Signed-off-by: Andrew Price <anprice(a)redhat.com>
---
tests/testsuite.at | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/tests/testsuite.at b/tests/testsuite.at
index aa86966..0422b02 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -1,15 +1,18 @@
# Regenerate the sparse file used for testing and skip the test if it fails
+# Usage: GFS_TGT_REGEN
m4_define([GFS_TGT_REGEN],
[AT_CHECK([rm -f $GFS_TGT && truncate -s ${GFS_TGT_SZ}G ${GFS_TGT}], [ignore], [ignore], [ignore])
AT_SKIP_IF([test ! -f ${GFS_TGT}])])
# Regenerate, check, fsck is used a lot so combine it into one macro
+# Usage: GFS_FSCK_CHECK ([mkfs.gfs2 ... $GFS_TGT])
m4_define([GFS_FSCK_CHECK],
[GFS_TGT_REGEN
AT_CHECK($1, 0, [ignore], [ignore])
AT_CHECK([fsck.gfs2 -n $GFS_TGT], 0, [ignore], [ignore])])
# Regenerate, mkfs, modify fs with gfs2l, fsck
+# Usage: GFS_TGT_REGEN ([<mkfs.gfs2 command>], [<gfs2l script>])
m4_define([GFS_LANG_CHECK],
[GFS_TGT_REGEN
AT_CHECK($1, 0, [ignore], [ignore])
9 years, 3 months
gfs2-utils: master - gfs2-utils tests: Skip unit tests if check is not found
by Andrew Price
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=0352f737...
Commit: 0352f73791b80745c17f651f55faf7ce3a28d435
Parent: 7a54f62b693f4b9e89de20c29e5d8db6d8ced34d
Author: Andrew Price <anprice(a)redhat.com>
AuthorDate: Wed Jan 14 15:05:25 2015 +0000
Committer: Andrew Price <anprice(a)redhat.com>
CommitterDate: Fri Jan 16 12:04:19 2015 +0000
gfs2-utils tests: Skip unit tests if check is not found
The check package (check-devel in Fedora) is required for building the
unit tests. When the configure script doesn't find check, it prevents
the unit tests from being built, but the test suite still tries to run
the unit tests. Introduce a wrapper m4 macro GFS_UNIT_TEST to set up
unit test test groups which will be skipped if check was not found in
the configure stage.
Signed-off-by: Andrew Price <anprice(a)redhat.com>
---
configure.ac | 2 +-
tests/Makefile.am | 13 +++++++------
tests/libgfs2.at | 6 ++----
tests/testsuite.at | 8 ++++++++
4 files changed, 18 insertions(+), 11 deletions(-)
diff --git a/configure.ac b/configure.ac
index 2341730..a523be3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -97,7 +97,7 @@ AC_ARG_ENABLE([gcov],
PKG_CHECK_MODULES([check], [check >= 0.9.8],
[have_check=yes],
[have_check=no])
-AM_CONDITIONAL([BUILD_TESTS], [test "x$have_check" = "xyes"])
+AM_CONDITIONAL([HAVE_CHECK], [test "x$have_check" = "xyes"])
PKG_CHECK_MODULES([zlib],[zlib])
PKG_CHECK_MODULES([blkid],[blkid])
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 475f4a7..3abb640 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -2,7 +2,7 @@ EXTRA_DIST = $(TESTSUITE_AT) package.m4 $(TESTSUITE) atlocal atconfig
DISTCLEANFILES = atlocal atconfig
CLEANFILES = testvol
-if BUILD_TESTS
+if HAVE_CHECK
UNIT_TESTS = \
check_meta \
check_rgrp
@@ -55,19 +55,20 @@ TESTSUITE_AT = \
testsuite.at \
mkfs.at \
fsck.at \
- edit.at
+ edit.at \
+ libgfs2.at
-if BUILD_TESTS
-TESTSUITE_AT += libgfs2.at
+if HAVE_CHECK
+ENABLE_UNIT=yes
endif
TESTSUITE = $(srcdir)/testsuite
check-local: atconfig atlocal $(TESTSUITE)
- $(SHELL) '$(TESTSUITE)' $(TOPTS)
+ $(SHELL) '$(TESTSUITE)' ENABLE_UNIT_TESTS=$(ENABLE_UNIT) $(TOPTS)
installcheck-local: atconfig atlocal $(TESTSUITE)
- $(SHELL) '$(TESTSUITE)' AUTOTEST_PATH='$(sbindir):tests' $(TOPTS)
+ $(SHELL) '$(TESTSUITE)' AUTOTEST_PATH='$(sbindir):tests' ENABLE_UNIT_TESTS=$(ENABLE_UNIT) $(TOPTS)
clean-local:
test ! -f '$(TESTSUITE)' || $(SHELL) '$(TESTSUITE)' --clean
diff --git a/tests/libgfs2.at b/tests/libgfs2.at
index a5bee87..1d2243c 100644
--- a/tests/libgfs2.at
+++ b/tests/libgfs2.at
@@ -1,11 +1,9 @@
AT_BANNER([libgfs2 unit tests])
-AT_SETUP([meta.c])
-AT_KEYWORDS(libgfs2)
+GFS_UNIT_TEST([meta.c],[libgfs2])
AT_CHECK([check_meta], 0, [ignore], [ignore])
AT_CLEANUP
-AT_SETUP([rgrp.c])
-AT_KEYWORDS(libgfs2)
+GFS_UNIT_TEST([rgrp.c],[libgfs2])
AT_CHECK([check_rgrp], 0, [ignore], [ignore])
AT_CLEANUP
diff --git a/tests/testsuite.at b/tests/testsuite.at
index fe781a7..aa86966 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -17,6 +17,14 @@ AT_CHECK([echo "$2" | gfs2l ${GFS_TGT}], 0, [ignore], [ignore])
AT_CHECK([fsck.gfs2 -y $GFS_TGT], 1, [ignore], [ignore])
AT_CHECK([fsck.gfs2 -n $GFS_TGT], 0, [ignore], [ignore])])
+# Set up a unit test, skipping if unit tests are disabled
+# Usage: GFS_UNIT_TEST ([name], [keywords])
+m4_define([GFS_UNIT_TEST],
+[AT_SETUP($1)
+AT_KEYWORDS($2)
+AT_CHECK([test x"$ENABLE_UNIT_TESTS" = "xyes" || exit 77])])
+
+# Test suite begins here
AT_INIT([])
AT_COLOR_TESTS
9 years, 3 months
gfs2-utils: master - gfs2-utils tests: Improve docs
by Andrew Price
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=7a54f62b...
Commit: 7a54f62b693f4b9e89de20c29e5d8db6d8ced34d
Parent: 8cd4466f8f0518f74f74ecafb228cf2ea03c356d
Author: Andrew Price <anprice(a)redhat.com>
AuthorDate: Wed Jan 14 12:30:04 2015 +0000
Committer: Andrew Price <anprice(a)redhat.com>
CommitterDate: Fri Jan 16 12:04:10 2015 +0000
gfs2-utils tests: Improve docs
Add a pointer to doc/README.tests in README.build and be more consistent
about how the test suite is run in doc/README.tests. Add example usage
and mention the TOPTS argument.
Signed-off-by: Andrew Price <anprice(a)redhat.com>
---
README.build | 3 ++-
doc/README.tests | 32 ++++++++++++++++++++++++--------
2 files changed, 26 insertions(+), 9 deletions(-)
diff --git a/README.build b/README.build
index 2aad6ab..f4ebe53 100644
--- a/README.build
+++ b/README.build
@@ -29,4 +29,5 @@ To install gfs2-utils, run:
make install
-See also doc/README.contributing for details on submitting patches.
+See also doc/README.contributing for details on submitting patches and
+doc/README.tests for more details regarding the test suite.
diff --git a/doc/README.tests b/doc/README.tests
index 79f51f6..1b90a0c 100644
--- a/doc/README.tests
+++ b/doc/README.tests
@@ -1,16 +1,30 @@
Working with the gfs2-utils test suite
--------------------------------------
+Overview
+--------
The test suite in the tests directory of the gfs2-utils source tree is based on
the Autotest framework provided by Autoconf. The basic idea is that the
testsuite.at file is the main source file for the tests, written in m4 and
-generating a bourne shell script called testsuite.
+generating a bourne shell script called testsuite, which we run with 'make check'.
-When run, either using 'make check' or directly from within the tests
-directory, the testsuite script sources atconfig and atlocal for configuration
-and then runs the whole testsuite or a specified set of tests (see ./testsuite
--h for help).
+When run, the test suite sources tests/atconfig and tests/atlocal for
+configuration and then runs the whole suite or a specified set of tests,
+depending on options passed to the test suite using TOPTS. For example, to see
+a list of available options, use 'make check TOPTS=-h' and to see a numbered
+list of the available tests, use 'make check TOPTS=-l'.
+A subset of the available tests can be run using keywords and/or by specifying
+the test ID numbers in TOPTS, e.g. make check TOPTS='-k mkfs 24 25'
+
+Test output is captured and, if a test fails, a log is kept in
+tests/testsuite.dir/$n/testsuite.log where $n is the test's ID number. Failed
+tests can be re-run using make check TOPTS='--recheck' although it's better to
+re-run the entire suite after fixing tests as a fix for one test could break
+another.
+
+Writing tests
+-------------
A number of GFS2-specific convenience macros have been defined in testsuite.at
to make defining new tests quick and easy. Also, some variables have been
defined in atlocal.in so that full paths to programs do not have to be included
@@ -32,15 +46,17 @@ do not fit into an existing category, in which case AT_BANNER can be used to
group them, and they can be organised into a new .at file and sourced from
testsuite.at.
-Since the tests can be run individually (e.g. ./testsuite 15) any new tests
-which require the dummy volume $GFS_TGT to be present should call GFS_TGT_REGEN
-before attempting to use it.
+As the tests can be run individually, any new tests which require the dummy
+volume $GFS_TGT to be present should call GFS_TGT_REGEN before attempting to
+use it.
Documentation for Autotest, including the AT_* macros used to define tests, can
be found in the autoconf manual at:
http://www.gnu.org/software/autoconf/manual/index.html
+Generating coverage reports
+---------------------------
Test coverage instrumentation can be enabled using the --enable-gcov option at
the configure stage. Once the tools have been built and run with this option
enabled, coverage data will be written to files in the source directories for
9 years, 3 months
gfs2-utils: master - gfs2-utils tests: Shorten TESTSUITEFLAGS to TOPTS
by Andrew Price
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=8cd4466f...
Commit: 8cd4466f8f0518f74f74ecafb228cf2ea03c356d
Parent: 4bd4d4a0817225d04080488e3f4688278135b2a3
Author: Andrew Price <anprice(a)redhat.com>
AuthorDate: Wed Jan 14 12:02:37 2015 +0000
Committer: Andrew Price <anprice(a)redhat.com>
CommitterDate: Fri Jan 16 12:04:01 2015 +0000
gfs2-utils tests: Shorten TESTSUITEFLAGS to TOPTS
TESTSUITEFLAGS is too long, replace it with TOPTS
Signed-off-by: Andrew Price <anprice(a)redhat.com>
---
tests/Makefile.am | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/tests/Makefile.am b/tests/Makefile.am
index b912dfa..475f4a7 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -64,10 +64,10 @@ endif
TESTSUITE = $(srcdir)/testsuite
check-local: atconfig atlocal $(TESTSUITE)
- $(SHELL) '$(TESTSUITE)' $(TESTSUITEFLAGS)
+ $(SHELL) '$(TESTSUITE)' $(TOPTS)
installcheck-local: atconfig atlocal $(TESTSUITE)
- $(SHELL) '$(TESTSUITE)' AUTOTEST_PATH='$(sbindir):tests' $(TESTSUITEFLAGS)
+ $(SHELL) '$(TESTSUITE)' AUTOTEST_PATH='$(sbindir):tests' $(TOPTS)
clean-local:
test ! -f '$(TESTSUITE)' || $(SHELL) '$(TESTSUITE)' --clean
9 years, 3 months
gfs2-utils: master - gfs2-utils tests: Add keywords to tests
by Andrew Price
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=4bd4d4a0...
Commit: 4bd4d4a0817225d04080488e3f4688278135b2a3
Parent: d07e72747f3f832d2f68f1a9788358fe4a4739b0
Author: Andrew Price <anprice(a)redhat.com>
AuthorDate: Wed Jan 14 11:42:50 2015 +0000
Committer: Andrew Price <anprice(a)redhat.com>
CommitterDate: Fri Jan 16 12:03:52 2015 +0000
gfs2-utils tests: Add keywords to tests
The testsuite script generated by autotest accepts a -k <keyword> option
which limits the set of tests to be run to a specified group. Add
keywords to tests to take advantage of this feature.
Signed-off-by: Andrew Price <anprice(a)redhat.com>
---
tests/edit.at | 5 +++++
tests/fsck.at | 2 ++
tests/libgfs2.at | 2 ++
tests/mkfs.at | 16 ++++++++++++++++
4 files changed, 25 insertions(+), 0 deletions(-)
diff --git a/tests/edit.at b/tests/edit.at
index 49f4a58..e3f02e6 100644
--- a/tests/edit.at
+++ b/tests/edit.at
@@ -2,6 +2,7 @@ AT_TESTED([gfs2_edit])
AT_BANNER([gfs2_edit tests])
AT_SETUP([Save/restoremeta, defaults])
+AT_KEYWORDS(gfs2_edit edit)
GFS_TGT_REGEN
AT_CHECK([$GFS_MKFS -p lock_nolock $GFS_TGT $(($(gfs_max_blocks 4096)/2))], 0, [ignore], [ignore])
AT_CHECK([gfs2_edit savemeta $GFS_TGT test.meta > savemeta.log], 0, [ignore], [ignore])
@@ -14,6 +15,7 @@ AT_CHECK([fsck.gfs2 -n $GFS_TGT], 0, [ignore], [ignore])
AT_CLEANUP
AT_SETUP([Save/restoremeta, no compression])
+AT_KEYWORDS(gfs2_edit edit)
GFS_TGT_REGEN
AT_CHECK([$GFS_MKFS -p lock_nolock $GFS_TGT $(($(gfs_max_blocks 4096)/2))], 0, [ignore], [ignore])
AT_CHECK([gfs2_edit savemeta -z0 $GFS_TGT test.meta], 0, [ignore], [ignore])
@@ -23,6 +25,7 @@ AT_CHECK([fsck.gfs2 -n $GFS_TGT], 0, [ignore], [ignore])
AT_CLEANUP
AT_SETUP([Save/restoremeta, min. block size])
+AT_KEYWORDS(gfs2_edit edit)
GFS_TGT_REGEN
AT_CHECK([$GFS_MKFS -p lock_nolock -b512 $GFS_TGT], 0, [ignore], [ignore])
AT_CHECK([gfs2_edit savemeta -z0 $GFS_TGT test.meta], 0, [ignore], [ignore])
@@ -32,6 +35,7 @@ AT_CHECK([fsck.gfs2 -n $GFS_TGT], 0, [ignore], [ignore])
AT_CLEANUP
AT_SETUP([Save/restoremeta, 4 journals])
+AT_KEYWORDS(gfs2_edit edit)
GFS_TGT_REGEN
AT_CHECK([$GFS_MKFS -p lock_nolock -j4 -J8 $GFS_TGT], 0, [ignore], [ignore])
AT_CHECK([gfs2_edit savemeta -z0 $GFS_TGT test.meta], 0, [ignore], [ignore])
@@ -41,6 +45,7 @@ AT_CHECK([fsck.gfs2 -n $GFS_TGT], 0, [ignore], [ignore])
AT_CLEANUP
AT_SETUP([Save/restoremeta, min. block size, 4 journals])
+AT_KEYWORDS(gfs2_edit edit)
GFS_TGT_REGEN
AT_CHECK([$GFS_MKFS -p lock_nolock -b512 -j4 -J8 $GFS_TGT], 0, [ignore], [ignore])
AT_CHECK([gfs2_edit savemeta -z0 $GFS_TGT test.meta], 0, [ignore], [ignore])
diff --git a/tests/fsck.at b/tests/fsck.at
index e3b82bd..4d25f40 100644
--- a/tests/fsck.at
+++ b/tests/fsck.at
@@ -2,6 +2,7 @@ AT_TESTED([fsck.gfs2])
AT_BANNER([fsck.gfs2 tests])
AT_SETUP([Fix invalid block sizes])
+AT_KEYWORDS(fsck.gfs2 fsck)
GFS_LANG_CHECK([mkfs.gfs2 -O -p lock_nolock $GFS_TGT], [set sb { sb_bsize: 0 }])
GFS_LANG_CHECK([mkfs.gfs2 -O -p lock_nolock $GFS_TGT], [set sb { sb_bsize: 1 }])
GFS_LANG_CHECK([mkfs.gfs2 -O -p lock_nolock $GFS_TGT], [set sb { sb_bsize: 513 }])
@@ -10,5 +11,6 @@ GFS_LANG_CHECK([mkfs.gfs2 -O -p lock_nolock $GFS_TGT], [set sb { sb_bsize: 4097
AT_CLEANUP
AT_SETUP([Fix invalid goal blocks])
+AT_KEYWORDS(fsck.gfs2 fsck)
GFS_LANG_CHECK([mkfs.gfs2 -O -p lock_nolock $GFS_TGT], [set '/' { di_goal_meta: 0 }])
AT_CLEANUP
diff --git a/tests/libgfs2.at b/tests/libgfs2.at
index 8c44cdd..a5bee87 100644
--- a/tests/libgfs2.at
+++ b/tests/libgfs2.at
@@ -1,9 +1,11 @@
AT_BANNER([libgfs2 unit tests])
AT_SETUP([meta.c])
+AT_KEYWORDS(libgfs2)
AT_CHECK([check_meta], 0, [ignore], [ignore])
AT_CLEANUP
AT_SETUP([rgrp.c])
+AT_KEYWORDS(libgfs2)
AT_CHECK([check_rgrp], 0, [ignore], [ignore])
AT_CLEANUP
diff --git a/tests/mkfs.at b/tests/mkfs.at
index ff99bb1..438184c 100644
--- a/tests/mkfs.at
+++ b/tests/mkfs.at
@@ -2,36 +2,43 @@ AT_TESTED([mkfs.gfs2])
AT_BANNER([mkfs.gfs2 tests])
AT_SETUP([Locking protocol validation])
+AT_KEYWORDS(mkfs.gfs2 mkfs)
AT_CHECK([$GFS_MKFS -p badprotocol $GFS_TGT], 255, [ignore], [ignore])
AT_CLEANUP
AT_SETUP([Resource group size validation])
+AT_KEYWORDS(mkfs.gfs2 mkfs)
AT_CHECK([$GFS_MKFS -p lock_nolock -r 31 $GFS_TGT], 255, [ignore], [ignore])
AT_CHECK([$GFS_MKFS -p lock_nolock -r 2049 $GFS_TGT], 255, [ignore], [ignore])
AT_CLEANUP
AT_SETUP([Journal size validation])
+AT_KEYWORDS(mkfs.gfs2 mkfs)
AT_CHECK([$GFS_MKFS -p lock_nolock -J 7 $GFS_TGT], 255, [ignore], [ignore])
AT_CHECK([$GFS_MKFS -p lock_nolock -J 1025 $GFS_TGT], 255, [ignore], [ignore])
AT_CLEANUP
AT_SETUP([Block count validation])
+AT_KEYWORDS(mkfs.gfs2 mkfs)
GFS_TGT_REGEN
AT_CHECK([$GFS_MKFS -p lock_nolock -b 512 $GFS_TGT $(($(gfs_max_blocks 512)+1))], 255, [ignore], [ignore])
AT_CHECK([$GFS_MKFS -p lock_nolock -b 4096 $GFS_TGT $(($(gfs_max_blocks 4096)+1))], 255, [ignore], [ignore])
AT_CLEANUP
AT_SETUP([Quota change file size validation])
+AT_KEYWORDS(mkfs.gfs2 mkfs)
AT_CHECK([$GFS_MKFS -p lock_nolock -c 0 $GFS_TGT], 255, [ignore], [ignore])
AT_CHECK([$GFS_MKFS -p lock_nolock -c 65 $GFS_TGT], 255, [ignore], [ignore])
AT_CLEANUP
AT_SETUP([Locking protocols])
+AT_KEYWORDS(mkfs.gfs2 mkfs)
GFS_FSCK_CHECK([$GFS_MKFS -p lock_nolock $GFS_TGT])
GFS_FSCK_CHECK([$GFS_MKFS -p lock_dlm -t foo:bar $GFS_TGT])
AT_CLEANUP
AT_SETUP([Valid block sizes 512-4096])
+AT_KEYWORDS(mkfs.gfs2 mkfs)
GFS_FSCK_CHECK([$GFS_MKFS -p lock_nolock -b 512 $GFS_TGT])
GFS_FSCK_CHECK([$GFS_MKFS -p lock_nolock -b 1024 $GFS_TGT])
GFS_FSCK_CHECK([$GFS_MKFS -p lock_nolock -b 2048 $GFS_TGT])
@@ -39,37 +46,46 @@ GFS_FSCK_CHECK([$GFS_MKFS -p lock_nolock -b 4096 $GFS_TGT])
AT_CLEANUP
AT_SETUP([Max. blocks, min. block size])
+AT_KEYWORDS(mkfs.gfs2 mkfs)
GFS_FSCK_CHECK([$GFS_MKFS -p lock_nolock -b 512 $GFS_TGT $(gfs_max_blocks 512)])
AT_CLEANUP
AT_SETUP([Max. blocks, max. block size])
+AT_KEYWORDS(mkfs.gfs2 mkfs)
GFS_FSCK_CHECK([$GFS_MKFS -p lock_nolock -b 4096 $GFS_TGT $(util_max_blocks 4096)])
AT_CLEANUP
AT_SETUP([Max. resource group size])
+AT_KEYWORDS(mkfs.gfs2 mkfs)
GFS_FSCK_CHECK([$GFS_MKFS -p lock_nolock -r 2048 $GFS_TGT])
AT_CLEANUP
AT_SETUP([Min. resource group size])
+AT_KEYWORDS(mkfs.gfs2 mkfs)
GFS_FSCK_CHECK([$GFS_MKFS -p lock_nolock -r 32 $GFS_TGT])
AT_CLEANUP
AT_SETUP([Max. resource group size, min. block size])
+AT_KEYWORDS(mkfs.gfs2 mkfs)
GFS_FSCK_CHECK([$GFS_MKFS -p lock_nolock -r 2048 -b 512 $GFS_TGT])
AT_CLEANUP
AT_SETUP([Max. journal size])
+AT_KEYWORDS(mkfs.gfs2 mkfs)
GFS_FSCK_CHECK([$GFS_MKFS -p lock_nolock -J 1024 $GFS_TGT])
AT_CLEANUP
AT_SETUP([Min. journal size])
+AT_KEYWORDS(mkfs.gfs2 mkfs)
GFS_FSCK_CHECK([$GFS_MKFS -p lock_nolock -J 8 $GFS_TGT])
AT_CLEANUP
AT_SETUP([Max. quota change file size])
+AT_KEYWORDS(mkfs.gfs2 mkfs)
GFS_FSCK_CHECK([$GFS_MKFS -p lock_nolock -c 64 $GFS_TGT])
AT_CLEANUP
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
9 years, 3 months
cluster: RHEL6 - fsck.gfs2: addendum to fix broken i_goal values in inodes - addendum 2 of 2
by Abhijith Das
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=407dbe2a3df...
Commit: 407dbe2a3df3882a1e936e37e7c0a8505a2d44ac
Parent: 9b64bf4d044d835d5c203e7ce8fbb5a683f84867
Author: Abhi Das <adas(a)redhat.com>
AuthorDate: Thu Jan 15 15:26:31 2015 -0600
Committer: Abhi Das <adas(a)redhat.com>
CommitterDate: Thu Jan 15 15:26:31 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 two patches to fix this problem were
checked in against bz 1149516 as well. The complete fix contains
those two patches (de32500, 7933984) and this two-patch addendum
for a total of 4 patches.
Resolves: rhbz#1149516
Signed-off-by: Abhi Das <adas(a)redhat.com>
---
gfs2/fsck/metawalk.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++
gfs2/fsck/metawalk.h | 2 +
gfs2/fsck/pass1.c | 54 +++---------------------------------
gfs2/libgfs2/libgfs2.h | 1 +
4 files changed, 78 insertions(+), 49 deletions(-)
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 8dc59fb..07e5c18 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -1435,6 +1435,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;
@@ -1830,6 +1833,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,
@@ -1840,6 +1909,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 d4ffc62..8bd604d 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 9606101..1162066 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -60,7 +60,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,
@@ -98,7 +97,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,
@@ -792,48 +791,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)
@@ -1214,7 +1171,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;
@@ -1254,6 +1212,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;
@@ -1508,9 +1467,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
@@ -1654,7 +1610,7 @@ int pass1(struct gfs2_sbd *sdp)
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);
diff --git a/gfs2/libgfs2/libgfs2.h b/gfs2/libgfs2/libgfs2.h
index 9985c97..9c20f11 100644
--- a/gfs2/libgfs2/libgfs2.h
+++ b/gfs2/libgfs2/libgfs2.h
@@ -131,6 +131,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 */
};
#define BUF_HASH_SHIFT (13) /* # hash buckets = 8K */
9 years, 3 months
cluster: RHEL6 - fsck.gfs2: Reprocess nodes if anything changed - addendum 1 of 2
by Abhijith Das
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=9b64bf4d044...
Commit: 9b64bf4d044d835d5c203e7ce8fbb5a683f84867
Parent: 7933984ea9c3cd08e1a68a52f098f55b05ab0924
Author: Abhi Das <adas(a)redhat.com>
AuthorDate: Thu Jan 15 14:22:36 2015 -0600
Committer: Abhi Das <adas(a)redhat.com>
CommitterDate: Thu Jan 15 14:22:36 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 two patches to fix this problem were
checked in against bz 1149516 as well. The complete fix contains
those two patches (de32500, 7933984) and this two-patch addendum
for a total of 4 patches.
Resolves: rhbz#1149516
Signed-off-by: Bob Peterson <rpeterso(a)redhat.com>
---
gfs2/fsck/lost_n_found.c | 6 ------
gfs2/fsck/metawalk.c | 6 +++---
gfs2/fsck/pass2.c | 23 +++++++++++++----------
gfs2/fsck/pass3.c | 17 +++++++++++++----
gfs2/fsck/pass4.c | 6 ++++++
gfs2/fsck/util.h | 20 ++++++++++++++++++++
6 files changed, 55 insertions(+), 23 deletions(-)
diff --git a/gfs2/fsck/lost_n_found.c b/gfs2/fsck/lost_n_found.c
index c8265a2..ed4d35e 100644
--- a/gfs2/fsck/lost_n_found.c
+++ b/gfs2/fsck/lost_n_found.c
@@ -171,7 +171,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;
@@ -181,7 +180,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);
@@ -239,10 +237,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 075c2e1..8dc59fb 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -1578,11 +1578,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);
@@ -1592,7 +1592,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 2125233..dd030ce 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -1,3 +1,4 @@
+
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
@@ -1708,7 +1709,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};
char *filename;
int filename_len;
@@ -1723,14 +1725,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);
@@ -1751,7 +1753,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);
sprintf(tmp_name, ".");
filename_len = strlen(tmp_name); /* no trailing NULL */
if (!(filename = malloc(sizeof(char) * filename_len))) {
@@ -1778,7 +1780,7 @@ static int check_system_dir(struct gfs2_inode *sysinode, const char *dirname,
free(filename);
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,
@@ -1861,7 +1863,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;
@@ -1931,14 +1934,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);
@@ -2015,7 +2018,7 @@ int pass2(struct gfs2_sbd *sdp)
}
memcpy(filename, tmp_name, filename_len);
- cur_blks = ip->i_di.di_blocks;
+ astate_save(ip, &as);
error = dir_add(ip, filename, filename_len,
&(ip->i_di.di_num),
(sdp->gfs1 ? GFS_FILE_DIR :
@@ -2025,7 +2028,7 @@ int pass2(struct gfs2_sbd *sdp)
filename, 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 6a6305a..0b1a60a 100644
--- a/gfs2/fsck/pass3.c
+++ b/gfs2/fsck/pass3.c
@@ -20,7 +20,7 @@ static int attach_dotdot_to(struct gfs2_sbd *sdp, uint64_t newdotdot,
char *filename;
int filename_len, 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);
@@ -51,7 +51,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) {
@@ -59,7 +59,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)"),
@@ -192,6 +192,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) {
@@ -238,6 +239,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) {
@@ -340,8 +343,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 4605671..36fc38a 100644
--- a/gfs2/fsck/pass4.c
+++ b/gfs2/fsck/pass4.c
@@ -45,12 +45,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"));
@@ -179,6 +182,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 fe3fd6a..04ab1e2 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);
@@ -23,6 +28,21 @@ extern void dup_listent_delete(struct duptree *dt, struct inode_with_dups *id);
extern const char *reftypes[ref_types + 1];
+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;
9 years, 3 months