On 03/13/2017 07:14 AM, Filipe Manana wrote:
> On Sat, Mar 11, 2017 at 11:02 PM, Goldwyn Rodrigues <rgold...@suse.de> wrote:
>> From: Goldwyn Rodrigues <rgold...@suse.com>
>>
>> We are facing the same problem with EDQUOT which was experienced with
>> ENOSPC. Not sure if we require a full ticketing system such as ENOSPC, but
>> here is a fix. Let me know if it is too big a hammer.
>>
>> Quotas are reserved during the start of an operation, incrementing
>> qg->reserved. However, it is written to disk in a commit_transaction
>> which could take as long as commit_interval. In the meantime there
>> could be deletions which are not accounted for because deletions are
>> accounted for only while committed (free_refroot). So, when we get
>> a EDQUOT flush the data to disk and try again.
> 
> So this doesn't explain why the problem happens, taking into account
> the reproducer below.
> You mention that deletions are only accounted at transaction commit
> time, but the reproducer does not do any deletions.

Yes it does, after Cleanup. It is a loop. I suppose you got confused by
the indent.

> So why does the reproducer gets EDQUOT errors? The second sentence
> "However, it is written to disk in a commit_transaction
> which could take as long as commit_interval." also does not explain
> why is that a problem, why it makes the reproducer get EDQUOT errors.
> 
> I would like to see a clear and complete explanation in the changelog.

I suppose this comment is irrelevant now?

> 
>>
>> I combined the conditions of rfer and excl to reduce code lines, though
>> the condition looks uglier.
> 
> This sentence is outdated, it's no longer valid for v2 as it now calls
> qgroup_check_limits().
> 
>>
>> Here is a sample script which shows this issue.
>>
>> DEVICE=/dev/vdb
>> MOUNTPOINT=/mnt
>> TESTVOL=$MOUNTPOINT/tmp
>> QUOTA=5
>> PROG=btrfs
>> DD_BS="4k"
>> DD_COUNT="256"
>> RUN_TIMES=5000
>>
>> mkfs.btrfs -f $DEVICE
>> mount -o commit=240 $DEVICE $MOUNTPOINT
>> $PROG subvolume create $TESTVOL
>> $PROG quota enable $TESTVOL
>> $PROG qgroup limit ${QUOTA}G $TESTVOL
>>
>> typeset -i DD_RUN_GOOD
>> typeset -i QUOTA
>>
>> function _check_cmd() {
>>         if [[ ${?} > 0 ]]; then
>>                 echo -n "$(date) E: Running previous command"
>>                 echo ${*}
>>                 echo "Without sync"
>>                 $PROG qgroup show -pcreFf ${TESTVOL}
>>                 echo "With sync"
>>                 $PROG qgroup show -pcreFf --sync ${TESTVOL}
>>                 exit 1
>>         fi
>> }
>>
>> while true; do
>> DD_RUN_GOOD=$RUN_TIMES
>>
>> while (( ${DD_RUN_GOOD} != 0 )); do
>>         dd if=/dev/zero of=${TESTVOL}/quotatest${DD_RUN_GOOD} bs=${DD_BS} 
>> count=${DD_COUNT}
>>         _check_cmd "dd if=/dev/zero of=${TESTVOL}/quotatest${DD_RUN_GOOD} 
>> bs=${DD_BS} count=${DD_COUNT}"
>>         DD_RUN_GOOD=(${DD_RUN_GOOD}-1)
>> done
>>
>> $PROG qgroup show -pcref $TESTVOL
>> echo "----------- Cleanup ---------- "
>> rm $TESTVOL/quotatest*

Here is the deletion.

>>
>> done

And the infinite loop ending.

> 
> Please write a test case for fstests.

You mean xfstests. will do.

> 
>>
>> Changes since v1:
>>  - Changed start_delalloc_roots() to start_delalloc_inode() to target
>>    the root in question only to reduce the amount of flush to be done.
>>  - Added wait_ordered_extents().
> 
> Listing what changed between versions is not meant to appear in the
> changelog. This should go after the --- below. You should also prefix
> the patch subject with "btrfs:" (or "btrfs-progs:"). See the examples
> from others or the wiki for intsructions
> (https://btrfs.wiki.kernel.org/index.php/Writing_patch_for_btrfs#Updating_patches).
> 

Ok, understood. Thanks.

> thanks
> 
>>
>> Signed-off-by: Goldwyn Rodrigues <rgold...@suse.com>
>> Reviewed-by: Qu Wenruo <quwen...@cn.fujitsu.com>
>> ---
>>  fs/btrfs/qgroup.c | 15 +++++++++++++++
>>  1 file changed, 15 insertions(+)
>>
>> diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
>> index a5da750..6215264 100644
>> --- a/fs/btrfs/qgroup.c
>> +++ b/fs/btrfs/qgroup.c
>> @@ -2367,6 +2367,7 @@ static int qgroup_reserve(struct btrfs_root *root, u64 
>> num_bytes, bool enforce)
>>         struct btrfs_fs_info *fs_info = root->fs_info;
>>         u64 ref_root = root->root_key.objectid;
>>         int ret = 0;
>> +       int retried = 0;
>>         struct ulist_node *unode;
>>         struct ulist_iterator uiter;
>>
>> @@ -2376,6 +2377,7 @@ static int qgroup_reserve(struct btrfs_root *root, u64 
>> num_bytes, bool enforce)
>>         if (num_bytes == 0)
>>                 return 0;
>>
>> +retry:
>>         spin_lock(&fs_info->qgroup_lock);
>>         quota_root = fs_info->quota_root;
>>         if (!quota_root)
>> @@ -2402,6 +2404,19 @@ static int qgroup_reserve(struct btrfs_root *root, 
>> u64 num_bytes, bool enforce)
>>                 qg = unode_aux_to_qgroup(unode);
>>
>>                 if (enforce && !qgroup_check_limits(qg, num_bytes)) {
>> +                       if (!retried && qg->reserved > 0) {
>> +                               struct btrfs_trans_handle *trans;
>> +                               spin_unlock(&fs_info->qgroup_lock);
>> +                               btrfs_start_delalloc_inodes(root, 0);
>> +                               btrfs_wait_ordered_extents(root, -1, 0,
>> +                                               (u64)-1);
>> +                               trans = btrfs_join_transaction(root);
>> +                               if (IS_ERR(trans))
>> +                                       return PTR_ERR(trans);
>> +                               btrfs_commit_transaction(trans);
>> +                               retried++;
>> +                               goto retry;
>> +                       }
>>                         ret = -EDQUOT;
>>                         goto out;
>>                 }
>> --
>> 2.10.2
>>

-- 
Goldwyn
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to