backup_super_roots() unconditionally dereferences extent_root and csum_root pointers obtained from btrfs_extent_root() and btrfs_csum_root() respectively. These functions can return NULL when the corresponding filesystem trees are unavailable due to corruption or other error conditions. This causes a kernel panic.
Add proper NULL checking and skip the backup operations for the unavailable roots.
Fixes: 29cbcf401793 ("btrfs: stop accessing ->extent_root directly") Fixes: f7238e509404 ("btrfs: add support for multiple global roots") Cc: stable@vger.kernel.org Signed-off-by: Zhen Ni zhen.ni@easystack.cn --- fs/btrfs/disk-io.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-)
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 0aa7e5d1b05f..b54c79a1db14 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -1670,18 +1670,22 @@ static void backup_super_roots(struct btrfs_fs_info *info) struct btrfs_root *extent_root = btrfs_extent_root(info, 0); struct btrfs_root *csum_root = btrfs_csum_root(info, 0);
- btrfs_set_backup_extent_root(root_backup, - extent_root->node->start); - btrfs_set_backup_extent_root_gen(root_backup, - btrfs_header_generation(extent_root->node)); - btrfs_set_backup_extent_root_level(root_backup, - btrfs_header_level(extent_root->node)); - - btrfs_set_backup_csum_root(root_backup, csum_root->node->start); - btrfs_set_backup_csum_root_gen(root_backup, - btrfs_header_generation(csum_root->node)); - btrfs_set_backup_csum_root_level(root_backup, - btrfs_header_level(csum_root->node)); + if (unlikely(!extent_root || !csum_root)) { + btrfs_warn(info, "failed to get extent or csum root for backup"); + } else { + btrfs_set_backup_extent_root(root_backup, + extent_root->node->start); + btrfs_set_backup_extent_root_gen(root_backup, + btrfs_header_generation(extent_root->node)); + btrfs_set_backup_extent_root_level(root_backup, + btrfs_header_level(extent_root->node)); + + btrfs_set_backup_csum_root(root_backup, csum_root->node->start); + btrfs_set_backup_csum_root_gen(root_backup, + btrfs_header_generation(csum_root->node)); + btrfs_set_backup_csum_root_level(root_backup, + btrfs_header_level(csum_root->node)); + } }
/*