Skip to content

Commit f5fef45

Browse files
adam900710kdave
authored andcommitted
btrfs: qgroup: Make qgroup async transaction commit more aggressive
[BUG] Btrfs qgroup will still hit EDQUOT under the following case: $ dev=/dev/test/test $ mnt=/mnt/btrfs $ umount $mnt &> /dev/null $ umount $dev &> /dev/null $ mkfs.btrfs -f $dev $ mount $dev $mnt -o nospace_cache $ btrfs subv create $mnt/subv $ btrfs quota enable $mnt $ btrfs quota rescan -w $mnt $ btrfs qgroup limit -e 1G $mnt/subv $ fallocate -l 900M $mnt/subv/padding $ sync $ rm $mnt/subv/padding # Hit EDQUOT $ xfs_io -f -c "pwrite 0 512M" $mnt/subv/real_file [CAUSE] Since commit a514d63 ("btrfs: qgroup: Commit transaction in advance to reduce early EDQUOT"), btrfs is not forced to commit transaction to reclaim more quota space. Instead, we just check pertrans metadata reservation against some threshold and try to do asynchronously transaction commit. However in above case, the pertrans metadata reservation is pretty small thus it will never trigger asynchronous transaction commit. [FIX] Instead of only accounting pertrans metadata reservation, we calculate how much free space we have, and if there isn't much free space left, commit transaction asynchronously to try to free some space. This may slow down the fs when we have less than 32M free qgroup space, but should reduce a lot of false EDQUOT, so the cost should be acceptable. Signed-off-by: Qu Wenruo <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent 1418bae commit f5fef45

File tree

1 file changed

+14
-14
lines changed

1 file changed

+14
-14
lines changed

fs/btrfs/qgroup.c

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2794,16 +2794,15 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid,
27942794
/*
27952795
* Two limits to commit transaction in advance.
27962796
*
2797-
* For RATIO, it will be 1/RATIO of the remaining limit
2798-
* (excluding data and prealloc meta) as threshold.
2797+
* For RATIO, it will be 1/RATIO of the remaining limit as threshold.
27992798
* For SIZE, it will be in byte unit as threshold.
28002799
*/
2801-
#define QGROUP_PERTRANS_RATIO 32
2802-
#define QGROUP_PERTRANS_SIZE SZ_32M
2800+
#define QGROUP_FREE_RATIO 32
2801+
#define QGROUP_FREE_SIZE SZ_32M
28032802
static bool qgroup_check_limits(struct btrfs_fs_info *fs_info,
28042803
const struct btrfs_qgroup *qg, u64 num_bytes)
28052804
{
2806-
u64 limit;
2805+
u64 free;
28072806
u64 threshold;
28082807

28092808
if ((qg->lim_flags & BTRFS_QGROUP_LIMIT_MAX_RFER) &&
@@ -2822,20 +2821,21 @@ static bool qgroup_check_limits(struct btrfs_fs_info *fs_info,
28222821
*/
28232822
if ((qg->lim_flags & (BTRFS_QGROUP_LIMIT_MAX_RFER |
28242823
BTRFS_QGROUP_LIMIT_MAX_EXCL))) {
2825-
if (qg->lim_flags & BTRFS_QGROUP_LIMIT_MAX_EXCL)
2826-
limit = qg->max_excl;
2827-
else
2828-
limit = qg->max_rfer;
2829-
threshold = (limit - qg->rsv.values[BTRFS_QGROUP_RSV_DATA] -
2830-
qg->rsv.values[BTRFS_QGROUP_RSV_META_PREALLOC]) /
2831-
QGROUP_PERTRANS_RATIO;
2832-
threshold = min_t(u64, threshold, QGROUP_PERTRANS_SIZE);
2824+
if (qg->lim_flags & BTRFS_QGROUP_LIMIT_MAX_EXCL) {
2825+
free = qg->max_excl - qgroup_rsv_total(qg) - qg->excl;
2826+
threshold = min_t(u64, qg->max_excl / QGROUP_FREE_RATIO,
2827+
QGROUP_FREE_SIZE);
2828+
} else {
2829+
free = qg->max_rfer - qgroup_rsv_total(qg) - qg->rfer;
2830+
threshold = min_t(u64, qg->max_rfer / QGROUP_FREE_RATIO,
2831+
QGROUP_FREE_SIZE);
2832+
}
28332833

28342834
/*
28352835
* Use transaction_kthread to commit transaction, so we no
28362836
* longer need to bother nested transaction nor lock context.
28372837
*/
2838-
if (qg->rsv.values[BTRFS_QGROUP_RSV_META_PERTRANS] > threshold)
2838+
if (free < threshold)
28392839
btrfs_commit_transaction_locksafe(fs_info);
28402840
}
28412841

0 commit comments

Comments
 (0)