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 <wqu@xxxxxxxx>
---
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