Skip to content

Commit e85fde5

Browse files
adam900710kdave
authored andcommitted
btrfs: qgroup: fix qgroup meta rsv leak for subvolume operations
[BUG] When quota is enabled for TEST_DEV, generic/013 sometimes fails like this: generic/013 14s ... _check_dmesg: something found in dmesg (see xfstests-dev/results//generic/013.dmesg) And with the following metadata leak: BTRFS warning (device dm-3): qgroup 0/1370 has unreleased space, type 2 rsv 49152 ------------[ cut here ]------------ WARNING: CPU: 2 PID: 47912 at fs/btrfs/disk-io.c:4078 close_ctree+0x1dc/0x323 [btrfs] Call Trace: btrfs_put_super+0x15/0x17 [btrfs] generic_shutdown_super+0x72/0x110 kill_anon_super+0x18/0x30 btrfs_kill_super+0x17/0x30 [btrfs] deactivate_locked_super+0x3b/0xa0 deactivate_super+0x40/0x50 cleanup_mnt+0x135/0x190 __cleanup_mnt+0x12/0x20 task_work_run+0x64/0xb0 __prepare_exit_to_usermode+0x1bc/0x1c0 __syscall_return_slowpath+0x47/0x230 do_syscall_64+0x64/0xb0 entry_SYSCALL_64_after_hwframe+0x44/0xa9 ---[ end trace a6cfd45ba80e4e06 ]--- BTRFS error (device dm-3): qgroup reserved space leaked BTRFS info (device dm-3): disk space caching is enabled BTRFS info (device dm-3): has skinny extents [CAUSE] The qgroup preallocated meta rsv operations of that offending root are: btrfs_delayed_inode_reserve_metadata: rsv_meta_prealloc root=1370 num_bytes=131072 btrfs_delayed_inode_reserve_metadata: rsv_meta_prealloc root=1370 num_bytes=131072 btrfs_subvolume_reserve_metadata: rsv_meta_prealloc root=1370 num_bytes=49152 btrfs_delayed_inode_release_metadata: convert_meta_prealloc root=1370 num_bytes=-131072 btrfs_delayed_inode_release_metadata: convert_meta_prealloc root=1370 num_bytes=-131072 It's pretty obvious that, we reserve qgroup meta rsv in btrfs_subvolume_reserve_metadata(), but doesn't have corresponding release/convert calls in btrfs_subvolume_release_metadata(). This leads to the leakage. [FIX] To fix this bug, we should follow what we're doing in btrfs_delalloc_reserve_metadata(), where we reserve qgroup space, and add it to block_rsv->qgroup_rsv_reserved. And free the qgroup reserved metadata space when releasing the block_rsv. To do this, we need to change the btrfs_subvolume_release_metadata() to accept btrfs_root, and record the qgroup_to_release number, and call btrfs_qgroup_convert_reserved_meta() for it. Fixes: 733e03a ("btrfs: qgroup: Split meta rsv type into meta_prealloc and meta_pertrans") CC: [email protected] # 4.19+ Reviewed-by: Josef Bacik <[email protected]> Signed-off-by: Qu Wenruo <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent b4c5d8f commit e85fde5

File tree

4 files changed

+16
-7
lines changed

4 files changed

+16
-7
lines changed

fs/btrfs/ctree.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2622,7 +2622,7 @@ enum btrfs_flush_state {
26222622
int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
26232623
struct btrfs_block_rsv *rsv,
26242624
int nitems, bool use_global_rsv);
2625-
void btrfs_subvolume_release_metadata(struct btrfs_fs_info *fs_info,
2625+
void btrfs_subvolume_release_metadata(struct btrfs_root *root,
26262626
struct btrfs_block_rsv *rsv);
26272627
void btrfs_delalloc_release_extents(struct btrfs_inode *inode, u64 num_bytes);
26282628

fs/btrfs/inode.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4051,7 +4051,7 @@ int btrfs_delete_subvolume(struct inode *dir, struct dentry *dentry)
40514051
err = ret;
40524052
inode->i_flags |= S_DEAD;
40534053
out_release:
4054-
btrfs_subvolume_release_metadata(fs_info, &block_rsv);
4054+
btrfs_subvolume_release_metadata(root, &block_rsv);
40554055
out_up_write:
40564056
up_write(&fs_info->subvol_sem);
40574057
if (err) {

fs/btrfs/ioctl.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -618,7 +618,7 @@ static noinline int create_subvol(struct inode *dir,
618618
trans = btrfs_start_transaction(root, 0);
619619
if (IS_ERR(trans)) {
620620
ret = PTR_ERR(trans);
621-
btrfs_subvolume_release_metadata(fs_info, &block_rsv);
621+
btrfs_subvolume_release_metadata(root, &block_rsv);
622622
goto fail_free;
623623
}
624624
trans->block_rsv = &block_rsv;
@@ -742,7 +742,7 @@ static noinline int create_subvol(struct inode *dir,
742742
kfree(root_item);
743743
trans->block_rsv = NULL;
744744
trans->bytes_reserved = 0;
745-
btrfs_subvolume_release_metadata(fs_info, &block_rsv);
745+
btrfs_subvolume_release_metadata(root, &block_rsv);
746746

747747
err = btrfs_commit_transaction(trans);
748748
if (err && !ret)
@@ -856,7 +856,7 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
856856
if (ret && pending_snapshot->snap)
857857
pending_snapshot->snap->anon_dev = 0;
858858
btrfs_put_root(pending_snapshot->snap);
859-
btrfs_subvolume_release_metadata(fs_info, &pending_snapshot->block_rsv);
859+
btrfs_subvolume_release_metadata(root, &pending_snapshot->block_rsv);
860860
free_pending:
861861
if (pending_snapshot->anon_dev)
862862
free_anon_bdev(pending_snapshot->anon_dev);

fs/btrfs/root-tree.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -512,11 +512,20 @@ int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
512512
if (ret && qgroup_num_bytes)
513513
btrfs_qgroup_free_meta_prealloc(root, qgroup_num_bytes);
514514

515+
if (!ret) {
516+
spin_lock(&rsv->lock);
517+
rsv->qgroup_rsv_reserved += qgroup_num_bytes;
518+
spin_unlock(&rsv->lock);
519+
}
515520
return ret;
516521
}
517522

518-
void btrfs_subvolume_release_metadata(struct btrfs_fs_info *fs_info,
523+
void btrfs_subvolume_release_metadata(struct btrfs_root *root,
519524
struct btrfs_block_rsv *rsv)
520525
{
521-
btrfs_block_rsv_release(fs_info, rsv, (u64)-1, NULL);
526+
struct btrfs_fs_info *fs_info = root->fs_info;
527+
u64 qgroup_to_release;
528+
529+
btrfs_block_rsv_release(fs_info, rsv, (u64)-1, &qgroup_to_release);
530+
btrfs_qgroup_convert_reserved_meta(root, qgroup_to_release);
522531
}

0 commit comments

Comments
 (0)