So we can detect log root related problem early and report the error more meaningfully other than hitting it log root read time.
Signed-off-by: Qu Wenruo <w...@suse.com> --- fs/btrfs/disk-io.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 5124c15705ce..34c68401c6bc 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -2408,6 +2408,7 @@ static int validate_super(struct btrfs_fs_info *fs_info, { u64 nodesize = btrfs_super_nodesize(sb); u64 sectorsize = btrfs_super_sectorsize(sb); + u64 generation; int ret = 0; if (btrfs_super_magic(sb) != BTRFS_MAGIC) { @@ -2534,21 +2535,36 @@ static int validate_super(struct btrfs_fs_info *fs_info, ret = -EINVAL; } + generation = btrfs_super_generation(sb); /* * The generation is a global counter, we'll trust it more than the others * but it's still possible that it's the one that's wrong. */ - if (btrfs_super_generation(sb) < btrfs_super_chunk_root_generation(sb)) + if (generation < btrfs_super_chunk_root_generation(sb)) btrfs_warn(fs_info, "suspicious: generation < chunk_root_generation: %llu < %llu", - btrfs_super_generation(sb), - btrfs_super_chunk_root_generation(sb)); - if (btrfs_super_generation(sb) < btrfs_super_cache_generation(sb) + generation, btrfs_super_chunk_root_generation(sb)); + if (generation < btrfs_super_cache_generation(sb) && btrfs_super_cache_generation(sb) != (u64)-1) btrfs_warn(fs_info, "suspicious: generation < cache_generation: %llu < %llu", - btrfs_super_generation(sb), - btrfs_super_cache_generation(sb)); + generation, btrfs_super_cache_generation(sb)); + + /* + * Check log root transid against super block generation. + * + * Older kernel doesn't populate log_root_transid, only need to check + * it when it's not zero. + * Since replaying suspicious log tree can cause serious problem, refuse + * to mount if it doesn't match. + */ + if (btrfs_super_log_root_transid(sb) && + btrfs_super_log_root_transid(sb) != generation + 1) { + btrfs_err(fs_info, + "bad log tree, log_root_transid != generation + 1: %llu != %llu + 1", + btrfs_super_log_root_transid(sb), generation); + ret = -EINVAL; + } return ret; } -- 2.19.0