Gentle ping? It would be pretty nice to make it into the next merge windows (v5.1). Thanks, Qu On 2019/1/25 上午7:55, Qu Wenruo wrote: > [BUG] > Btrfs qgroup will still hit EDQUOT under the following case: > > #!/bin/bash > > 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 a514d63882c3 ("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 > --- > fs/btrfs/qgroup.c | 29 ++++++++++++++++------------- > 1 file changed, 16 insertions(+), 13 deletions(-) > > diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c > index 4e473a998219..f0b7425bf289 100644 > --- a/fs/btrfs/qgroup.c > +++ b/fs/btrfs/qgroup.c > @@ -2843,15 +2843,15 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid, > * Two limits to commit transaction in advance. > * > * For RATIO, it will be 1/RATIO of the remaining limit > - * (excluding data and prealloc meta) as threshold. > + * as threshold. > * For SIZE, it will be in byte unit as threshold. > */ > -#define QGROUP_PERTRANS_RATIO 32 > -#define QGROUP_PERTRANS_SIZE SZ_32M > +#define QGROUP_FREE_RATIO 32 > +#define QGROUP_FREE_SIZE SZ_32M > static bool qgroup_check_limits(struct btrfs_fs_info *fs_info, > const struct btrfs_qgroup *qg, u64 num_bytes) > { > - u64 limit; > + u64 free; > u64 threshold; > > if ((qg->lim_flags & BTRFS_QGROUP_LIMIT_MAX_RFER) && > @@ -2870,20 +2870,23 @@ static bool qgroup_check_limits(struct btrfs_fs_info *fs_info, > */ > if ((qg->lim_flags & (BTRFS_QGROUP_LIMIT_MAX_RFER | > BTRFS_QGROUP_LIMIT_MAX_EXCL))) { > - if (qg->lim_flags & BTRFS_QGROUP_LIMIT_MAX_EXCL) > - limit = qg->max_excl; > - else > - limit = qg->max_rfer; > - threshold = (limit - qg->rsv.values[BTRFS_QGROUP_RSV_DATA] - > - qg->rsv.values[BTRFS_QGROUP_RSV_META_PREALLOC]) / > - QGROUP_PERTRANS_RATIO; > - threshold = min_t(u64, threshold, QGROUP_PERTRANS_SIZE); > + if (qg->lim_flags & BTRFS_QGROUP_LIMIT_MAX_EXCL) { > + free = (qg->max_excl - qgroup_rsv_total(qg) - > + qg->excl); > + threshold = min_t(u64, qg->max_excl / QGROUP_FREE_RATIO, > + QGROUP_FREE_SIZE); > + } else { > + free = (qg->max_rfer - qgroup_rsv_total(qg) - > + qg->rfer); > + threshold = min_t(u64, qg->max_rfer / QGROUP_FREE_RATIO, > + QGROUP_FREE_SIZE); > + } > > /* > * Use transaction_kthread to commit transaction, so we no > * longer need to bother nested transaction nor lock context. > */ > - if (qg->rsv.values[BTRFS_QGROUP_RSV_META_PERTRANS] > threshold) > + if (free < threshold) > btrfs_commit_transaction_locksafe(fs_info); > } > >