• Qu Wenruo's avatar
    btrfs: qgroup: allow to unreserve range without releasing other ranges · 263da812
    Qu Wenruo authored
    [PROBLEM]
    Before this patch, when btrfs_qgroup_reserve_data() fails, we free all
    reserved space of the changeset.
    
    For example:
    	ret = btrfs_qgroup_reserve_data(inode, changeset, 0, SZ_1M);
    	ret = btrfs_qgroup_reserve_data(inode, changeset, SZ_1M, SZ_1M);
    	ret = btrfs_qgroup_reserve_data(inode, changeset, SZ_2M, SZ_1M);
    
    If the last btrfs_qgroup_reserve_data() failed, it will release the
    entire [0, 3M) range.
    
    This behavior is kind of OK for now, as when we hit -EDQUOT, we normally
    go error handling and need to release all reserved ranges anyway.
    
    But this also means the following call is not possible:
    
    	ret = btrfs_qgroup_reserve_data();
    	if (ret == -EDQUOT) {
    		/* Do something to free some qgroup space */
    		ret = btrfs_qgroup_reserve_data();
    	}
    
    As if the first btrfs_qgroup_reserve_data() fails, it will free all
    reserved qgroup space.
    
    [CAUSE]
    This is because we release all reserved ranges when
    btrfs_qgroup_reserve_data() fails.
    
    [FIX]
    This patch will implement a new function, qgroup_unreserve_range(), to
    iterate through the ulist nodes, to find any nodes in the failure range,
    and remove the EXTENT_QGROUP_RESERVED bits from the io_tree, and
    decrease the extent_changeset::bytes_changed, so that we can revert to
    previous state.
    
    This allows later patches to retry btrfs_qgroup_reserve_data() if EDQUOT
    happens.
    Suggested-by: default avatarJosef Bacik <josef@toxicpanda.com>
    Reviewed-by: default avatarJosef Bacik <josef@toxicpanda.com>
    Signed-off-by: default avatarQu Wenruo <wqu@suse.com>
    Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
    Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
    263da812
qgroup.c 106 KB