Whamcloud - gitweb
e2fsck: track errors/badness found for each inode
authorAndreas Dilger <andreas.dilger@intel.com>
Fri, 13 Apr 2012 07:13:58 +0000 (01:13 -0600)
committerAndreas Dilger <adilger@whamcloud.com>
Thu, 15 Dec 2022 18:49:58 +0000 (11:49 -0700)
commite9b0ac5eb8f255383e825b16e17fcb9be1401505
tree223d065174543b634dfadb3eef60c29087833e39
parenta18d3cc765aceccc719089d80977969b91ec172d
e2fsck: track errors/badness found for each inode

The present e2fsck code checks the inode, per field basis.  It
doesn't take into consideration to total sanity of the inode.
This may cause e2fsck turning a garbage inode into an apparently
sane inode ("It is a vessel of fertilizer, and none may abide
its strength").

Add heuristics into fix_problem() so that e2fsck tracks the degree
of badness of an inode, without needing to be added in many places
in code and explicitly set. An icount is used to keep track the
badness of every inode.  Take advantage of pctx->ino almost always
pointing at the bad inode and increment badness when fix_problem()
is called on an inode.  This also handles future problem addition.

That leaves only a handful of places in the code that need special
handling to either set a higher badness (e.g. inode blocks that are
directly referencing filesystem metadata or have wildly incorrect
timestamps), or should not contribute to inode badness at all.

Badness above a certain threshold value results in clearing the
inode.  The default badness threshold value is 12, it can be tuned
for e2fsck using "-E inode_badness_threshold=<value>" if needed.

When multiply-claimed blocks are found, this is often caused by a
corrupted inode or indirect block that causes a bad inode to overlap
with many good inodes.  This problem is made worse when running
on a large filesystem (16TB or more) because random 32-bit numbers
in the inode->i_blocks[] array are always "valid" block numbers
(with smaller filesystems the random block numbers would be detected
as an error).  Garbage triple/double/indirect blocks will also point
to random "valid" blocks that will themselves contain random 32-bit
block numbers and multiply duplicate blocks count exponentially.

Rather than clone all of those blocks, or possibly deleting/zeroing
all such inodes (as done with "-E shared=delete") it would be better
to find the "bad" inode(s) causing the most problems, and clear only
those inodes, rather than clearing all of inodes with shared blocks.
However, care should be taken to avoid spuriously clearing inodes
that only share blocks with a small number of peers, as it is
difficult to know for sure in this case which inode is the bad one.

An added difficulty in implementing this is that the full list of
inodes sharing a given block is only available in pass1d, at which
point it is already starting to clone the shared blocks.  Some checks
could be done in pass1b, by penalizing inodes wiht the most shared
*blocks*, but it is better to count the shared *inodes*.

If a bad inode is found in pass1b it can be cleared before adding it
to the shared cluster/inode dictionaries.  Otherwise, if found in
pass1d the code to remove inodes/cluster dict_delete_free() code is
non-functional.  For now, restart e2fsck pass1 if very bad inodes
are found.  This will not affect already-processed inodes, and should
reduce the number of duplicate blocks significantly.

Add a new f_ibadness_dup test case for a many-conflicting inode.
Update f_ind_inode_collision, which is a many-blocks conflicting
case that is much better handled by this new mechanism.

Signed-off-by: Girish Shilamkar <girish@clusterfs.com>
Change-Id: I9f5f48d979afebb9c953d9fb2777ebf570f30c15
Signed-off-by: Andreas Dilger <adilger@whamcloud.com>
33 files changed:
e2fsck/e2fsck.8.in
e2fsck/e2fsck.c
e2fsck/e2fsck.h
e2fsck/pass1.c
e2fsck/pass1b.c
e2fsck/pass2.c
e2fsck/pass3.c
e2fsck/problem.c
e2fsck/problem.h
e2fsck/super.c
e2fsck/unix.c
lib/ext2fs/ext2fs.h
lib/ext2fs/icount.c
tests/f_ibadness/expect.1 [new file with mode: 0644]
tests/f_ibadness/expect.2 [new file with mode: 0644]
tests/f_ibadness/image.gz [new file with mode: 0644]
tests/f_ibadness/name [new file with mode: 0644]
tests/f_ibadness/script [new file with mode: 0644]
tests/f_ibadness_bad_extents/expect.1 [new file with mode: 0644]
tests/f_ibadness_bad_extents/expect.2 [new file with mode: 0644]
tests/f_ibadness_bad_extents/image.gz [new file with mode: 0644]
tests/f_ibadness_bad_extents/name [new file with mode: 0644]
tests/f_ibadness_bad_extents/script [new file with mode: 0644]
tests/f_ibadness_dup/expect.1 [new file with mode: 0644]
tests/f_ibadness_dup/expect.2 [new file with mode: 0644]
tests/f_ibadness_dup/name [new file with mode: 0644]
tests/f_ibadness_dup/script [new file with mode: 0644]
tests/f_ind_inode_collision/expect.1
tests/f_ind_inode_collision/expect.2
tests/f_messy_inode/expect.1
tests/f_messy_inode/expect.2
tests/f_messy_inode/script [new file with mode: 0644]
tests/filter.sed