Skip to content

Commit e562a8b

Browse files
adam900710kdave
authored andcommitted
btrfs: introduce BTRFS_QGROUP_RUNTIME_FLAG_CANCEL_RESCAN
Introduce a new runtime flag, BTRFS_QGROUP_RUNTIME_FLAG_CANCEL_RESCAN, which will inform qgroup rescan to cancel its work asynchronously. This is to address the window when an operation makes qgroup numbers inconsistent (like qgroup inheriting) while a qgroup rescan is running. In that case, qgroup inconsistent flag will be cleared when qgroup rescan finishes. But we changed the ownership of some extents, which means the rescan is already meaningless, and the qgroup inconsistent flag should not be cleared. With the new flag, each time we set INCONSISTENT flag, we also set this new flag to inform any running qgroup rescan to exit immediately, and leaving the INCONSISTENT flag there. The new runtime flag can only be cleared when a new rescan is started. Signed-off-by: Qu Wenruo <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent e71564c commit e562a8b

File tree

2 files changed

+28
-17
lines changed

2 files changed

+28
-17
lines changed

fs/btrfs/qgroup.c

+26-17
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,12 @@ int btrfs_verify_qgroup_counts(struct btrfs_fs_info *fs_info, u64 qgroupid,
333333
}
334334
#endif
335335

