Hi,

   > Here's a patch to btrfsck from Josef that should fix this:

Sorry, that was an older patch.  This is the working one:


From: Josef Bacik <jba...@redhat.com>
Date: Wed, 14 Oct 2009 14:39:26 -0400
Subject: [PATCH] patch fix-space-accounting.patch


Signed-off-by: Josef Bacik <jba...@redhat.com>
---
 btrfsck.c     |   32 +++++++++++++++++++++++++++++
 ctree.h       |    2 +
 disk-io.c     |   47 +++++++++++++++++++++++++++++++++++++++++++
 disk-io.h     |    2 +
 extent-tree.c |   62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 145 insertions(+), 0 deletions(-)

diff --git a/btrfsck.c b/btrfsck.c
index 46a6eae..1aaf022 100644
--- a/btrfsck.c
+++ b/btrfsck.c
@@ -2805,6 +2805,36 @@ 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;
+
+               btrfs_make_readwrite(info);
+               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);
+               btrfs_make_readonly(info);
+       } 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 +2866,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);
diff --git a/ctree.h b/ctree.h
index a9062ea..0681017 100644
--- a/ctree.h
+++ b/ctree.h
@@ -1699,6 +1699,8 @@ 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);
+void btrfs_update_block_groups_readonly(struct btrfs_fs_info *info);
 int btrfs_make_block_groups(struct btrfs_trans_handle *trans,
                            struct btrfs_root *root);
 int btrfs_update_block_group(struct btrfs_trans_handle *trans,
diff --git a/disk-io.c b/disk-io.c
index 4d4e902..ecea152 100644
--- a/disk-io.c
+++ b/disk-io.c
@@ -946,6 +946,53 @@ static int close_all_devices(struct btrfs_fs_info *fs_info)
        return 0;
 }
 
+int btrfs_make_readwrite(struct btrfs_fs_info *fs_info)
+{
+       struct list_head *list;
+       struct list_head *next;
+       struct list_head *tmp;
+       struct btrfs_device *device;
+       int fd;
+
+       list = &fs_info->fs_devices->devices;
+       list_for_each_safe(next, tmp, list) {
+               device = list_entry(next, struct btrfs_device, dev_list);
+               close(device->fd);
+               fd = open(device->name, O_RDWR);
+               if (fd < 0)
+                       return -errno;
+               device->fd = fd;
+               device->writeable = 1;
+       }
+       fs_info->readonly = 0;
+       btrfs_update_block_groups_readonly(fs_info);
+       return 0;
+}
+
+int btrfs_make_readonly(struct btrfs_fs_info *fs_info)
+{
+       struct list_head *list;
+       struct list_head *next;
+       struct list_head *tmp;
+       struct btrfs_device *device;
+       int fd;
+
+       list = &fs_info->fs_devices->devices;
+       list_for_each_safe(next, tmp, list) {
+               device = list_entry(next, struct btrfs_device, dev_list);
+               close(device->fd);
+               fd = open(device->name, O_RDONLY);
+               if (fd < 0)
+                       return -errno;
+               device->fd = fd;
+               device->writeable = 0;
+       }
+       fs_info->readonly = 1;
+       btrfs_update_block_groups_readonly(fs_info);
+       return 0;
+
+}
+
 int close_ctree(struct btrfs_root *root)
 {
        int ret;
diff --git a/disk-io.h b/disk-io.h
index 49e5692..646586e 100644
--- a/disk-io.h
+++ b/disk-io.h
@@ -75,4 +75,6 @@ int csum_tree_block_size(struct extent_buffer *buf, u16 
csum_sectorsize,
 int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf,
                    int verify);
 int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid);
+int btrfs_make_readwrite(struct btrfs_fs_info *fs_info);
+int btrfs_make_readonly(struct btrfs_fs_info *fs_info);
 #endif
diff --git a/extent-tree.c b/extent-tree.c
index e1d7ffd..49bffe7 100644
--- a/extent-tree.c
+++ b/extent-tree.c
@@ -3135,6 +3135,68 @@ error:
        return ret;
 }
 
+void btrfs_update_block_groups_readonly(struct btrfs_fs_info *info)
+{
+       struct btrfs_block_group_cache *cache;
+       struct extent_io_tree *block_group_cache;
+       int ret;
+       u64 ptr;
+       u64 start;
+       u64 end;
+
+       block_group_cache = &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;
+               cache->ro = btrfs_chunk_readonly(info->extent_root,
+                                                cache->key.objectid);
+               start = end + 1;
+       }
+}
+
+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,
-- 
1.5.4.3

-- 
Chris Ball   <c...@laptop.org>
One Laptop Per Child
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to