Skip to content

Commit 6e9a12a

Browse files
boryasgregkh
authored andcommitted
btrfs: fix squota compressed stats leak
commit de134cb upstream. The following workload on a squota enabled fs: btrfs subvol create mnt/subvol # ensure subvol extents get accounted sync btrfs qgroup create 1/1 mnt btrfs qgroup assign mnt/subvol 1/1 mnt btrfs qgroup delete mnt/subvol # make the cleaner thread run btrfs filesystem sync mnt sleep 1 btrfs filesystem sync mnt btrfs qgroup destroy 1/1 mnt will fail with EBUSY. The reason is that 1/1 does the quick accounting when we assign subvol to it, gaining its exclusive usage as excl and excl_cmpr. But then when we delete subvol, the decrement happens via record_squota_delta() which does not update excl_cmpr, as squotas does not make any distinction between compressed and normal extents. Thus, we increment excl_cmpr but never decrement it, and are unable to delete 1/1. The two possible fixes are to make squota always mirror excl and excl_cmpr or to make the fast accounting separately track the plain and cmpr numbers. The latter felt cleaner to me so that is what I opted for. Fixes: 1e0e9d5 ("btrfs: add helper for recording simple quota deltas") CC: stable@vger.kernel.org # 6.12+ Reviewed-by: Qu Wenruo <wqu@suse.com> Signed-off-by: Boris Burkov <boris@bur.io> Signed-off-by: David Sterba <dsterba@suse.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 1d3c965 commit 6e9a12a

File tree

1 file changed

+4
-2
lines changed

1 file changed

+4
-2
lines changed

fs/btrfs/qgroup.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1501,6 +1501,7 @@ static int __qgroup_excl_accounting(struct btrfs_fs_info *fs_info, u64 ref_root,
15011501
struct btrfs_qgroup *qgroup;
15021502
LIST_HEAD(qgroup_list);
15031503
u64 num_bytes = src->excl;
1504+
u64 num_bytes_cmpr = src->excl_cmpr;
15041505
int ret = 0;
15051506

15061507
qgroup = find_qgroup_rb(fs_info, ref_root);
@@ -1512,11 +1513,12 @@ static int __qgroup_excl_accounting(struct btrfs_fs_info *fs_info, u64 ref_root,
15121513
struct btrfs_qgroup_list *glist;
15131514

15141515
qgroup->rfer += sign * num_bytes;
1515-
qgroup->rfer_cmpr += sign * num_bytes;
1516+
qgroup->rfer_cmpr += sign * num_bytes_cmpr;
15161517

15171518
WARN_ON(sign < 0 && qgroup->excl < num_bytes);
1519+
WARN_ON(sign < 0 && qgroup->excl_cmpr < num_bytes_cmpr);
15181520
qgroup->excl += sign * num_bytes;
1519-
qgroup->excl_cmpr += sign * num_bytes;
1521+
qgroup->excl_cmpr += sign * num_bytes_cmpr;
15201522

15211523
if (sign > 0)
15221524
qgroup_rsv_add_by_qgroup(fs_info, qgroup, src);

0 commit comments

Comments
 (0)