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 <wqu@xxxxxxxx>
> ---
> 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);
> }
>
>
Attachment:
signature.asc
Description: OpenPGP digital signature
