Skip to content

Commit 1c414ff

Browse files
fdmananagregkh
authored andcommitted
btrfs: fix double free of anon_dev after failure to create subvolume
commit 33fab97 upstream. When creating a subvolume, at create_subvol(), we allocate an anonymous device and later call btrfs_get_new_fs_root(), which in turn just calls btrfs_get_root_ref(). There we call btrfs_init_fs_root() which assigns the anonymous device to the root, but if after that call there's an error, when we jump to 'fail' label, we call btrfs_put_root(), which frees the anonymous device and then returns an error that is propagated back to create_subvol(). Than create_subvol() frees the anonymous device again. When this happens, if the anonymous device was not reallocated after the first time it was freed with btrfs_put_root(), we get a kernel message like the following: (...) [13950.282466] BTRFS: error (device dm-0) in create_subvol:663: errno=-5 IO failure [13950.283027] ida_free called for id=65 which is not allocated. [13950.285974] BTRFS info (device dm-0): forced readonly (...) If the anonymous device gets reallocated by another btrfs filesystem or any other kernel subsystem, then bad things can happen. So fix this by setting the root's anonymous device to 0 at btrfs_get_root_ref(), before we call btrfs_put_root(), if an error happened. Fixes: 2dfb1e4 ("btrfs: preallocate anon block device at first phase of snapshot creation") CC: stable@vger.kernel.org # 5.10+ Reviewed-by: Qu Wenruo <wqu@suse.com> Signed-off-by: Filipe Manana <fdmanana@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 005d929 commit 1c414ff

File tree

1 file changed

+8
-0
lines changed

1 file changed

+8
-0
lines changed

fs/btrfs/disk-io.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1603,6 +1603,14 @@ static struct btrfs_root *btrfs_get_root_ref(struct btrfs_fs_info *fs_info,
16031603
}
16041604
return root;
16051605
fail:
1606+
/*
1607+
* If our caller provided us an anonymous device, then it's his
1608+
* responsability to free it in case we fail. So we have to set our
1609+
* root's anon_dev to 0 to avoid a double free, once by btrfs_put_root()
1610+
* and once again by our caller.
1611+
*/
1612+
if (anon_dev)
1613+
root->anon_dev = 0;
16061614
btrfs_put_root(root);
16071615
return ERR_PTR(ret);
16081616
}

0 commit comments

Comments
 (0)