aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKirk McKusick <mckusick@FreeBSD.org>2021-03-25 00:23:33 +0000
committerKirk McKusick <mckusick@FreeBSD.org>2021-03-25 00:24:41 +0000
commit7848b25edd2a513f115de6d91f0a5a8d8fa1aa58 (patch)
tree8990534ce81e1793fb7f9b74605dae0331ae5198
parent66f138563becf12d5c21924f816d2a45c3a1ed7a (diff)
downloadsrc-7848b25edd2a513f115de6d91f0a5a8d8fa1aa58.tar.gz
src-7848b25edd2a513f115de6d91f0a5a8d8fa1aa58.zip
Fix fsck_ffs -R finds unfixed duplicate block errors when rerunning.
This fixes a long-standing but very obscure bug in fsck_ffs when it is run with the -R (rerun after unexpected errors). It only occurs if fsck_ffs finds duplicate blocks and they are all contained in inodes that reside in the first block of inodes (typically among the first 128 inodes). Rather than use the usual ginode() interface to walk through the inodes in pass1, there is a special optimized `getnextinode()' routine for walking through all the inodes. It has its own private buffer for reading the inode blocks. If pass 1 finds duplicate blocks it runs pass 1b to find all the inodes that contain these duplicate blocks. Pass 1b also uses the `getnextinode()' to search for the inodes with duplicate blocks. Pass 1b stops when all the duplicate blocks have been found. If all the duplicate blocks are found in the first block of inodes, then the getnextinode cache holds this block of bad inodes. The subsequent cleanup of the inodes in passes 2-5 is done using ginode() which uses the regular fsck_ffs cache. When fsck_ffs restarts, pass1() calls setinodebuf() to point at the first block of inodes. When it calls getnextinode() to get inode 2, getnextino() sees that its private cache already has the first set of inodes loaded and starts using them. They are of course the trashed inodes left over from the previous run of pass1b(). The fix is to always invalidate the getnextinode cache when calling setinodebuf(). Reported by: Chuck Silvers Tested by: Chuck Silvers MFC after: 3 days Sponsored by: Netflix
-rw-r--r--sbin/fsck_ffs/inode.c3
1 files changed, 3 insertions, 0 deletions
diff --git a/sbin/fsck_ffs/inode.c b/sbin/fsck_ffs/inode.c
index 60019425c825..020a69dd72f8 100644
--- a/sbin/fsck_ffs/inode.c
+++ b/sbin/fsck_ffs/inode.c
@@ -600,6 +600,9 @@ setinodebuf(int cg, ino_t inosused)
nextino = inum;
lastinum = inum;
readcount = 0;
+ /* Flush old contents in case they have been updated */
+ flush(fswritefd, &inobuf);
+ inobuf.b_bno = 0;
if (inobuf.b_un.b_buf == NULL) {
inobufsize = blkroundup(&sblock,
MAX(INOBUFSIZE, sblock.fs_bsize));