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 | flags, 64); | 980 | flags, 64); |
| 981 | BTRFS_SETGET_FUNCS(qgroup_status_rescan, struct btrfs_qgroup_status_item, | 981 | BTRFS_SETGET_FUNCS(qgroup_status_rescan, struct btrfs_qgroup_status_item, |
| 982 | rescan, 64); | 982 | rescan, 64); |
| 983 | BTRFS_SETGET_FUNCS(qgroup_status_enable_gen, struct btrfs_qgroup_status_item, | ||
| 984 | enable_gen, 64); | ||
| 983 | 985 | ||
| 984 | /* btrfs_qgroup_info_item */ | 986 | /* btrfs_qgroup_info_item */ |
| 985 | BTRFS_SETGET_FUNCS(qgroup_info_generation, struct btrfs_qgroup_info_item, | 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 | .rsv_bytes = href->reserved_bytes, | 1566 | .rsv_bytes = href->reserved_bytes, |
| 1567 | .is_data = true, | 1567 | .is_data = true, |
| 1568 | .is_inc = true, | 1568 | .is_inc = true, |
| 1569 | .generation = trans->transid, | ||
| 1569 | }; | 1570 | }; |
| 1570 | 1571 | ||
| 1571 | if (extent_op) | 1572 | if (extent_op) |
| @@ -1738,6 +1739,7 @@ static int run_delayed_tree_ref(struct btrfs_trans_handle *trans, · 166 unmodified lines | |||
| 1738 | .rsv_bytes = 0, | 1739 | .rsv_bytes = 0, |
| 1739 | .is_data = false, | 1740 | .is_data = false, |
| 1740 | .is_inc = true, | 1741 | .is_inc = true, |
| 1742 | .generation = trans->transid, | ||
| 1741 | }; | 1743 | }; |
| 1742 | 1744 | ||
| 1743 | BUG_ON(!extent_op || !extent_op->update_flags); | 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 | .rsv_bytes = 0, | 3289 | .rsv_bytes = 0, |
| 3288 | .is_data = is_data, | 3290 | .is_data = is_data, |
| 3289 | .is_inc = false, | 3291 | .is_inc = false, |
| 3292 | .generation = btrfs_extent_generation(leaf, ei), | ||
| 3290 | }; | 3293 | }; |
| 3291 | 3294 | ||
| 3292 | /* In this branch refs == 1 */ | 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 | struct btrfs_squota_delta delta = { | 4927 | struct btrfs_squota_delta delta = { |
| 4925 | .root = root_objectid, | 4928 | .root = root_objectid, |
| 4926 | .num_bytes = ins->offset, | 4929 | .num_bytes = ins->offset, |
| 4930 | .generation = trans->transid, | ||
| 4927 | .rsv_bytes = 0, | 4931 | .rsv_bytes = 0, |
| 4928 | .is_data = true, | 4932 | .is_data = true, |
| 4929 | .is_inc = true, | 4933 | .is_inc = true, |
| @@ -687,6 +687,7 @@ struct btrfs_fs_info { · 686 unmodified lines | |||
| 687 | /* Protected by qgroup_rescan_lock */ | 687 | /* Protected by qgroup_rescan_lock */ |
| 688 | bool qgroup_rescan_running; | 688 | bool qgroup_rescan_running; |
| 689 | u8 qgroup_drop_subtree_thres; | 689 | u8 qgroup_drop_subtree_thres; |
| 690 | u64 qgroup_enable_gen; | ||
| 690 | 691 | ||
| 691 | /* | 692 | /* |
| 692 | * If this is not 0, then it indicates a serious filesystem error has | 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 | BTRFS_QGROUP_RUNTIME_FLAG_NO_ACCOUNTING); | 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 | * The full config is read in one go, only called from open_ctree() | 382 | * The full config is read in one go, only called from open_ctree() |
| 374 | * It doesn't use any locking, as at this point we're still single-threaded | 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 | int ret = 0; | 393 | int ret = 0; |
| 385 | u64 flags = 0; | 394 | u64 flags = 0; |
| 386 | u64 rescan_progress = 0; | 395 | u64 rescan_progress = 0; |
| 387 | bool simple; | ||
| 388 | 396 | ||
| 389 | if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_DISABLED) | 397 | if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_DISABLED) |
| 390 | return 0; | 398 | return 0; |
| @@ -437,9 +445,9 @@ int btrfs_read_qgroup_config(struct btrfs_fs_info *fs_info) · 46 unmodified lines | |||
| 437 | goto out; | 445 | goto out; |
| 438 | } | 446 | } |
| 439 | fs_info->qgroup_flags = btrfs_qgroup_status_flags(l, ptr); | 447 | fs_info->qgroup_flags = btrfs_qgroup_status_flags(l, ptr); |
| 440 | simple = (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_SIMPLE_MODE); | 448 | if (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_SIMPLE_MODE) { |
| 441 | if (btrfs_qgroup_status_generation(l, ptr) != | 449 | qgroup_read_enable_gen(fs_info, l, slot, ptr); |
| 442 | fs_info->generation && !simple) { | 450 | } else if (btrfs_qgroup_status_generation(l, ptr) != fs_info->generation) { |
| 443 | qgroup_mark_inconsistent(fs_info); | 451 | qgroup_mark_inconsistent(fs_info); |
| 444 | btrfs_err(fs_info, | 452 | btrfs_err(fs_info, |
| 445 | "qgroup generation mismatch, marked as inconsistent"); | 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 | btrfs_set_qgroup_status_generation(leaf, ptr, trans->transid); | 1111 | btrfs_set_qgroup_status_generation(leaf, ptr, trans->transid); |
| 1104 | btrfs_set_qgroup_status_version(leaf, ptr, BTRFS_QGROUP_STATUS_VERSION); | 1112 | btrfs_set_qgroup_status_version(leaf, ptr, BTRFS_QGROUP_STATUS_VERSION); |
| 1105 | fs_info->qgroup_flags = BTRFS_QGROUP_STATUS_FLAG_ON; | 1113 | fs_info->qgroup_flags = BTRFS_QGROUP_STATUS_FLAG_ON; |
| 1106 | if (simple) | 1114 | if (simple) { |
| 1107 | fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_SIMPLE_MODE; | 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 | fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; | 1118 | fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; |
| 1119 | } | ||
| 1110 | btrfs_set_qgroup_status_flags(leaf, ptr, fs_info->qgroup_flags & | 1120 | btrfs_set_qgroup_status_flags(leaf, ptr, fs_info->qgroup_flags & |
| 1111 | BTRFS_QGROUP_STATUS_FLAGS_MASK); | 1121 | BTRFS_QGROUP_STATUS_FLAGS_MASK); |
| 1112 | btrfs_set_qgroup_status_rescan(leaf, ptr, 0); | 1122 | btrfs_set_qgroup_status_rescan(leaf, ptr, 0); |
| @@ -1210,6 +1220,8 @@ out_add_root: · 97 unmodified lines | |||
| 1210 | goto out_free_path; | 1220 | goto out_free_path; |
| 1211 | } | 1221 | } |
| 1212 | 1222 | ||
| 1223 | fs_info->qgroup_enable_gen = trans->transid; | ||
| 1224 | |||
| 1213 | mutex_unlock(&fs_info->qgroup_ioctl_lock); | 1225 | mutex_unlock(&fs_info->qgroup_ioctl_lock); |
| 1214 | /* | 1226 | /* |
| 1215 | * Commit the transaction while not holding qgroup_ioctl_lock, to avoid | 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 | if (!is_fstree(root)) | 4667 | if (!is_fstree(root)) |
| 4656 | return 0; | 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 | spin_lock(&fs_info->qgroup_lock); | 4674 | spin_lock(&fs_info->qgroup_lock); |
| 4659 | qgroup = find_qgroup_rb(fs_info, root); | 4675 | qgroup = find_qgroup_rb(fs_info, root); |
| 4660 | if (!qgroup) { | 4676 | if (!qgroup) { |
| @@ -276,6 +276,8 @@ struct btrfs_squota_delta { · 275 unmodified lines | |||
| 276 | u64 num_bytes; | 276 | u64 num_bytes; |
| 277 | /* The number of bytes reserved for this extent. */ | 277 | /* The number of bytes reserved for this extent. */ |
| 278 | u64 rsv_bytes; | 278 | u64 rsv_bytes; |
| 279 | /* The generation the extent was created in. */ | ||
| 280 | u64 generation; | ||
| 279 | /* Whether we are using or freeing the extent. */ | 281 | /* Whether we are using or freeing the extent. */ |
| 280 | bool is_inc; | 282 | bool is_inc; |
| 281 | /* Whether the extent is data or metadata. */ | 283 | /* Whether the extent is data or metadata. */ |
| @@ -1277,6 +1277,15 @@ struct btrfs_qgroup_status_item { · 1276 unmodified lines | |||
| 1277 | * of the scan. It contains a logical address | 1277 | * of the scan. It contains a logical address |
| 1278 | */ | 1278 | */ |
| 1279 | __le64 rescan; | 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 | } __attribute__ ((__packed__)); | 1289 | } __attribute__ ((__packed__)); |
| 1281 | 1290 | ||
| 1282 | struct btrfs_qgroup_info_item { | 1291 | struct btrfs_qgroup_info_item { |