Skip to content

Commit 263da81

Browse files
adam900710kdave
authored andcommitted
btrfs: qgroup: allow to unreserve range without releasing other ranges
[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: Josef Bacik <[email protected]> Reviewed-by: Josef Bacik <[email protected]> Signed-off-by: Qu Wenruo <[email protected]> Reviewed-by: David Sterba <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent 48aaeeb commit 263da81

File tree

1 file changed

+77
-15
lines changed

1 file changed

+77
-15
lines changed

fs/btrfs/qgroup.c

Lines changed: 77 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3447,6 +3447,73 @@ btrfs_qgroup_rescan_resume(struct btrfs_fs_info *fs_info)
34473447
}
34483448
}
34493449

3450+
#define rbtree_iterate_from_safe(node, next, start) \
3451+
for (node = start; node && ({ next = rb_next(node); 1;}); node = next)
3452+
3453+
static int qgroup_unreserve_range(struct btrfs_inode *inode,
3454+
struct extent_changeset *reserved, u64 start,
3455+
u64 len)
3456+
{
3457+
struct rb_node *node;
3458+
struct rb_node *next;
3459+
struct ulist_node *entry = NULL;
3460+
int ret = 0;
3461+
3462+
node = reserved->range_changed.root.rb_node;
3463+
while (node) {
3464+
entry = rb_entry(node, struct ulist_node, rb_node);
3465+
if (entry->val < start)
3466+
node = node->rb_right;
3467+
else if (entry)
3468+
node = node->rb_left;
3469+
else
3470+
break;
3471+
}
3472+
3473+
/* Empty changeset */
3474+
if (!entry)
3475+
return 0;
3476+
3477+
if (entry->val > start && rb_prev(&entry->rb_node))
3478+
entry = rb_entry(rb_prev(&entry->rb_node), struct ulist_node,
3479+
rb_node);
3480+
3481+
rbtree_iterate_from_safe(node, next, &entry->rb_node) {
3482+
u64 entry_start;
3483+
u64 entry_end;
3484+
u64 entry_len;
3485+
int clear_ret;
3486+
3487+
entry = rb_entry(node, struct ulist_node, rb_node);
3488+
entry_start = entry->val;
3489+
entry_end = entry->aux;
3490+
entry_len = entry_end - entry_start + 1;
3491+
3492+
if (entry_start >= start + len)
3493+
break;
3494+
if (entry_start + entry_len <= start)
3495+
continue;
3496+
/*
3497+
* Now the entry is in [start, start + len), revert the
3498+
* EXTENT_QGROUP_RESERVED bit.
3499+
*/
3500+
clear_ret = clear_extent_bits(&inode->io_tree, entry_start,
3501+
entry_end, EXTENT_QGROUP_RESERVED);
3502+
if (!ret && clear_ret < 0)
3503+
ret = clear_ret;
3504+
3505+
ulist_del(&reserved->range_changed, entry->val, entry->aux);
3506+
if (likely(reserved->bytes_changed >= entry_len)) {
3507+
reserved->bytes_changed -= entry_len;
3508+
} else {
3509+
WARN_ON(1);
3510+
reserved->bytes_changed = 0;
3511+
}
3512+
}
3513+
3514+
return ret;
3515+
}
3516+
34503517
/*
34513518
* Reserve qgroup space for range [start, start + len).
34523519
*
@@ -3457,18 +3524,14 @@ btrfs_qgroup_rescan_resume(struct btrfs_fs_info *fs_info)
34573524
* Return <0 for error (including -EQUOT)
34583525
*
34593526
* NOTE: this function may sleep for memory allocation.
3460-
* if btrfs_qgroup_reserve_data() is called multiple times with
3461-
* same @reserved, caller must ensure when error happens it's OK
3462-
* to free *ALL* reserved space.
34633527
*/
34643528
int btrfs_qgroup_reserve_data(struct btrfs_inode *inode,
34653529
struct extent_changeset **reserved_ret, u64 start,
34663530
u64 len)
34673531
{
34683532
struct btrfs_root *root = inode->root;
3469-
struct ulist_node *unode;
3470-
struct ulist_iterator uiter;
34713533
struct extent_changeset *reserved;
3534+
bool new_reserved = false;
34723535
u64 orig_reserved;
34733536
u64 to_reserve;
34743537
int ret;
@@ -3481,6 +3544,7 @@ int btrfs_qgroup_reserve_data(struct btrfs_inode *inode,
34813544
if (WARN_ON(!reserved_ret))
34823545
return -EINVAL;
34833546
if (!*reserved_ret) {
3547+
new_reserved = true;
34843548
*reserved_ret = extent_changeset_alloc();
34853549
if (!*reserved_ret)
34863550
return -ENOMEM;
@@ -3496,23 +3560,21 @@ int btrfs_qgroup_reserve_data(struct btrfs_inode *inode,
34963560
trace_btrfs_qgroup_reserve_data(&inode->vfs_inode, start, len,
34973561
to_reserve, QGROUP_RESERVE);
34983562
if (ret < 0)
3499-
goto cleanup;
3563+
goto out;
35003564
ret = qgroup_reserve(root, to_reserve, true, BTRFS_QGROUP_RSV_DATA);
35013565
if (ret < 0)
35023566
goto cleanup;
35033567

35043568
return ret;
35053569

35063570
cleanup:
3507-
/* cleanup *ALL* already reserved ranges */
3508-
ULIST_ITER_INIT(&uiter);
3509-
while ((unode = ulist_next(&reserved->range_changed, &uiter)))
3510-
clear_extent_bit(&inode->io_tree, unode->val,
3511-
unode->aux, EXTENT_QGROUP_RESERVED, 0, 0, NULL);
3512-
/* Also free data bytes of already reserved one */
3513-
btrfs_qgroup_free_refroot(root->fs_info, root->root_key.objectid,
3514-
orig_reserved, BTRFS_QGROUP_RSV_DATA);
3515-
extent_changeset_release(reserved);
3571+
qgroup_unreserve_range(inode, reserved, start, len);
3572+
out:
3573+
if (new_reserved) {
3574+
extent_changeset_release(reserved);
3575+
kfree(reserved);
3576+
*reserved_ret = NULL;
3577+
}
35163578
return ret;
35173579
}
35183580

0 commit comments

Comments
 (0)