@@ -2805,6 +2805,34 @@ static int check_extents(struct btrfs_root *root)
return ret;
}
+static void check_space_used(struct btrfs_root *root)
+{
+ struct btrfs_fs_info *info = root->fs_info;
+ u64 total;
+ u64 super_total;
+
+ total = btrfs_total_used(root);
+ super_total = btrfs_super_bytes_used(&info->super_copy);
+
+ if (total != super_total) {
+ struct btrfs_trans_handle *trans;
+
+ trans = btrfs_start_transaction(root, 1);
+ if (!trans)
+ return;
+ printf("Super total bytes used (%llu) doesn't match actual "
+ "bytes used (%llu). Fixing.\n",
+ (unsigned long long)super_total,
+ (unsigned long long)total);
+ btrfs_set_super_bytes_used(&info->super_copy, total);
+ btrfs_commit_transaction(trans, root);
+ } else {
+ printf("Super total bytes used (%llu) matches actual (%llu)\n",
+ (unsigned long long)super_total,
+ (unsigned long long)total);
+ }
+}
+
static void print_usage(void)
{
fprintf(stderr, "usage: btrfsck dev\n");
@@ -2836,6 +2864,8 @@ int main(int ac, char **av)
goto out;
ret = check_root_refs(root, &root_cache);
+ if (!ret)
+ check_space_used(root);
out:
free_root_recs(&root_cache);
close_ctree(root);
@@ -1699,6 +1699,7 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 bytes_used,
u64 type, u64 chunk_objectid, u64 chunk_offset,
u64 size);
+u64 btrfs_total_used(struct btrfs_root *root);
int btrfs_make_block_groups(struct btrfs_trans_handle *trans,
struct btrfs_root *root);
int btrfs_update_block_group(struct btrfs_trans_handle *trans,
@@ -3135,6 +3135,38 @@ error:
return ret;
}
+u64 btrfs_total_used(struct btrfs_root *root)
+{
+ struct btrfs_block_group_cache *cache;
+ struct extent_io_tree *block_group_cache;
+ int ret;
+ u64 ptr;
+ u64 start;
+ u64 end;
+ u64 total = 0;
+
+ block_group_cache = &root->fs_info->block_group_cache;
+ start = BTRFS_SUPER_INFO_OFFSET + BTRFS_SUPER_INFO_SIZE;
+ while (1) {
+ ret = find_first_extent_bit(block_group_cache,
+ start, &start, &end,
+ BLOCK_GROUP_DATA |
+ BLOCK_GROUP_METADATA |
+ BLOCK_GROUP_SYSTEM);
+ if (ret)
+ break;
+ ret = get_state_private(block_group_cache, start, &ptr);
+ if (ret)
+ break;
+
+ cache = (struct btrfs_block_group_cache *)(unsigned long)ptr;
+ total += btrfs_block_group_used(&cache->item);
+ start = end + 1;
+ }
+
+ return total;
+}
+
int btrfs_make_block_group(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 bytes_used,
u64 type, u64 chunk_objectid, u64 chunk_offset,