aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/disk-io.c
diff options
context:
space:
mode:
authorDavid Sterba <dsterba@suse.cz>2014-09-30 13:16:47 -0400
committerChris Mason <clm@fb.com>2014-10-03 19:14:59 -0400
commitc926093ec516f5d316ecdf8c1be11f577ac71b85 (patch)
tree80cea5b9e2d7264940ae53a5ab2808a34dc107f9 /fs/btrfs/disk-io.c
parent42383020beb1cfb05f5d330cc311931bc4917a97 (diff)
btrfs: add more superblock checks
Populate btrfs_check_super_valid() with checks that try to verify consistency of superblock by additional conditions that may arise from corrupted devices or bitflips. Some of tests are only hints and issue warnings instead of failing the mount, basically when the checks are derived from the data found in the superblock. Tested on a broken image provided by Qu. Reported-by: Qu Wenruo <quwenruo@cn.fujitsu.com> Signed-off-by: David Sterba <dsterba@suse.cz> Signed-off-by: Chris Mason <clm@fb.com>
Diffstat (limited to 'fs/btrfs/disk-io.c')
-rw-r--r--fs/btrfs/disk-io.c67
1 files changed, 65 insertions, 2 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 09b3c8a0c790..fc8dfaa27967 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -3817,10 +3817,73 @@ int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid)
3817static int btrfs_check_super_valid(struct btrfs_fs_info *fs_info, 3817static int btrfs_check_super_valid(struct btrfs_fs_info *fs_info,
3818 int read_only) 3818 int read_only)
3819{ 3819{
3820 struct btrfs_super_block *sb = fs_info->super_copy;
3821 int ret = 0;
3822
3823 if (sb->root_level > BTRFS_MAX_LEVEL) {
3824 printk(KERN_ERR "BTRFS: tree_root level too big: %d > %d\n",
3825 sb->root_level, BTRFS_MAX_LEVEL);
3826 ret = -EINVAL;
3827 }
3828 if (sb->chunk_root_level > BTRFS_MAX_LEVEL) {
3829 printk(KERN_ERR "BTRFS: chunk_root level too big: %d > %d\n",
3830 sb->chunk_root_level, BTRFS_MAX_LEVEL);
3831 ret = -EINVAL;
3832 }
3833 if (sb->log_root_level > BTRFS_MAX_LEVEL) {
3834 printk(KERN_ERR "BTRFS: log_root level too big: %d > %d\n",
3835 sb->log_root_level, BTRFS_MAX_LEVEL);
3836 ret = -EINVAL;
3837 }
3838
3820 /* 3839 /*
3821 * Placeholder for checks 3840 * The common minimum, we don't know if we can trust the nodesize/sectorsize
3841 * items yet, they'll be verified later. Issue just a warning.
3822 */ 3842 */
3823 return 0; 3843 if (!IS_ALIGNED(sb->root, 4096))
3844 printk(KERN_WARNING "BTRFS: tree_root block unaligned: %llu\n",
3845 sb->root);
3846 if (!IS_ALIGNED(sb->chunk_root, 4096))
3847 printk(KERN_WARNING "BTRFS: tree_root block unaligned: %llu\n",
3848 sb->chunk_root);
3849 if (!IS_ALIGNED(sb->log_root, 4096))
3850 printk(KERN_WARNING "BTRFS: tree_root block unaligned: %llu\n",
3851 sb->log_root);
3852
3853 if (memcmp(fs_info->fsid, sb->dev_item.fsid, BTRFS_UUID_SIZE) != 0) {
3854 printk(KERN_ERR "BTRFS: dev_item UUID does not match fsid: %pU != %pU\n",
3855 fs_info->fsid, sb->dev_item.fsid);
3856 ret = -EINVAL;
3857 }
3858
3859 /*
3860 * Hint to catch really bogus numbers, bitflips or so, more exact checks are
3861 * done later
3862 */
3863 if (sb->num_devices > (1UL << 31))
3864 printk(KERN_WARNING "BTRFS: suspicious number of devices: %llu\n",
3865 sb->num_devices);
3866
3867 if (sb->bytenr != BTRFS_SUPER_INFO_OFFSET) {
3868 printk(KERN_ERR "BTRFS: super offset mismatch %llu != %u\n",
3869 sb->bytenr, BTRFS_SUPER_INFO_OFFSET);
3870 ret = -EINVAL;
3871 }
3872
3873 /*
3874 * The generation is a global counter, we'll trust it more than the others
3875 * but it's still possible that it's the one that's wrong.
3876 */
3877 if (sb->generation < sb->chunk_root_generation)
3878 printk(KERN_WARNING
3879 "BTRFS: suspicious: generation < chunk_root_generation: %llu < %llu\n",
3880 sb->generation, sb->chunk_root_generation);
3881 if (sb->generation < sb->cache_generation && sb->cache_generation != (u64)-1)
3882 printk(KERN_WARNING
3883 "BTRFS: suspicious: generation < cache_generation: %llu < %llu\n",
3884 sb->generation, sb->cache_generation);
3885
3886 return ret;
3824} 3887}
3825 3888
3826static void btrfs_error_commit_super(struct btrfs_root *root) 3889static void btrfs_error_commit_super(struct btrfs_root *root)