Skip to content

Commit d7c6005

Browse files
boryaskdave
authored andcommitted
btrfs: fix squota accounting during enable generation
The first transaction that enables squotas is special and a bit tricky. We have to set BTRFS_FS_QUOTA_ENABLED after the transaction to avoid a deadlock, so any delayed refs that run before we set the bit are not squota accounted. For data this is fine, we don't get an owner_ref, so there is no real harm, it's as if the extent predated squotas. However for metadata, the tree block will have gen == enable_gen so when we free it later, we will decrement the squota accounting, which can result in an underflow. Before it is freed, btrfs check shows errors, as we have mismatched usage between the node generations/owners and the squota values. There are two angles to this fix: 1. For extents that come in delayed_refs that run during the enable_gen transaction, we must actually set enable_gen to the *next* transaction. That is the first transaction that we can really properly account in any way. 2. For extents that come in between the end of our transaction handle and the time we set the BTRFS_FS_QUOTA_ENABLED bit, we need an additional bit, BTRFS_FS_SQUOTA_ENABLING which only affects recording squota deltas, so we do pick up those extents. Otherwise, we would miss them, even for enable_gen + 1. Fixes: bd7c1ea ("btrfs: qgroup: check generation when recording simple quota delta") Reviewed-by: Qu Wenruo <wqu@suse.com> Signed-off-by: Boris Burkov <boris@bur.io> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
1 parent 1e92637 commit d7c6005

2 files changed

Lines changed: 28 additions & 4 deletions

File tree

fs/btrfs/fs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ enum {
155155
BTRFS_FS_LOG_RECOVERING,
156156
BTRFS_FS_OPEN,
157157
BTRFS_FS_QUOTA_ENABLED,
158+
BTRFS_FS_SQUOTA_ENABLING,
158159
BTRFS_FS_UPDATE_UUID_TREE_GEN,
159160
BTRFS_FS_CREATING_FREE_SPACE_TREE,
160161
BTRFS_FS_BTREE_ERR,

fs/btrfs/qgroup.c

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1107,7 +1107,13 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info,
11071107
if (simple) {
11081108
fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_SIMPLE_MODE;
11091109
btrfs_set_fs_incompat(fs_info, SIMPLE_QUOTA);
1110-
btrfs_set_qgroup_status_enable_gen(leaf, ptr, trans->transid);
1110+
/*
1111+
* Set the enable generation to the next transaction, as we cannot
1112+
* ensure that extents written during this transaction will see any
1113+
* state we have set here. So we should treat all extents of the
1114+
* transaction as coming in before squotas was enabled.
1115+
*/
1116+
btrfs_set_qgroup_status_enable_gen(leaf, ptr, trans->transid + 1);
11111117
} else {
11121118
fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT;
11131119
}
@@ -1210,7 +1216,15 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info,
12101216
goto out_free_path;
12111217
}
12121218

1213-
fs_info->qgroup_enable_gen = trans->transid;
1219+
/*
1220+
* Set fs_info->qgroup_enable_gen and BTRFS_FS_SQUOTA_ENABLING
1221+
* under the transaction handle. We want to ensure that all extents in
1222+
* the next transaction definitely see them.
1223+
*/
1224+
if (simple) {
1225+
fs_info->qgroup_enable_gen = trans->transid + 1;
1226+
set_bit(BTRFS_FS_SQUOTA_ENABLING, &fs_info->flags);
1227+
}
12141228

12151229
mutex_unlock(&fs_info->qgroup_ioctl_lock);
12161230
/*
@@ -1224,9 +1238,15 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info,
12241238
*/
12251239
ret = btrfs_commit_transaction(trans);
12261240
trans = NULL;
1241+
12271242
mutex_lock(&fs_info->qgroup_ioctl_lock);
1228-
if (ret)
1243+
if (ret) {
1244+
if (simple) {
1245+
clear_bit(BTRFS_FS_SQUOTA_ENABLING, &fs_info->flags);
1246+
fs_info->qgroup_enable_gen = 0;
1247+
}
12291248
goto out_free_path;
1249+
}
12301250

12311251
/*
12321252
* Set quota enabled flag after committing the transaction, to avoid
@@ -1236,6 +1256,8 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info,
12361256
spin_lock(&fs_info->qgroup_lock);
12371257
fs_info->quota_root = quota_root;
12381258
set_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags);
1259+
if (simple)
1260+
clear_bit(BTRFS_FS_SQUOTA_ENABLING, &fs_info->flags);
12391261
spin_unlock(&fs_info->qgroup_lock);
12401262

12411263
/* Skip rescan for simple qgroups. */
@@ -4922,7 +4944,8 @@ int btrfs_record_squota_delta(struct btrfs_fs_info *fs_info,
49224944
u64 num_bytes = delta->num_bytes;
49234945
const int sign = (delta->is_inc ? 1 : -1);
49244946

4925-
if (btrfs_qgroup_mode(fs_info) != BTRFS_QGROUP_MODE_SIMPLE)
4947+
if (btrfs_qgroup_mode(fs_info) != BTRFS_QGROUP_MODE_SIMPLE &&
4948+
!test_bit(BTRFS_FS_SQUOTA_ENABLING, &fs_info->flags))
49264949
return 0;
49274950

49284951
if (!btrfs_is_fstree(root))

0 commit comments

Comments
 (0)