Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=704beb265c…
Commit: 704beb265cd6f860a10f4a5ae0fd8c52e72bf392
Parent: c78fedfd07a455e934b0a603c9c2e124b9522662
Author: Andrew Price <anprice(a)redhat.com>
AuthorDate: Tue Jul 19 15:41:13 2016 +0100
Committer: Andrew Price <anprice(a)redhat.com>
CommitterDate: Tue Jul 19 16:55:41 2016 +0100
gfs2(5): Clarify the availability of the loccookie option
The loccookie option was added in kernel-3.10.0-341.el7 but the first
release will be RHEL 7.3 so use that to clarify when 'loccookie' appears
in RHEL7.
Resolves: rhbz#1326508
Signed-off-by: Andrew Price <anprice(a)redhat.com>
---
gfs2/man/gfs2.5 | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/gfs2/man/gfs2.5 b/gfs2/man/gfs2.5
index 56d1a00..6c77519 100644
--- a/gfs2/man/gfs2.5
+++ b/gfs2/man/gfs2.5
@@ -193,7 +193,7 @@ give out well over half a billion location based cookies. This option was added
in the 4.5 Linux kernel. Prior to this kernel, gfs2 did not add directory
entries in a way that allowed it to use location based readdir cookies.
\fBNote:\fP To safely turn on this option, all nodes mounting the filesystem
-must be running at least a 4.5 Linux kernel. If this option is only enabled on
+must be running at least a 4.5 Linux kernel or RHEL 7.3. If this option is only enabled on
some of the nodes mounting a filesystem, the cookies returned by nodes using
this option will not be valid on nodes that are not using this option, and vice
versa. Finally, when first enabling this option on a filesystem that had been
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=a0fc4e870e…
Commit: a0fc4e870e6a4504de2b0911493451a43aaad261
Parent: ab92c41323babc6b6578cddfb4324ae545927f88
Author: Andrew Price <anprice(a)redhat.com>
AuthorDate: Wed Jun 29 00:29:03 2016 +0100
Committer: Andrew Price <anprice(a)redhat.com>
CommitterDate: Wed Jul 6 15:19:04 2016 +0100
gfs2_convert: Fix misleading indentation warning
Caught by the new -Wmisleading-indentation warning in gcc 6:
CC gfs2_convert-gfs2_convert.o
gfs2_convert.c: In function 'inode_renumber':
gfs2_convert.c:1073:5: warning: this 'if' clause does not guard...
if (block != rindex_addr && block != jindex_addr)
^~
gfs2_convert.c:1075:6: note: ...this statement, but the latter is
misleadingly indented as if it is guarded by the 'if'
if (error) {
^~
Fortunately, this wasn't actually a bug, it just caused the value of
'error' to be checked when it couldn't possibly be non-zero as well as
the one time it could be.
Signed-off-by: Andrew Price <anprice(a)redhat.com>
---
gfs2/convert/gfs2_convert.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/gfs2/convert/gfs2_convert.c b/gfs2/convert/gfs2_convert.c
index aac4853..9845049 100644
--- a/gfs2/convert/gfs2_convert.c
+++ b/gfs2/convert/gfs2_convert.c
@@ -1070,11 +1070,11 @@ static int inode_renumber(struct gfs2_sbd *sbp, uint64_t root_inode_addr, osi_li
bh = bread(sbp, block);
if (!gfs2_check_meta(bh, GFS_METATYPE_DI)) {/* if it is an dinode */
/* Skip the rindex and jindex inodes for now. */
- if (block != rindex_addr && block != jindex_addr)
+ if (block != rindex_addr && block != jindex_addr) {
error = adjust_inode(sbp, bh);
- if (error) {
+ if (error)
return error;
- }
+ }
} else { /* It's metadata, but not an inode, so fix the bitmap. */
int blk, buf_offset;
int bitmap_byte; /* byte within the bitmap to fix */
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=c78fedfd07…
Commit: c78fedfd07a455e934b0a603c9c2e124b9522662
Parent: 1adddb1098c10766ae2587d393c1612e5670a52d
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Fri Jun 24 08:53:41 2016 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Wed Jul 6 08:00:01 2016 -0500
fsck.gfs2: check formal inode number when links go from 1 to 2
Before commit f2ffb1e, function basic_dentry_checks had access to a
complete inode tree, so it was able to check the formal inode number
of every dentry against what it previously found in the inode in
pass1. But commit f2ffb1e changed function basic_dentry_checks so
that it bypasses the check if the reference count is 1, which is
most likely, and it's going to be correct 99% of the time. The
comments state:
"Since we don't have ii or di, the only way to validate formal_ino
is to read in the inode, which would kill performance. So skip it
for now."
The problem is, problems can slip through, undetected, and will
only be fixed with a second run of fsck.gfs2. For example, during
testing, I found a set of gfs2 metadata that had two dentries
pointing to the same dinode. The first dentry encountered by pass2
was wrong, but it was not checked for this reason. The second
dentry was correct. The first run of fsck did not catch the problem
and reacted by setting link count to 2 for the dinode, keeping
both dentries. The second run found the problem and fixed it,
changing the link count back to 1 and deleting the bad dentry.
Note that this problem only applies to non-directories, since
directories will have a value in the dirtree to check against.
This patch solves the problem with a new "innocent until proven
guilty" approach. When the first dentry reference is found, it is
assumed to be correct (most files will have a single link).
When the second dentry reference is found, it goes back and checks
the original reference. To do that, it takes the (time expensive)
step of traversing the directory tree, searching every directory
for the original reference. Once the original dentry is found, it
checks its formal inode number against the one that has been proven
correct. This situation ought to be quite rare because the vast
number of files will have a single correct link. So hopefully only
valid hard links will cause the slow tree traversal. Once the first
dentry is found, the tree traversal stops and pass2 continues its
work.
Signed-off-by: Bob Peterson <rpeterso(a)redhat.com>
This is a RHEL7 port of this upstream patch:
https://git.fedorahosted.org/cgit/gfs2-utils.git/commit/?id=ab92c41323babc6…
rhbz#1350600
---
gfs2/fsck/link.c | 20 +++++----
gfs2/fsck/link.h | 7 +++
gfs2/fsck/pass2.c | 118 +++++++++++++++++++++++++++++++++++++++++++++++++++--
3 files changed, 133 insertions(+), 12 deletions(-)
diff --git a/gfs2/fsck/link.c b/gfs2/fsck/link.c
index 00636d7..8ea09c7 100644
--- a/gfs2/fsck/link.c
+++ b/gfs2/fsck/link.c
@@ -88,33 +88,33 @@ int incr_link_count(struct gfs2_inum no, struct gfs2_inode *ip,
di = dirtree_find(no.no_addr);
if (di) {
if (di->dinode.no_formal_ino != no.no_formal_ino)
- return 1;
+ return incr_link_ino_mismatch;
di->counted_links++;
whyincr(no.no_addr, why, referenced_from, di->counted_links);
- return 0;
+ return incr_link_good;
}
ii = inodetree_find(no.no_addr);
/* If the list has entries, look for one that matches inode_no */
if (ii) {
if (ii->di_num.no_formal_ino != no.no_formal_ino)
- return 1;
+ return incr_link_ino_mismatch;
ii->counted_links++;
whyincr(no.no_addr, why, referenced_from, ii->counted_links);
- return 0;
+ return incr_link_good;
}
if (link1_type(&clink1map, no.no_addr) != 1) {
link1_set(&clink1map, no.no_addr, 1);
whyincr(no.no_addr, why, referenced_from, 1);
- return 0;
+ return incr_link_good;
}
link_ip = fsck_load_inode(ip->i_sbd, no.no_addr);
/* Check formal ino against dinode before adding to inode tree. */
if (no.no_formal_ino != link_ip->i_di.di_num.no_formal_ino) {
fsck_inode_put(&link_ip);
- return 1;
+ return incr_link_ino_mismatch; /* inode mismatch */
}
/* Move it from the link1 maps to a real inode tree entry */
link1_set(&nlink1map, no.no_addr, 0);
@@ -130,7 +130,7 @@ int incr_link_count(struct gfs2_inum no, struct gfs2_inode *ip,
(unsigned long long)referenced_from,
(unsigned long long)no.no_addr);
fsck_inode_put(&link_ip);
- return -1;
+ return incr_link_bad;
}
ii->di_num = link_ip->i_di.di_num;
fsck_inode_put(&link_ip);
@@ -138,7 +138,11 @@ int incr_link_count(struct gfs2_inum no, struct gfs2_inode *ip,
nlink1map */
ii->counted_links = 2;
whyincr(no.no_addr, why, referenced_from, ii->counted_links);
- return 0;
+ /* We transitioned a dentry link count from 1 to 2, and we know it's
+ not a directory. But the new reference has the correct formal
+ inode number, so the first reference is suspect: we need to
+ check it in case it's a bad reference, and not just a hard link. */
+ return incr_link_check_orig;
}
#define whydecr(no_addr, why, referenced_from, counted_links) \
diff --git a/gfs2/fsck/link.h b/gfs2/fsck/link.h
index 14534e5..a5dd1c8 100644
--- a/gfs2/fsck/link.h
+++ b/gfs2/fsck/link.h
@@ -4,6 +4,13 @@
extern struct gfs2_bmap nlink1map; /* map of dinodes with nlink == 1 */
extern struct gfs2_bmap clink1map; /* map of dinodes w/counted links == 1 */
+enum {
+ incr_link_bad = -1,
+ incr_link_good = 0,
+ incr_link_ino_mismatch = 1,
+ incr_link_check_orig = 2,
+};
+
int link1_set(struct gfs2_bmap *bmap, uint64_t bblock, int mark);
int set_di_nlink(struct gfs2_inode *ip);
int incr_link_count(struct gfs2_inum no, struct gfs2_inode *ip,
diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
index 8ac5547..808cf21 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -667,6 +667,113 @@ static int basic_dentry_checks(struct gfs2_inode *ip, struct gfs2_dirent *dent,
return 0;
}
+static int dirref_find(struct gfs2_inode *ip, struct gfs2_dirent *dent,
+ struct gfs2_dirent *prev, struct gfs2_buffer_head *bh,
+ char *filename, uint32_t *count, int *lindex,
+ void *private)
+{
+ /* the metawalk_fxn's private field must be set to the dentry
+ * block we want to clear */
+ struct gfs2_inum *entry = (struct gfs2_inum *)private;
+ struct gfs2_dirent dentry, *de;
+ char fn[MAX_FILENAME];
+
+ memset(&dentry, 0, sizeof(struct gfs2_dirent));
+ gfs2_dirent_in(&dentry, (char *)dent);
+ de = &dentry;
+
+ if (de->de_inum.no_addr != entry->no_addr) {
+ (*count)++;
+ return 0;
+ }
+ if (de->de_inum.no_formal_ino == dent->de_inum.no_formal_ino) {
+ log_debug("Formal inode number matches; must be a hard "
+ "link.\n");
+ goto out;
+ }
+ log_err(_("The original reference to inode %lld (0x%llx) from "
+ "directory %lld (0x%llx) has the wrong 'formal' inode "
+ "number.\n"), (unsigned long long)entry->no_addr,
+ (unsigned long long)entry->no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr);
+ memset(fn, 0, sizeof(fn));
+ if (de->de_name_len < MAX_FILENAME)
+ strncpy(fn, filename, de->de_name_len);
+ else
+ strncpy(fn, filename, MAX_FILENAME - 1);
+ log_err(_("The bad reference '%s' had formal inode number: %lld "
+ "(0x%llx) but the correct value is: %lld (0x%llx)\n"),
+ fn, (unsigned long long)de->de_inum.no_formal_ino,
+ (unsigned long long)de->de_inum.no_formal_ino,
+ (unsigned long long)entry->no_formal_ino,
+ (unsigned long long)entry->no_formal_ino);
+ if (!query(_("Delete the bad directory entry? (y/n) "))) {
+ log_err(_("The corrupt directory entry was not fixed.\n"));
+ goto out;
+ }
+ decr_link_count(entry->no_addr, ip->i_di.di_num.no_addr,
+ ip->i_sbd->gfs1, _("bad original reference"));
+ dirent2_del(ip, bh, prev, dent);
+ log_err(_("The corrupt directory entry '%s' was deleted.\n"), fn);
+out:
+ return -1; /* force check_dir to stop; don't waste time. */
+}
+
+/**
+ * check_suspicious_dirref - double-check a questionable first dentry ref
+ *
+ * This function is called when a dentry has caused us to increment the
+ * link count to a file from 1 to 2, and we know the object pointed to is
+ * not a directory. (Most likely, it'a a file). The second directory to
+ * reference the dinode has the correct formal inode number, but when we
+ * created the original reference in the counted links bitmap (clink1map),
+ * we had no way to check the formal inode number. (Well, we could have read
+ * in the dinode, but that would kill fsck.gfs2 performance.)
+ * So now we have to walk through the directory tree and find that original
+ * reference so make sure it's a valid reference. If the formal inode number
+ * is the same, it's a hard link (which is unlikely for gfs2). If it's not
+ * the same, that's an error, and we need to delete the damaged original
+ * dentry, since we failed to detect the problem earlier.
+ */
+static int check_suspicious_dirref(struct gfs2_sbd *sdp,
+ struct gfs2_inum *entry)
+{
+ struct osi_node *tmp, *next = NULL;
+ struct dir_info *dt;
+ struct gfs2_inode *ip;
+ uint64_t dirblk;
+ int error = FSCK_OK;
+ struct metawalk_fxns dirref_hunt = {
+ .private = (void *)entry,
+ .check_dentry = dirref_find,
+ };
+
+ log_debug("This dentry is good, but since this is a second "
+ "reference to block 0x%llx, we need to check the "
+ "original.\n", (unsigned long long)entry->no_addr);
+ for (tmp = osi_first(&dirtree); tmp; tmp = next) {
+ next = osi_next(tmp);
+ dt = (struct dir_info *)tmp;
+ dirblk = dt->dinode.no_addr;
+ if (skip_this_pass || fsck_abort) /* asked to skip the rest */
+ break;
+ ip = fsck_load_inode(sdp, dirblk);
+ if (ip == NULL) {
+ stack;
+ return FSCK_ERROR;
+ }
+ error = check_dir(sdp, ip, &dirref_hunt);
+ fsck_inode_put(&ip);
+ /* Error just means we found the dentry and dealt with it. */
+ if (error)
+ break;
+ }
+ log_debug("Original reference check complete. Found = %d.\n",
+ error ? 1 : 0);
+ return 0;
+}
+
/* FIXME: should maybe refactor this a bit - but need to deal with
* FIXMEs internally first */
static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
@@ -870,10 +977,13 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
dentry_is_valid:
/* This directory inode links to this inode via this dentry */
error = incr_link_count(entry, ip, _("valid reference"));
- if (error > 0 &&
- bad_formal_ino(ip, dent, entry, tmp_name, q, de, bh) == 1)
- goto nuke_dentry;
-
+ if (error == incr_link_check_orig) {
+ error = check_suspicious_dirref(sdp, &entry);
+ } else if (error == incr_link_ino_mismatch) {
+ log_err("incr_link_count err=%d.\n", error);
+ if (bad_formal_ino(ip, dent, entry, tmp_name, q, de, bh) == 1)
+ goto nuke_dentry;
+ }
(*count)++;
ds->entry_count++;
/* End of checks */
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=1adddb1098…
Commit: 1adddb1098c10766ae2587d393c1612e5670a52d
Parent: 0a0d4af99c9be8abc863e272d6e7f46bb6ad4b41
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Thu Jun 23 08:16:25 2016 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Wed Jul 6 07:57:25 2016 -0500
fsck.gfs2: link count checking wrong inode's formal inode number
This patch fixes a bug whereby inodes that aren't in the dirtree or
the inodetree are checking the wrong formal inode number. Function
incr_link_count checks the wrong inode value, and thus reports an
error where there are none. Also, when the error is reported back,
it reports the wrong value, using a copy of the inum value. In this
case, it should look up the dentry's inode's formal inode number.
This should only hurt performance in error cases.
Signed-off-by: Bob Peterson <rpeterso(a)redhat.com>
This is a RHEL7 port of this upstream patch:
https://git.fedorahosted.org/cgit/gfs2-utils.git/commit/?id=ad19203f04caa3f…
rhbz#1350597
---
gfs2/fsck/link.c | 2 +-
gfs2/fsck/pass2.c | 9 +++++++--
2 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/gfs2/fsck/link.c b/gfs2/fsck/link.c
index 0243d85..00636d7 100644
--- a/gfs2/fsck/link.c
+++ b/gfs2/fsck/link.c
@@ -112,7 +112,7 @@ int incr_link_count(struct gfs2_inum no, struct gfs2_inode *ip,
link_ip = fsck_load_inode(ip->i_sbd, no.no_addr);
/* Check formal ino against dinode before adding to inode tree. */
- if (no.no_formal_ino != ip->i_di.di_num.no_formal_ino) {
+ if (no.no_formal_ino != link_ip->i_di.di_num.no_formal_ino) {
fsck_inode_put(&link_ip);
return 1;
}
diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
index f808cea..8ac5547 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -195,8 +195,13 @@ static int bad_formal_ino(struct gfs2_inode *ip, struct gfs2_dirent *dent,
di = dirtree_find(entry.no_addr);
if (di)
inum = di->dinode;
- else if (link1_type(&clink1map, entry.no_addr) == 1)
- inum = entry;
+ else if (link1_type(&clink1map, entry.no_addr) == 1) {
+ struct gfs2_inode *dent_ip;
+
+ dent_ip = fsck_load_inode(ip->i_sbd, entry.no_addr);
+ inum = dent_ip->i_di.di_num;
+ fsck_inode_put(&dent_ip);
+ }
}
log_err( _("Directory entry '%s' pointing to block %llu (0x%llx) in "
"directory %llu (0x%llx) has the wrong 'formal' inode "
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=0a0d4af99c…
Commit: 0a0d4af99c9be8abc863e272d6e7f46bb6ad4b41
Parent: 0187f95861092a5e06c31e35ce8a2b778bd9958d
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Tue Jun 21 14:52:06 2016 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Wed Jul 6 07:53:20 2016 -0500
fsck.gfs2: "undo" functions can stop too early on duplicates
This patch addresses a bug in which blocks may not be freed properly
because the "undo" processing in pass1 can stop early when duplicate
data blocks are encountered. What happens is this: The "undo" process
called from metawalk.c is coded to stop its undo when it encounters
the block containing corruption. However, if the block containing the
corruption is actually the second reference to the same block, inside
the same dinode, the undo process stops early when it encounters the
first reference. The problem is that it's coded to stop when it sees
a reference to the corrupt block. That's wrong. It should really
stop when it sees the reference to that block that triggered the
"unrecoverable" error. In other words, when it hits that exact
metadata block and its offset. This patch scraps the old system of
looking for the corrupt block in favor of looking for the corrupt
reference, including metadata block and offset within that block.
Signed-off-by: Bob Peterson <rpeterso(a)redhat.com>
This is a RHEL7 port of this upstream patch:
https://git.fedorahosted.org/cgit/gfs2-utils.git/commit/?id=6b40deabbbbd59a…
rhbz#1348703
---
gfs2/fsck/fsck.h | 6 ++++
gfs2/fsck/metawalk.c | 77 +++++++++++++++++++++++++++++++++++++-------------
2 files changed, 63 insertions(+), 20 deletions(-)
diff --git a/gfs2/fsck/fsck.h b/gfs2/fsck/fsck.h
index 73cff4c..8af4eb4 100644
--- a/gfs2/fsck/fsck.h
+++ b/gfs2/fsck/fsck.h
@@ -106,6 +106,12 @@ enum rgindex_trust_level { /* how far can we trust our RG index? */
must have been converted from gfs2_convert. */
};
+struct error_block {
+ uint64_t metablk; /* metadata block where error was found */
+ int metaoff; /* offset in that metadata block where error found */
+ uint64_t errblk; /* error block */
+};
+
extern struct gfs2_inode *fsck_load_inode(struct gfs2_sbd *sdp, uint64_t block);
extern struct gfs2_inode *fsck_inode_get(struct gfs2_sbd *sdp,
struct rgrp_tree *rgd,
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index c0cc2ab..fecf33e 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -1387,7 +1387,7 @@ error_undo: /* undo what we've done so far for this block */
*/
static int check_data(struct gfs2_inode *ip, struct metawalk_fxns *pass,
struct gfs2_buffer_head *bh, int head_size,
- uint64_t *blks_checked, uint64_t *error_blk)
+ uint64_t *blks_checked, struct error_block *error_blk)
{
int error = 0, rc = 0;
uint64_t block, *ptr;
@@ -1418,21 +1418,36 @@ static int check_data(struct gfs2_inode *ip, struct metawalk_fxns *pass,
log_info("\n");
if (rc < 0) {
/* A fatal error trumps a non-fatal one. */
- if ((*error_blk == 0) || (rc < error)) {
- log_debug(_("Fatal error on block 0x"
- "%llx preempts non-fatal "
- "error on block 0x%llx\n"),
+ if ((error_blk->errblk == 0) ||
+ (rc < error)) {
+ log_debug(_("Fatal error on metadata "
+ "block 0x%llx, offset "
+ "0x%x, referencing block "
+ "0x%llx preempts non-fatal"
+ " error on block 0x%llx\n"),
+ (unsigned long long)metablock,
+ (int)(ptr - ptr_start),
(unsigned long long)block,
- (unsigned long long)*error_blk);
- *error_blk = block;
+ (unsigned long long)error_blk->errblk);
+ error_blk->metablk = metablock;
+ error_blk->metaoff = ptr - ptr_start;
+ error_blk->errblk = block;
}
log_info(_("Unrecoverable "));
} else { /* nonfatal error */
- if ((*error_blk) == 0)
- *error_blk = block;
+ if (error_blk->errblk == 0) {
+ error_blk->metablk = metablock;
+ error_blk->metaoff = ptr - ptr_start;
+ error_blk->errblk = block;
+ }
}
- log_info(_("data block error %d on block %llu "
- "(0x%llx).\n"), rc,
+ log_info(_("data block error %d on metadata block "
+ "%lld (0x%llx), offset %d (0x%x), "
+ "referencing data block %lld (0x%llx).\n"),
+ rc, (unsigned long long)metablock,
+ (unsigned long long)metablock,
+ (int)(ptr - ptr_start),
+ (int)(ptr - ptr_start),
(unsigned long long)block,
(unsigned long long)block);
error = rc;
@@ -1445,8 +1460,9 @@ static int check_data(struct gfs2_inode *ip, struct metawalk_fxns *pass,
}
static int undo_check_data(struct gfs2_inode *ip, struct metawalk_fxns *pass,
+ uint64_t metablock,
uint64_t *ptr_start, char *ptr_end,
- uint64_t error_blk, int error)
+ struct error_block *error_blk, int error)
{
int rc = 0;
uint64_t block, *ptr;
@@ -1460,19 +1476,27 @@ static int undo_check_data(struct gfs2_inode *ip, struct metawalk_fxns *pass,
if (skip_this_pass || fsck_abort)
return 1;
block = be64_to_cpu(*ptr);
- if (block == error_blk) {
+ if (metablock == error_blk->metablk &&
+ (ptr - ptr_start == error_blk->metaoff) &&
+ block == error_blk->errblk) {
if (error < 0) { /* A fatal error that stopped it? */
log_debug(_("Stopping the undo process: "
"fatal error block 0x%llx was "
- "found.\n"),
- (unsigned long long)error_blk);
+ "found at metadata block 0x%llx,"
+ "offset 0x%x.\n"),
+ (unsigned long long)error_blk->errblk,
+ (unsigned long long)error_blk->metablk,
+ error_blk->metaoff);
return 1;
}
found_error_blk = 1;
log_debug(_("The non-fatal error block 0x%llx was "
- "found, but undo processing will continue "
+ "found at metadata block 0x%llx, offset "
+ "0x%d, but undo processing will continue "
"until the end of this metadata block.\n"),
- (unsigned long long)error_blk);
+ (unsigned long long)error_blk->errblk,
+ (unsigned long long)error_blk->metablk,
+ error_blk->metaoff);
}
rc = pass->undo_check_data(ip, block, pass->private);
if (rc < 0)
@@ -1514,7 +1538,7 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass)
uint64_t blks_checked = 0;
int error, rc;
int metadata_clean = 0;
- uint64_t error_blk = 0;
+ struct error_block error_blk = {0, 0, 0};
int hit_error_blk = 0;
if (!height && !is_dir(&ip->i_di, ip->i_sbd->gfs1))
@@ -1577,10 +1601,15 @@ undo_metalist:
if (!error)
goto out;
log_err( _("Error: inode %llu (0x%llx) had unrecoverable errors at "
+ "metadata block %lld (0x%llx), offset %d (0x%x), block "
"%lld (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)error_blk, (unsigned long long)error_blk);
+ (unsigned long long)error_blk.metablk,
+ (unsigned long long)error_blk.metablk,
+ error_blk.metaoff, error_blk.metaoff,
+ (unsigned long long)error_blk.errblk,
+ (unsigned long long)error_blk.errblk);
if (!query( _("Remove the invalid inode? (y/n) "))) {
free_metalist(ip, &metalist[0]);
log_err(_("Invalid inode not deleted.\n"));
@@ -1606,12 +1635,20 @@ undo_metalist:
head_size = hdr_size(bh, height);
if (head_size) {
rc = undo_check_data(ip, pass,
+ bh->b_blocknr,
(uint64_t *)
(bh->b_data + head_size),
(bh->b_data + ip->i_sbd->bsize),
- error_blk, error);
+ &error_blk,
+ error);
if (rc > 0) {
hit_error_blk = 1;
+ log_err("Reached the error "
+ "block undoing work "
+ "for inode %lld "
+ "(0x%llx).\n",
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr);
rc = 0;
}
}