Skip to content

Commit a514d63

Browse files
adam900710kdave
authored andcommitted
btrfs: qgroup: Commit transaction in advance to reduce early EDQUOT
Unlike previous method that tries to commit transaction inside qgroup_reserve(), this time we will try to commit transaction using fs_info->transaction_kthread to avoid nested transaction and no need to worry about locking context. Since it's an asynchronous function call and we won't wait for transaction commit, unlike previous method, we must call it before we hit the qgroup limit. So this patch will use the ratio and size of qgroup meta_pertrans reservation as indicator to check if we should trigger a transaction commit. (meta_prealloc won't be cleaned in transaction committ, it's useless anyway) Signed-off-by: Qu Wenruo <wqu@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
1 parent 5d41be6 commit a514d63

File tree

5 files changed

+63
-2
lines changed

5 files changed

+63
-2
lines changed

fs/btrfs/ctree.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -714,6 +714,12 @@ struct btrfs_delayed_root;
714714
*/
715715
#define BTRFS_FS_EXCL_OP 16
716716

717+
/*
718+
* To info transaction_kthread we need an immediate commit so it doesn't
719+
* need to wait for commit_interval
720+
*/
721+
#define BTRFS_FS_NEED_ASYNC_COMMIT 17
722+
717723
struct btrfs_fs_info {
718724
u8 fsid[BTRFS_FSID_SIZE];
719725
u8 chunk_tree_uuid[BTRFS_UUID_SIZE];

fs/btrfs/disk-io.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1824,6 +1824,7 @@ static int transaction_kthread(void *arg)
18241824

18251825
now = get_seconds();
18261826
if (cur->state < TRANS_STATE_BLOCKED &&
1827+
!test_bit(BTRFS_FS_NEED_ASYNC_COMMIT, &fs_info->flags) &&
18271828
(now < cur->start_time ||
18281829
now - cur->start_time < fs_info->commit_interval)) {
18291830
spin_unlock(&fs_info->trans_lock);

fs/btrfs/qgroup.c

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <linux/slab.h>
1212
#include <linux/workqueue.h>
1313
#include <linux/btrfs.h>
14+
#include <linux/sizes.h>
1415

1516
#include "ctree.h"
1617
#include "transaction.h"
@@ -2375,8 +2376,21 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans,
23752376
return ret;
23762377
}
23772378

2378-
static bool qgroup_check_limits(const struct btrfs_qgroup *qg, u64 num_bytes)
2379+
/*
2380+
* Two limits to commit transaction in advance.
2381+
*
2382+
* For RATIO, it will be 1/RATIO of the remaining limit
2383+
* (excluding data and prealloc meta) as threshold.
2384+
* For SIZE, it will be in byte unit as threshold.
2385+
*/
2386+
#define QGROUP_PERTRANS_RATIO 32
2387+
#define QGROUP_PERTRANS_SIZE SZ_32M
2388+
static bool qgroup_check_limits(struct btrfs_fs_info *fs_info,
2389+
const struct btrfs_qgroup *qg, u64 num_bytes)
23792390
{
2391+
u64 limit;
2392+
u64 threshold;
2393+
23802394
if ((qg->lim_flags & BTRFS_QGROUP_LIMIT_MAX_RFER) &&
23812395
qgroup_rsv_total(qg) + (s64)qg->rfer + num_bytes > qg->max_rfer)
23822396
return false;
@@ -2385,6 +2399,31 @@ static bool qgroup_check_limits(const struct btrfs_qgroup *qg, u64 num_bytes)
23852399
qgroup_rsv_total(qg) + (s64)qg->excl + num_bytes > qg->max_excl)
23862400
return false;
23872401

2402+
/*
2403+
* Even if we passed the check, it's better to check if reservation
2404+
* for meta_pertrans is pushing us near limit.
2405+
* If there is too much pertrans reservation or it's near the limit,
2406+
* let's try commit transaction to free some, using transaction_kthread
2407+
*/
2408+
if ((qg->lim_flags & (BTRFS_QGROUP_LIMIT_MAX_RFER |
2409+
BTRFS_QGROUP_LIMIT_MAX_EXCL))) {
2410+
if (qg->lim_flags & BTRFS_QGROUP_LIMIT_MAX_EXCL)
2411+
limit = qg->max_excl;
2412+
else
2413+
limit = qg->max_rfer;
2414+
threshold = (limit - qg->rsv.values[BTRFS_QGROUP_RSV_DATA] -
2415+
qg->rsv.values[BTRFS_QGROUP_RSV_META_PREALLOC]) /
2416+
QGROUP_PERTRANS_RATIO;
2417+
threshold = min_t(u64, threshold, QGROUP_PERTRANS_SIZE);
2418+
2419+
/*
2420+
* Use transaction_kthread to commit transaction, so we no
2421+
* longer need to bother nested transaction nor lock context.
2422+
*/
2423+
if (qg->rsv.values[BTRFS_QGROUP_RSV_META_PERTRANS] > threshold)
2424+
btrfs_commit_transaction_locksafe(fs_info);
2425+
}
2426+
23882427
return true;
23892428
}
23902429

@@ -2434,7 +2473,7 @@ static int qgroup_reserve(struct btrfs_root *root, u64 num_bytes, bool enforce,
24342473

24352474
qg = unode_aux_to_qgroup(unode);
24362475

2437-
if (enforce && !qgroup_check_limits(qg, num_bytes)) {
2476+
if (enforce && !qgroup_check_limits(fs_info, qg, num_bytes)) {
24382477
ret = -EDQUOT;
24392478
goto out;
24402479
}

fs/btrfs/transaction.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2267,6 +2267,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
22672267
*/
22682268
cur_trans->state = TRANS_STATE_COMPLETED;
22692269
wake_up(&cur_trans->commit_wait);
2270+
clear_bit(BTRFS_FS_NEED_ASYNC_COMMIT, &fs_info->flags);
22702271

22712272
spin_lock(&fs_info->trans_lock);
22722273
list_del_init(&cur_trans->list);

fs/btrfs/transaction.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,20 @@ int btrfs_clean_one_deleted_snapshot(struct btrfs_root *root);
199199
int btrfs_commit_transaction(struct btrfs_trans_handle *trans);
200200
int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans,
201201
int wait_for_unblock);
202+
203+
/*
204+
* Try to commit transaction asynchronously, so this is safe to call
205+
* even holding a spinlock.
206+
*
207+
* It's done by informing transaction_kthread to commit transaction without
208+
* waiting for commit interval.
209+
*/
210+
static inline void btrfs_commit_transaction_locksafe(
211+
struct btrfs_fs_info *fs_info)
212+
{
213+
set_bit(BTRFS_FS_NEED_ASYNC_COMMIT, &fs_info->flags);
214+
wake_up_process(fs_info->transaction_kthread);
215+
}
202216
int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans);
203217
int btrfs_should_end_transaction(struct btrfs_trans_handle *trans);
204218
void btrfs_throttle(struct btrfs_fs_info *fs_info);

0 commit comments

Comments
 (0)