e2fsck: handle an already recovered journal with a non-zero s_error field

If a file system was remounted read-only after a file system
corruption is detected, and then that file system is mounted and
unmounted by the kernel, the journal would have been recovered, but
the kernel currently leaves the s_errno field still set.  This is
arguably a bug, since it has already propgated the non-zero s_errno
field to the file system superblock, where it will be retained until
e2fsck has been run.

However, e2fsck should handle this case for existing kernel by
checking the journal superblock's s_errno field even if journal
recovery is not required.

Without this commit, e2fsck would not notice anything wrong with the
file system, but a subsequent mount of the file system by the kernel
would mark the file system's superblock as needing checking (since the
journal's s_errno field would still be set), resulting an full e2fsck
run at the next reboot, which would find nothing wrong --- and then
when the file system was mounted, the whole cycle would repeat again.

I had seen reports of this in the past, but it wasn't until recently
that I realized exactly how this had come about, since normally e2fsck
would be run automatically before the file system is mounted again,
thus avoiding this problem.  However, a user using a rescue CD who
didn't run e2fsck before mounting the a file system in this condition
could trigger this situation, and unfortunately, with previous
versions of e2fsprogs and the kernel, there would be no way out no
matter what the user tried to do.

Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
This commit is contained in:
Theodore Ts'o 2012-05-31 19:19:02 -04:00
parent 9906409e13
commit 6d75685e2b

View File

@ -803,6 +803,19 @@ no_has_journal:
*/ */
} }
/*
* If we don't need to do replay the journal, check to see if
* the journal's errno is set; if so, we need to mark the file
* system as being corrupt and clear the journal's s_errno.
*/
if (!(sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) &&
journal->j_superblock->s_errno) {
ctx->fs->super->s_state |= EXT2_ERROR_FS;
ext2fs_mark_super_dirty(ctx->fs);
journal->j_superblock->s_errno = 0;
mark_buffer_dirty(journal->j_sb_buffer);
}
e2fsck_journal_release(ctx, journal, reset, 0); e2fsck_journal_release(ctx, journal, reset, 0);
return retval; return retval;
} }