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)); + } }
/*
在 2025/11/4 18:44, Zhen Ni 写道:
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.
Explain why backup_super_roots() is called on those situations.
Remember csum/extent trees can only be NULL if corresponding rescue mount options are used, which requires the full fs to be RO (and no log replay is allowed either).
If you hit it in the real world, please give the call trace.
Otherwise give a deeper dig first.
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)); }}/*
linux-stable-mirror@lists.linaro.org