Skip to content

Commit 182940f

Browse files
boryaskdave
authored andcommitted
btrfs: qgroup: add new quota mode for simple quotas
Add a new quota mode called "simple quotas". It can be enabled by the existing quota enable ioctl via a new command, and sets an incompat bit, as the implementation of simple quotas will make backwards incompatible changes to the disk format of the extent tree. Signed-off-by: Boris Burkov <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent 6b0cd63 commit 182940f

File tree

9 files changed

+115
-45
lines changed

9 files changed

+115
-45
lines changed

fs/btrfs/delayed-ref.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -959,8 +959,7 @@ int btrfs_add_delayed_tree_ref(struct btrfs_trans_handle *trans,
959959
return -ENOMEM;
960960
}
961961

962-
if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) &&
963-
!generic_ref->skip_qgroup) {
962+
if (btrfs_qgroup_enabled(fs_info) && !generic_ref->skip_qgroup) {
964963
record = kzalloc(sizeof(*record), GFP_NOFS);
965964
if (!record) {
966965
kmem_cache_free(btrfs_delayed_tree_ref_cachep, ref);
@@ -1063,8 +1062,7 @@ int btrfs_add_delayed_data_ref(struct btrfs_trans_handle *trans,
10631062
return -ENOMEM;
10641063
}
10651064

1066-
if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) &&
1067-
!generic_ref->skip_qgroup) {
1065+
if (btrfs_qgroup_enabled(fs_info) && !generic_ref->skip_qgroup) {
10681066
record = kzalloc(sizeof(*record), GFP_NOFS);
10691067
if (!record) {
10701068
kmem_cache_free(btrfs_delayed_data_ref_cachep, ref);

fs/btrfs/fs.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,8 @@ enum {
220220
BTRFS_FEATURE_INCOMPAT_NO_HOLES | \
221221
BTRFS_FEATURE_INCOMPAT_METADATA_UUID | \
222222
BTRFS_FEATURE_INCOMPAT_RAID1C34 | \
223-
BTRFS_FEATURE_INCOMPAT_ZONED)
223+
BTRFS_FEATURE_INCOMPAT_ZONED | \
224+
BTRFS_FEATURE_INCOMPAT_SIMPLE_QUOTA)
224225

225226
#ifdef CONFIG_BTRFS_DEBUG
226227
/*

fs/btrfs/ioctl.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3697,7 +3697,8 @@ static long btrfs_ioctl_quota_ctl(struct file *file, void __user *arg)
36973697

36983698
switch (sa->cmd) {
36993699
case BTRFS_QUOTA_CTL_ENABLE:
3700-
ret = btrfs_quota_enable(fs_info);
3700+
case BTRFS_QUOTA_CTL_ENABLE_SIMPLE_QUOTA:
3701+
ret = btrfs_quota_enable(fs_info, sa);
37013702
break;
37023703
case BTRFS_QUOTA_CTL_DISABLE:
37033704
ret = btrfs_quota_disable(fs_info);

fs/btrfs/qgroup.c

Lines changed: 80 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,21 @@ enum btrfs_qgroup_mode btrfs_qgroup_mode(struct btrfs_fs_info *fs_info)
3434
{
3535
if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
3636
return BTRFS_QGROUP_MODE_DISABLED;
37+
if (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_SIMPLE_MODE)
38+
return BTRFS_QGROUP_MODE_SIMPLE;
3739
return BTRFS_QGROUP_MODE_FULL;
3840
}
3941

42+
bool btrfs_qgroup_enabled(struct btrfs_fs_info *fs_info)
43+
{
44+
return btrfs_qgroup_mode(fs_info) != BTRFS_QGROUP_MODE_DISABLED;
45+
}
46+
47+
bool btrfs_qgroup_full_accounting(struct btrfs_fs_info *fs_info)
48+
{
49+
return btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_FULL;
50+
}
51+
4052
/*
4153
* Helpers to access qgroup reservation
4254
*
@@ -350,6 +362,8 @@ int btrfs_verify_qgroup_counts(struct btrfs_fs_info *fs_info, u64 qgroupid,
350362

351363
static void qgroup_mark_inconsistent(struct btrfs_fs_info *fs_info)
352364
{
365+
if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_SIMPLE)
366+
return;
353367
fs_info->qgroup_flags |= (BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT |
354368
BTRFS_QGROUP_RUNTIME_FLAG_CANCEL_RESCAN |
355369
BTRFS_QGROUP_RUNTIME_FLAG_NO_ACCOUNTING);
@@ -370,8 +384,9 @@ int btrfs_read_qgroup_config(struct btrfs_fs_info *fs_info)
370384
int ret = 0;
371385
u64 flags = 0;
372386
u64 rescan_progress = 0;
387+
bool simple;
373388

374-
if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
389+
if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_DISABLED)
375390
return 0;
376391

377392
fs_info->qgroup_ulist = ulist_alloc(GFP_KERNEL);
@@ -421,14 +436,14 @@ int btrfs_read_qgroup_config(struct btrfs_fs_info *fs_info)
421436
"old qgroup version, quota disabled");
422437
goto out;
423438
}
439+
fs_info->qgroup_flags = btrfs_qgroup_status_flags(l, ptr);
440+
simple = (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_SIMPLE_MODE);
424441
if (btrfs_qgroup_status_generation(l, ptr) !=
425-
fs_info->generation) {
442+
fs_info->generation && !simple) {
426443
qgroup_mark_inconsistent(fs_info);
427444
btrfs_err(fs_info,
428445
"qgroup generation mismatch, marked as inconsistent");
429446
}
430-
fs_info->qgroup_flags = btrfs_qgroup_status_flags(l,
431-
ptr);
432447
rescan_progress = btrfs_qgroup_status_rescan(l, ptr);
433448
goto next1;
434449
}
@@ -571,7 +586,7 @@ bool btrfs_check_quota_leak(struct btrfs_fs_info *fs_info)
571586
struct rb_node *node;
572587
bool ret = false;
573588

574-
if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
589+
if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_DISABLED)
575590
return ret;
576591
/*
577592
* Since we're unmounting, there is no race and no need to grab qgroup
@@ -970,7 +985,8 @@ static int btrfs_clean_quota_tree(struct btrfs_trans_handle *trans,
970985
return ret;
971986
}
972987

973-
int btrfs_quota_enable(struct btrfs_fs_info *fs_info)
988+
int btrfs_quota_enable(struct btrfs_fs_info *fs_info,
989+
struct btrfs_ioctl_quota_ctl_args *quota_ctl_args)
974990
{
975991
struct btrfs_root *quota_root;
976992
struct btrfs_root *tree_root = fs_info->tree_root;
@@ -983,6 +999,7 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info)
983999
struct btrfs_qgroup *prealloc = NULL;
9841000
struct btrfs_trans_handle *trans = NULL;
9851001
struct ulist *ulist = NULL;
1002+
const bool simple = (quota_ctl_args->cmd == BTRFS_QUOTA_CTL_ENABLE_SIMPLE_QUOTA);
9861003
int ret = 0;
9871004
int slot;
9881005

@@ -1085,8 +1102,11 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info)
10851102
struct btrfs_qgroup_status_item);
10861103
btrfs_set_qgroup_status_generation(leaf, ptr, trans->transid);
10871104
btrfs_set_qgroup_status_version(leaf, ptr, BTRFS_QGROUP_STATUS_VERSION);
1088-
fs_info->qgroup_flags = BTRFS_QGROUP_STATUS_FLAG_ON |
1089-
BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT;
1105+
fs_info->qgroup_flags = BTRFS_QGROUP_STATUS_FLAG_ON;
1106+
if (simple)
1107+
fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_SIMPLE_MODE;
1108+
else
1109+
fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT;
10901110
btrfs_set_qgroup_status_flags(leaf, ptr, fs_info->qgroup_flags &
10911111
BTRFS_QGROUP_STATUS_FLAGS_MASK);
10921112
btrfs_set_qgroup_status_rescan(leaf, ptr, 0);
@@ -1214,8 +1234,14 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info)
12141234
spin_lock(&fs_info->qgroup_lock);
12151235
fs_info->quota_root = quota_root;
12161236
set_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags);
1237+
if (simple)
1238+
btrfs_set_fs_incompat(fs_info, SIMPLE_QUOTA);
12171239
spin_unlock(&fs_info->qgroup_lock);
12181240

1241+
/* Skip rescan for simple qgroups. */
1242+
if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_SIMPLE)
1243+
goto out_free_path;
1244+
12191245
ret = qgroup_rescan_init(fs_info, 0, 1);
12201246
if (!ret) {
12211247
qgroup_rescan_zero_tracking(fs_info);
@@ -1330,6 +1356,7 @@ int btrfs_quota_disable(struct btrfs_fs_info *fs_info)
13301356
quota_root = fs_info->quota_root;
13311357
fs_info->quota_root = NULL;
13321358
fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_ON;
1359+
fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_SIMPLE_MODE;
13331360
fs_info->qgroup_drop_subtree_thres = BTRFS_MAX_LEVEL;
13341361
spin_unlock(&fs_info->qgroup_lock);
13351362

@@ -1810,6 +1837,9 @@ int btrfs_qgroup_trace_extent_nolock(struct btrfs_fs_info *fs_info,
18101837
struct btrfs_qgroup_extent_record *entry;
18111838
u64 bytenr = record->bytenr;
18121839

1840+
if (!btrfs_qgroup_full_accounting(fs_info))
1841+
return 0;
1842+
18131843
lockdep_assert_held(&delayed_refs->lock);
18141844
trace_btrfs_qgroup_trace_extent(fs_info, record);
18151845

@@ -1863,6 +1893,8 @@ int btrfs_qgroup_trace_extent_post(struct btrfs_trans_handle *trans,
18631893
struct btrfs_backref_walk_ctx ctx = { 0 };
18641894
int ret;
18651895

1896+
if (!btrfs_qgroup_full_accounting(trans->fs_info))
1897+
return 0;
18661898
/*
18671899
* We are always called in a context where we are already holding a
18681900
* transaction handle. Often we are called when adding a data delayed
@@ -1931,8 +1963,7 @@ int btrfs_qgroup_trace_extent(struct btrfs_trans_handle *trans, u64 bytenr,
19311963
struct btrfs_delayed_ref_root *delayed_refs;
19321964
int ret;
19331965

1934-
if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)
1935-
|| bytenr == 0 || num_bytes == 0)
1966+
if (!btrfs_qgroup_full_accounting(fs_info) || bytenr == 0 || num_bytes == 0)
19361967
return 0;
19371968
record = kzalloc(sizeof(*record), GFP_NOFS);
19381969
if (!record)
@@ -1970,7 +2001,7 @@ int btrfs_qgroup_trace_leaf_items(struct btrfs_trans_handle *trans,
19702001
u64 bytenr, num_bytes;
19712002

19722003
/* We can be called directly from walk_up_proc() */
1973-
if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
2004+
if (!btrfs_qgroup_full_accounting(fs_info))
19742005
return 0;
19752006

19762007
for (i = 0; i < nr; i++) {
@@ -2346,7 +2377,7 @@ static int qgroup_trace_subtree_swap(struct btrfs_trans_handle *trans,
23462377
int level;
23472378
int ret;
23482379

2349-
if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
2380+
if (!btrfs_qgroup_full_accounting(fs_info))
23502381
return 0;
23512382

23522383
/* Wrong parameter order */
@@ -2413,7 +2444,7 @@ int btrfs_qgroup_trace_subtree(struct btrfs_trans_handle *trans,
24132444
BUG_ON(root_level < 0 || root_level >= BTRFS_MAX_LEVEL);
24142445
BUG_ON(root_eb == NULL);
24152446

2416-
if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
2447+
if (!btrfs_qgroup_full_accounting(fs_info))
24172448
return 0;
24182449

24192450
spin_lock(&fs_info->qgroup_lock);
@@ -2747,7 +2778,7 @@ int btrfs_qgroup_account_extent(struct btrfs_trans_handle *trans, u64 bytenr,
27472778
* If quotas get disabled meanwhile, the resources need to be freed and
27482779
* we can't just exit here.
27492780
*/
2750-
if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) ||
2781+
if (!btrfs_qgroup_full_accounting(fs_info) ||
27512782
fs_info->qgroup_flags & BTRFS_QGROUP_RUNTIME_FLAG_NO_ACCOUNTING)
27522783
goto out_free;
27532784

@@ -2816,6 +2847,9 @@ int btrfs_qgroup_account_extents(struct btrfs_trans_handle *trans)
28162847
u64 qgroup_to_skip;
28172848
int ret = 0;
28182849

2850+
if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_SIMPLE)
2851+
return 0;
2852+
28192853
delayed_refs = &trans->transaction->delayed_refs;
28202854
qgroup_to_skip = delayed_refs->qgroup_to_skip;
28212855
while ((node = rb_first(&delayed_refs->dirty_extent_root))) {
@@ -2931,7 +2965,7 @@ int btrfs_run_qgroups(struct btrfs_trans_handle *trans)
29312965
qgroup_mark_inconsistent(fs_info);
29322966
spin_lock(&fs_info->qgroup_lock);
29332967
}
2934-
if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
2968+
if (btrfs_qgroup_enabled(fs_info))
29352969
fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_ON;
29362970
else
29372971
fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_ON;
@@ -2990,7 +3024,7 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid,
29903024

29913025
if (!committing)
29923026
mutex_lock(&fs_info->qgroup_ioctl_lock);
2993-
if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
3027+
if (!btrfs_qgroup_enabled(fs_info))
29943028
goto out;
29953029

29963030
quota_root = fs_info->quota_root;
@@ -3076,7 +3110,7 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid,
30763110
qgroup_dirty(fs_info, dstgroup);
30773111
}
30783112

3079-
if (srcid) {
3113+
if (srcid && btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_FULL) {
30803114
srcgroup = find_qgroup_rb(fs_info, srcid);
30813115
if (!srcgroup)
30823116
goto unlock;
@@ -3339,6 +3373,9 @@ static int qgroup_rescan_leaf(struct btrfs_trans_handle *trans,
33393373
int slot;
33403374
int ret;
33413375

3376+
if (!btrfs_qgroup_full_accounting(fs_info))
3377+
return 1;
3378+
33423379
mutex_lock(&fs_info->qgroup_rescan_lock);
33433380
extent_root = btrfs_extent_root(fs_info,
33443381
fs_info->qgroup_rescan_progress.objectid);
@@ -3419,10 +3456,15 @@ static int qgroup_rescan_leaf(struct btrfs_trans_handle *trans,
34193456

34203457
static bool rescan_should_stop(struct btrfs_fs_info *fs_info)
34213458
{
3422-
return btrfs_fs_closing(fs_info) ||
3423-
test_bit(BTRFS_FS_STATE_REMOUNTING, &fs_info->fs_state) ||
3424-
!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) ||
3425-
fs_info->qgroup_flags & BTRFS_QGROUP_RUNTIME_FLAG_CANCEL_RESCAN;
3459+
if (btrfs_fs_closing(fs_info))
3460+
return true;
3461+
if (test_bit(BTRFS_FS_STATE_REMOUNTING, &fs_info->fs_state))
3462+
return true;
3463+
if (!btrfs_qgroup_enabled(fs_info))
3464+
return true;
3465+
if (fs_info->qgroup_flags & BTRFS_QGROUP_RUNTIME_FLAG_CANCEL_RESCAN)
3466+
return true;
3467+
return false;
34263468
}
34273469

34283470
static void btrfs_qgroup_rescan_worker(struct btrfs_work *work)
@@ -3436,6 +3478,9 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work)
34363478
bool stopped = false;
34373479
bool did_leaf_rescans = false;
34383480

3481+
if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_SIMPLE)
3482+
return;
3483+
34393484
path = btrfs_alloc_path();
34403485
if (!path)
34413486
goto out;
@@ -3539,6 +3584,11 @@ qgroup_rescan_init(struct btrfs_fs_info *fs_info, u64 progress_objectid,
35393584
{
35403585
int ret = 0;
35413586

3587+
if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_SIMPLE) {
3588+
btrfs_warn(fs_info, "qgroup rescan init failed, running in simple mode");
3589+
return -EINVAL;
3590+
}
3591+
35423592
if (!init_flags) {
35433593
/* we're resuming qgroup rescan at mount time */
35443594
if (!(fs_info->qgroup_flags &
@@ -3569,7 +3619,7 @@ qgroup_rescan_init(struct btrfs_fs_info *fs_info, u64 progress_objectid,
35693619
btrfs_warn(fs_info,
35703620
"qgroup rescan init failed, qgroup is not enabled");
35713621
ret = -EINVAL;
3572-
} else if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) {
3622+
} else if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_DISABLED) {
35733623
/* Quota disable is in progress */
35743624
ret = -EBUSY;
35753625
}
@@ -3828,7 +3878,7 @@ static int qgroup_reserve_data(struct btrfs_inode *inode,
38283878
u64 to_reserve;
38293879
int ret;
38303880

3831-
if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &root->fs_info->flags) ||
3881+
if (btrfs_qgroup_mode(root->fs_info) == BTRFS_QGROUP_MODE_DISABLED ||
38323882
!is_fstree(root->root_key.objectid) || len == 0)
38333883
return 0;
38343884

@@ -3960,7 +4010,7 @@ static int __btrfs_qgroup_release_data(struct btrfs_inode *inode,
39604010
int trace_op = QGROUP_RELEASE;
39614011
int ret;
39624012

3963-
if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &inode->root->fs_info->flags))
4013+
if (btrfs_qgroup_mode(inode->root->fs_info) == BTRFS_QGROUP_MODE_DISABLED)
39644014
return 0;
39654015

39664016
/* In release case, we shouldn't have @reserved */
@@ -4071,7 +4121,7 @@ int btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes,
40714121
struct btrfs_fs_info *fs_info = root->fs_info;
40724122
int ret;
40734123

4074-
if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) ||
4124+
if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_DISABLED ||
40754125
!is_fstree(root->root_key.objectid) || num_bytes == 0)
40764126
return 0;
40774127

@@ -4116,7 +4166,7 @@ void btrfs_qgroup_free_meta_all_pertrans(struct btrfs_root *root)
41164166
{
41174167
struct btrfs_fs_info *fs_info = root->fs_info;
41184168

4119-
if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) ||
4169+
if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_DISABLED ||
41204170
!is_fstree(root->root_key.objectid))
41214171
return;
41224172

@@ -4132,7 +4182,7 @@ void __btrfs_qgroup_free_meta(struct btrfs_root *root, int num_bytes,
41324182
{
41334183
struct btrfs_fs_info *fs_info = root->fs_info;
41344184

4135-
if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) ||
4185+
if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_DISABLED ||
41364186
!is_fstree(root->root_key.objectid))
41374187
return;
41384188

@@ -4191,7 +4241,7 @@ void btrfs_qgroup_convert_reserved_meta(struct btrfs_root *root, int num_bytes)
41914241
{
41924242
struct btrfs_fs_info *fs_info = root->fs_info;
41934243

4194-
if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) ||
4244+
if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_DISABLED ||
41954245
!is_fstree(root->root_key.objectid))
41964246
return;
41974247
/* Same as btrfs_qgroup_free_meta_prealloc() */
@@ -4299,7 +4349,7 @@ int btrfs_qgroup_add_swapped_blocks(struct btrfs_trans_handle *trans,
42994349
int level = btrfs_header_level(subvol_parent) - 1;
43004350
int ret = 0;
43014351

4302-
if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
4352+
if (!btrfs_qgroup_full_accounting(fs_info))
43034353
return 0;
43044354

43054355
if (btrfs_node_ptr_generation(subvol_parent, subvol_slot) >
@@ -4409,7 +4459,7 @@ int btrfs_qgroup_trace_subtree_after_cow(struct btrfs_trans_handle *trans,
44094459
int ret = 0;
44104460
int i;
44114461

4412-
if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
4462+
if (!btrfs_qgroup_full_accounting(fs_info))
44134463
return 0;
44144464
if (!is_fstree(root->root_key.objectid) || !root->reloc_root)
44154465
return 0;

0 commit comments

Comments
 (0)