336+
static void qgroup_mark_inconsistent(struct btrfs_fs_info *fs_info)
337+
{
338+
fs_info->qgroup_flags |= (BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT |
339+
BTRFS_QGROUP_RUNTIME_FLAG_CANCEL_RESCAN);
340+
}
341+
336342
/*
337343
* The full config is read in one go, only called from open_ctree()
338344
* It doesn't use any locking, as at this point we're still single-threaded
@@ -401,7 +407,7 @@ int btrfs_read_qgroup_config(struct btrfs_fs_info *fs_info)
401407
}
402408
if (btrfs_qgroup_status_generation(l, ptr) !=
403409
fs_info->generation) {
404-
flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT;
410+
qgroup_mark_inconsistent(fs_info);
405411
btrfs_err(fs_info,
406412
"qgroup generation mismatch, marked as inconsistent");
407413
}
@@ -419,7 +425,7 @@ int btrfs_read_qgroup_config(struct btrfs_fs_info *fs_info)
419425
if ((qgroup && found_key.type == BTRFS_QGROUP_INFO_KEY) ||
420426
(!qgroup && found_key.type == BTRFS_QGROUP_LIMIT_KEY)) {
421427
btrfs_err(fs_info, "inconsistent qgroup config");
422-
flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT;
428+
qgroup_mark_inconsistent(fs_info);
423429
}
424430
if (!qgroup) {
425431
qgroup = add_qgroup_rb(fs_info, found_key.offset);
@@ -1734,7 +1740,7 @@ int btrfs_limit_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid,
17341740

17351741
ret = update_qgroup_limit_item(trans, qgroup);
17361742
if (ret) {
1737-
fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT;
1743+
qgroup_mark_inconsistent(fs_info);
17381744
btrfs_info(fs_info, "unable to update quota limit for %llu",
17391745
qgroupid);
17401746
}
@@ -1810,7 +1816,7 @@ int btrfs_qgroup_trace_extent_post(struct btrfs_trans_handle *trans,
18101816
ret = btrfs_find_all_roots(NULL, trans->fs_info, bytenr, 0, &old_root,
18111817
true);
18121818
if (ret < 0) {
1813-
trans->fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT;
1819+
qgroup_mark_inconsistent(trans->fs_info);
18141820
btrfs_warn(trans->fs_info,
18151821
"error accounting new delayed refs extent (err code: %d), quota inconsistent",
18161822
ret);
@@ -2286,7 +2292,7 @@ static int qgroup_trace_subtree_swap(struct btrfs_trans_handle *trans,
22862292
out:
22872293
btrfs_free_path(dst_path);
22882294
if (ret < 0)
2289-
fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT;
2295+
qgroup_mark_inconsistent(fs_info);
22902296
return ret;
22912297
}
22922298

@@ -2790,12 +2796,10 @@ int btrfs_run_qgroups(struct btrfs_trans_handle *trans)
27902796
spin_unlock(&fs_info->qgroup_lock);
27912797
ret = update_qgroup_info_item(trans, qgroup);
27922798
if (ret)
2793-
fs_info->qgroup_flags |=
2794-
BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT;
2799+
qgroup_mark_inconsistent(fs_info);
27952800
ret = update_qgroup_limit_item(trans, qgroup);
27962801
if (ret)
2797-
fs_info->qgroup_flags |=
2798-
BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT;
2802+
qgroup_mark_inconsistent(fs_info);
27992803
spin_lock(&fs_info->qgroup_lock);
28002804
}
28012805
if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
@@ -2806,7 +2810,7 @@ int btrfs_run_qgroups(struct btrfs_trans_handle *trans)
28062810

28072811
ret = update_qgroup_status_item(trans);
28082812
if (ret)
2809-
fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT;
2813+
qgroup_mark_inconsistent(fs_info);
28102814

28112815
return ret;
28122816
}
@@ -2924,7 +2928,7 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid,
29242928

29252929
ret = update_qgroup_limit_item(trans, dstgroup);
29262930
if (ret) {
2927-
fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT;
2931+
qgroup_mark_inconsistent(fs_info);
29282932
btrfs_info(fs_info,
29292933
"unable to update quota limit for %llu",
29302934
dstgroup->qgroupid);
@@ -3030,7 +3034,7 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid,
30303034
if (!committing)
30313035
mutex_unlock(&fs_info->qgroup_ioctl_lock);
30323036
if (need_rescan)
3033-
fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT;
3037+
qgroup_mark_inconsistent(fs_info);
30343038
return ret;
30353039
}
30363040

@@ -3303,7 +3307,8 @@ static bool rescan_should_stop(struct btrfs_fs_info *fs_info)
33033307
{
33043308
return btrfs_fs_closing(fs_info) ||
33053309
test_bit(BTRFS_FS_STATE_REMOUNTING, &fs_info->fs_state) ||
3306-
!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags);
3310+
!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) ||
3311+
fs_info->qgroup_flags & BTRFS_QGROUP_RUNTIME_FLAG_CANCEL_RESCAN;
33073312
}
33083313

33093314
static void btrfs_qgroup_rescan_worker(struct btrfs_work *work)
@@ -3368,7 +3373,8 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work)
33683373
}
33693374

33703375
mutex_lock(&fs_info->qgroup_rescan_lock);
3371-
if (!stopped)
3376+
if (!stopped ||
3377+
fs_info->qgroup_flags & BTRFS_QGROUP_RUNTIME_FLAG_CANCEL_RESCAN)
33723378
fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_RESCAN;
33733379
if (trans) {
33743380
ret = update_qgroup_status_item(trans);
@@ -3379,6 +3385,7 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work)
33793385
}
33803386
}
33813387
fs_info->qgroup_rescan_running = false;
3388+
fs_info->qgroup_flags &= ~BTRFS_QGROUP_RUNTIME_FLAG_CANCEL_RESCAN;
33823389
complete_all(&fs_info->qgroup_rescan_completion);
33833390
mutex_unlock(&fs_info->qgroup_rescan_lock);
33843391

@@ -3389,6 +3396,8 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work)
33893396

33903397
if (stopped) {
33913398
btrfs_info(fs_info, "qgroup scan paused");
3399+
} else if (fs_info->qgroup_flags & BTRFS_QGROUP_RUNTIME_FLAG_CANCEL_RESCAN) {
3400+
btrfs_info(fs_info, "qgroup scan cancelled");
33923401
} else if (err >= 0) {
33933402
btrfs_info(fs_info, "qgroup scan completed%s",
33943403
err > 0 ? " (inconsistency flag cleared)" : "");
@@ -3451,6 +3460,7 @@ qgroup_rescan_init(struct btrfs_fs_info *fs_info, u64 progress_objectid,
34513460

34523461
memset(&fs_info->qgroup_rescan_progress, 0,
34533462
sizeof(fs_info->qgroup_rescan_progress));
3463+
fs_info->qgroup_flags &= ~BTRFS_QGROUP_RUNTIME_FLAG_CANCEL_RESCAN;
34543464
fs_info->qgroup_rescan_progress.objectid = progress_objectid;
34553465
init_completion(&fs_info->qgroup_rescan_completion);
34563466
mutex_unlock(&fs_info->qgroup_rescan_lock);
@@ -4248,8 +4258,7 @@ int btrfs_qgroup_add_swapped_blocks(struct btrfs_trans_handle *trans,
42484258
spin_unlock(&blocks->lock);
42494259
out:
42504260
if (ret < 0)
4251-
fs_info->qgroup_flags |=
4252-
BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT;
4261+
qgroup_mark_inconsistent(fs_info);
42534262
return ret;
42544263
}
42554264

@@ -4336,7 +4345,7 @@ int btrfs_qgroup_trace_subtree_after_cow(struct btrfs_trans_handle *trans,
43364345
btrfs_err_rl(fs_info,
43374346
"failed to account subtree at bytenr %llu: %d",
43384347
subvol_eb->start, ret);
4339-
fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT;
4348+
qgroup_mark_inconsistent(fs_info);
43404349
}
43414350
return ret;
43424351
}

fs/btrfs/qgroup.h

+2
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@
100100
* subtree rescan for them.
101101
*/
102102

103+
#define BTRFS_QGROUP_RUNTIME_FLAG_CANCEL_RESCAN (1UL << 3)
104+
103105
/*
104106
* Record a dirty extent, and info qgroup to update quota on it
105107
* TODO: Use kmem cache to alloc it.

0 commit comments

Comments
 (0)