Simple quotas count extents only from the moment the feature is enabled. Therefore, if we do something like: 1. create subvol S 2. write F in S 3. enable quotas 4. remove F 5. write G in S then after 3. and 4. we would expect the simple quota usage of S to be 0 (putting aside some metadata extents that might be written) and after 5., it should be the size of G plus metadata. Therefore, we need to be able to determine whether a particular quota delta we are processing predates simple quota enablement. To do this, store the transaction id when quotas were enabled. In fs_info for immediate use and in the quota status item to make it recoverable on mount. When we see a delta, check if the generation of the extent item is less than that of quota enablement. If so, we should ignore the delta from this extent.
Unified · Split
| @@ -980,6 +980,8 @@ BTRFS_SETGET_FUNCS(qgroup_status_flags, struct btrfs_qgroup_status_item, · 979 unmodified lines | ||
| 980 | 980 | flags, 64); |
| 981 | 981 | BTRFS_SETGET_FUNCS(qgroup_status_rescan, struct btrfs_qgroup_status_item, |
| 982 | 982 | rescan, 64); |
| 983 | +BTRFS_SETGET_FUNCS(qgroup_status_enable_gen, struct btrfs_qgroup_status_item, | |
| 984 | + enable_gen, 64); | |
| 983 | 985 | |
| 984 | 986 | /* btrfs_qgroup_info_item */ |
| 985 | 987 | BTRFS_SETGET_FUNCS(qgroup_info_generation, struct btrfs_qgroup_info_item, |
| @@ -1566,6 +1566,7 @@ static int run_delayed_data_ref(struct btrfs_trans_handle *trans, · 1565 unmodified lines | ||
| 1566 | 1566 | .rsv_bytes = href->reserved_bytes, |
| 1567 | 1567 | .is_data = true, |
| 1568 | 1568 | .is_inc = true, |
| 1569 | + .generation = trans->transid, | |
| 1569 | 1570 | }; |
| 1570 | 1571 | |
| 1571 | 1572 | if (extent_op) |
| @@ -1738,6 +1739,7 @@ static int run_delayed_tree_ref(struct btrfs_trans_handle *trans, · 166 unmodified lines | ||
| 1738 | 1739 | .rsv_bytes = 0, |
| 1739 | 1740 | .is_data = false, |
| 1740 | 1741 | .is_inc = true, |
| 1742 | + .generation = trans->transid, | |
| 1741 | 1743 | }; |
| 1742 | 1744 | |
| 1743 | 1745 | BUG_ON(!extent_op || !extent_op->update_flags); |
| @@ -3287,6 +3289,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans, · 1543 unmodified lines | ||
| 3287 | 3289 | .rsv_bytes = 0, |
| 3288 | 3290 | .is_data = is_data, |
| 3289 | 3291 | .is_inc = false, |
| 3292 | + .generation = btrfs_extent_generation(leaf, ei), | |
| 3290 | 3293 | }; |
| 3291 | 3294 | |
| 3292 | 3295 | /* In this branch refs == 1 */ |
| @@ -4924,6 +4927,7 @@ int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans, · 1631 unmodified lines | ||
| 4924 | 4927 | struct btrfs_squota_delta delta = { |
| 4925 | 4928 | .root = root_objectid, |
| 4926 | 4929 | .num_bytes = ins->offset, |
| 4930 | + .generation = trans->transid, | |
| 4927 | 4931 | .rsv_bytes = 0, |
| 4928 | 4932 | .is_data = true, |
| 4929 | 4933 | .is_inc = true, |
| @@ -687,6 +687,7 @@ struct btrfs_fs_info { · 686 unmodified lines | ||
| 687 | 687 | /* Protected by qgroup_rescan_lock */ |
| 688 | 688 | bool qgroup_rescan_running; |
| 689 | 689 | u8 qgroup_drop_subtree_thres; |
| 690 | + u64 qgroup_enable_gen; | |
| 690 | 691 | |
| 691 | 692 | /* |
| 692 | 693 | * If this is not 0, then it indicates a serious filesystem error has |
| @@ -369,6 +369,15 @@ static void qgroup_mark_inconsistent(struct btrfs_fs_info *fs_info) · 368 unmodified lines | ||
| 369 | 369 | BTRFS_QGROUP_RUNTIME_FLAG_NO_ACCOUNTING); |
| 370 | 370 | } |
| 371 | 371 | |
| 372 | +static void qgroup_read_enable_gen(struct btrfs_fs_info *fs_info, | |
| 373 | + struct extent_buffer *leaf, int slot, | |
| 374 | + struct btrfs_qgroup_status_item *ptr) | |
| 375 | +{ | |
| 376 | + ASSERT(btrfs_fs_incompat(fs_info, SIMPLE_QUOTA)); | |
| 377 | + ASSERT(btrfs_item_size(leaf, slot) >= sizeof(*ptr)); | |
| 378 | + fs_info->qgroup_enable_gen = btrfs_qgroup_status_enable_gen(leaf, ptr); | |
| 379 | +} | |
| 380 | + | |
| 372 | 381 | /* |
| 373 | 382 | * The full config is read in one go, only called from open_ctree() |
| 374 | 383 | * It doesn't use any locking, as at this point we're still single-threaded |
| @@ -384,7 +393,6 @@ int btrfs_read_qgroup_config(struct btrfs_fs_info *fs_info) · 9 unmodified lines | ||
| 384 | 393 | int ret = 0; |
| 385 | 394 | u64 flags = 0; |
| 386 | 395 | u64 rescan_progress = 0; |
| 387 | − bool simple; | |
| 388 | 396 | |
| 389 | 397 | if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_DISABLED) |
| 390 | 398 | return 0; |
| @@ -437,9 +445,9 @@ int btrfs_read_qgroup_config(struct btrfs_fs_info *fs_info) · 46 unmodified lines | ||
| 437 | 445 | goto out; |
| 438 | 446 | } |
| 439 | 447 | fs_info->qgroup_flags = btrfs_qgroup_status_flags(l, ptr); |
| 440 | − simple = (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_SIMPLE_MODE); | |
| 441 | − if (btrfs_qgroup_status_generation(l, ptr) != | |
| 442 | − fs_info->generation && !simple) { | |
| 448 | + if (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_SIMPLE_MODE) { | |
| 449 | + qgroup_read_enable_gen(fs_info, l, slot, ptr); | |
| 450 | + } else if (btrfs_qgroup_status_generation(l, ptr) != fs_info->generation) { | |
| 443 | 451 | qgroup_mark_inconsistent(fs_info); |
| 444 | 452 | btrfs_err(fs_info, |
| 445 | 453 | "qgroup generation mismatch, marked as inconsistent"); |
| @@ -1103,10 +1111,12 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info, · 657 unmodified lines | ||
| 1103 | 1111 | btrfs_set_qgroup_status_generation(leaf, ptr, trans->transid); |
| 1104 | 1112 | btrfs_set_qgroup_status_version(leaf, ptr, BTRFS_QGROUP_STATUS_VERSION); |
| 1105 | 1113 | fs_info->qgroup_flags = BTRFS_QGROUP_STATUS_FLAG_ON; |
| 1106 | − if (simple) | |
| 1114 | + if (simple) { | |
| 1107 | 1115 | fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_SIMPLE_MODE; |
| 1108 | − else | |
| 1116 | + btrfs_set_qgroup_status_enable_gen(leaf, ptr, trans->transid); | |
| 1117 | + } else { | |
| 1109 | 1118 | fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; |
| 1119 | + } | |
| 1110 | 1120 | btrfs_set_qgroup_status_flags(leaf, ptr, fs_info->qgroup_flags & |
| 1111 | 1121 | BTRFS_QGROUP_STATUS_FLAGS_MASK); |
| 1112 | 1122 | btrfs_set_qgroup_status_rescan(leaf, ptr, 0); |
| @@ -1210,6 +1220,8 @@ out_add_root: · 97 unmodified lines | ||
| 1210 | 1220 | goto out_free_path; |
| 1211 | 1221 | } |
| 1212 | 1222 | |
| 1223 | + fs_info->qgroup_enable_gen = trans->transid; | |
| 1224 | + | |
| 1213 | 1225 | mutex_unlock(&fs_info->qgroup_ioctl_lock); |
| 1214 | 1226 | /* |
| 1215 | 1227 | * Commit the transaction while not holding qgroup_ioctl_lock, to avoid |
| @@ -4655,6 +4667,10 @@ int btrfs_record_squota_delta(struct btrfs_fs_info *fs_info, · 3439 unmodified lines | ||
| 4655 | 4667 | if (!is_fstree(root)) |
| 4656 | 4668 | return 0; |
| 4657 | 4669 | |
| 4670 | + /* If the extent predates enabling quotas, don't count it. */ | |
| 4671 | + if (delta->generation < fs_info->qgroup_enable_gen) | |
| 4672 | + return 0; | |
| 4673 | + | |
| 4658 | 4674 | spin_lock(&fs_info->qgroup_lock); |
| 4659 | 4675 | qgroup = find_qgroup_rb(fs_info, root); |
| 4660 | 4676 | if (!qgroup) { |
| @@ -276,6 +276,8 @@ struct btrfs_squota_delta { · 275 unmodified lines | ||
| 276 | 276 | u64 num_bytes; |
| 277 | 277 | /* The number of bytes reserved for this extent. */ |
| 278 | 278 | u64 rsv_bytes; |
| 279 | + /* The generation the extent was created in. */ | |
| 280 | + u64 generation; | |
| 279 | 281 | /* Whether we are using or freeing the extent. */ |
| 280 | 282 | bool is_inc; |
| 281 | 283 | /* Whether the extent is data or metadata. */ |
| @@ -1277,6 +1277,15 @@ struct btrfs_qgroup_status_item { · 1276 unmodified lines | ||
| 1277 | 1277 | * of the scan. It contains a logical address |
| 1278 | 1278 | */ |
| 1279 | 1279 | __le64 rescan; |
| 1280 | + | |
| 1281 | + /* | |
| 1282 | + * The generation when quotas were last enabled. Used by simple quotas to | |
| 1283 | + * avoid decrementing when freeing an extent that was written before | |
| 1284 | + * enable. | |
| 1285 | + * | |
| 1286 | + * Set only if flags contain BTRFS_QGROUP_STATUS_FLAG_SIMPLE_MODE. | |
| 1287 | + */ | |
| 1288 | + __le64 enable_gen; | |
| 1280 | 1289 | } __attribute__ ((__packed__)); |
| 1281 | 1290 | |
| 1282 | 1291 | struct btrfs_qgroup_info_item { |