Skip to content

Commit 522fb1a

Browse files
boryasgregkh
authored andcommitted
btrfs: qgroup: fix qgroup id collision across mounts
commit 2b8aa78 upstream. If we delete subvolumes whose ID is the largest in the filesystem, then unmount and mount again, then btrfs_init_root_free_objectid on the tree_root will select a subvolid smaller than that one and thus allow reusing it. If we are also using qgroups (and particularly squotas) it is possible to delete the subvol without deleting the qgroup. In that case, we will be able to create a new subvol whose id already has a level 0 qgroup. This will result in re-using that qgroup which would then lead to incorrect accounting. Fixes: 6ed0564 ("btrfs: create qgroup earlier in snapshot creation") CC: [email protected] # 6.7+ Reviewed-by: Qu Wenruo <[email protected]> Signed-off-by: Boris Burkov <[email protected]> Signed-off-by: David Sterba <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 27d8760 commit 522fb1a

File tree

1 file changed

+20
-0
lines changed

1 file changed

+20
-0
lines changed

fs/btrfs/qgroup.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,13 +468,33 @@ int btrfs_read_qgroup_config(struct btrfs_fs_info *fs_info)
468468
}
469469
if (!qgroup) {
470470
struct btrfs_qgroup *prealloc;
471+
struct btrfs_root *tree_root = fs_info->tree_root;
471472

472473
prealloc = kzalloc(sizeof(*prealloc), GFP_KERNEL);
473474
if (!prealloc) {
474475
ret = -ENOMEM;
475476
goto out;
476477
}
477478
qgroup = add_qgroup_rb(fs_info, prealloc, found_key.offset);
479+
/*
480+
* If a qgroup exists for a subvolume ID, it is possible
481+
* that subvolume has been deleted, in which case
482+
* re-using that ID would lead to incorrect accounting.
483+
*
484+
* Ensure that we skip any such subvol ids.
485+
*
486+
* We don't need to lock because this is only called
487+
* during mount before we start doing things like creating
488+
* subvolumes.
489+
*/
490+
if (is_fstree(qgroup->qgroupid) &&
491+
qgroup->qgroupid > tree_root->free_objectid)
492+
/*
493+
* Don't need to check against BTRFS_LAST_FREE_OBJECTID,
494+
* as it will get checked on the next call to
495+
* btrfs_get_free_objectid.
496+
*/
497+
tree_root->free_objectid = qgroup->qgroupid + 1;
478498
}
479499
ret = btrfs_sysfs_add_one_qgroup(fs_info, qgroup);
480500
if (ret < 0)

0 commit comments

Comments
 (0)