• Qu Wenruo's avatar
    btrfs: qgroup: Fix the wrong target io_tree when freeing reserved data space · bab32fc0
    Qu Wenruo authored
    [BUG]
    Under the following case with qgroup enabled, if some error happened
    after we have reserved delalloc space, then in error handling path, we
    could cause qgroup data space leakage:
    
    From btrfs_truncate_block() in inode.c:
    
    	ret = btrfs_delalloc_reserve_space(inode, &data_reserved,
    					   block_start, blocksize);
    	if (ret)
    		goto out;
    
     again:
    	page = find_or_create_page(mapping, index, mask);
    	if (!page) {
    		btrfs_delalloc_release_space(inode, data_reserved,
    					     block_start, blocksize, true);
    		btrfs_delalloc_release_extents(BTRFS_I(inode), blocksize, true);
    		ret = -ENOMEM;
    		goto out;
    	}
    
    [CAUSE]
    In the above case, btrfs_delalloc_reserve_space() will call
    btrfs_qgroup_reserve_data() and mark the io_tree range with
    EXTENT_QGROUP_RESERVED flag.
    
    In the error handling path, we have the following call stack:
    btrfs_delalloc_release_space()
    |- btrfs_free_reserved_data_space()
       |- btrsf_qgroup_free_data()
          |- __btrfs_qgroup_release_data(reserved=@reserved, free=1)
             |- qgroup_free_reserved_data(reserved=@reserved)
                |- clear_record_extent_bits();
                |- freed += changeset.bytes_changed;
    
    However due to a completion bug, qgroup_free_reserved_data() will clear
    EXTENT_QGROUP_RESERVED flag in BTRFS_I(inode)->io_failure_tree, other
    than the correct BTRFS_I(inode)->io_tree.
    Since io_failure_tree is never marked with that flag,
    btrfs_qgroup_free_data() will not free any data reserved space at all,
    causing a leakage.
    
    This type of error handling can only be triggered by errors outside of
    qgroup code. So EDQUOT error from qgroup can't trigger it.
    
    [FIX]
    Fix the wrong target io_tree.
    Reported-by: default avatarJosef Bacik <josef@toxicpanda.com>
    Fixes: bc42bda2 ("btrfs: qgroup: Fix qgroup reserved space underflow by only freeing reserved ranges")
    CC: stable@vger.kernel.org # 4.14+
    Reviewed-by: default avatarNikolay Borisov <nborisov@suse.com>
    Signed-off-by: default avatarQu Wenruo <wqu@suse.com>
    Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
    bab32fc0
qgroup.c 103 KB