btrfsck: add early code to handle corrupted block groups
authorChris Mason <chris.mason@oracle.com>
Wed, 22 Feb 2012 02:20:54 +0000 (21:20 -0500)
committerChris Mason <chris.mason@oracle.com>
Wed, 22 Feb 2012 15:59:55 +0000 (10:59 -0500)
This is mostly disabled, but it is step one in handling
corrupted block groups in the extent allocation tree.

Signed-off-by: Chris Mason <chris.mason@oracle.com>
btrfs-corrupt-block.c
btrfsck.c
ctree.c
extent-tree.c
volumes.c
volumes.h

index 980a006..7051e99 100644 (file)
@@ -242,11 +242,6 @@ static void btrfs_corrupt_extent_tree(struct btrfs_trans_handle *trans,
        if (!eb)
                return;
 
-       if ((rand() % 10) == 0) {
-               corrupt_keys(trans, root, eb);
-               return;
-       }
-
        nr = btrfs_header_nritems(eb);
        if (btrfs_is_leaf(eb)) {
                btrfs_corrupt_extent_leaf(trans, root, eb);
index 127f119..7aac736 100644 (file)
--- a/btrfsck.c
+++ b/btrfsck.c
@@ -26,6 +26,7 @@
 #include <getopt.h>
 #include "kerncompat.h"
 #include "ctree.h"
+#include "volumes.h"
 #include "repair.h"
 #include "disk-io.h"
 #include "print-tree.h"
@@ -3140,6 +3141,55 @@ static void free_corrupt_blocks(struct btrfs_fs_info *info)
        }
 }
 
+static int check_block_group(struct btrfs_trans_handle *trans,
+                             struct btrfs_fs_info *info,
+                             struct map_lookup *map,
+                             int *reinit)
+{
+       struct btrfs_key key;
+       struct btrfs_path path;
+       int ret;
+
+       key.objectid = map->ce.start;
+       key.offset = map->ce.size;
+       key.type = BTRFS_BLOCK_GROUP_ITEM_KEY;
+
+       btrfs_init_path(&path);
+       ret = btrfs_search_slot(NULL, info->extent_root,
+                               &key, &path, 0, 0);
+       btrfs_release_path(NULL, &path);
+       if (ret <= 0)
+               goto out;
+
+       ret = btrfs_make_block_group(trans, info->extent_root, 0, map->type,
+                              BTRFS_FIRST_CHUNK_TREE_OBJECTID,
+                              key.objectid, key.offset);
+       *reinit = 1;
+out:
+       return ret;
+}
+
+static int check_block_groups(struct btrfs_trans_handle *trans,
+                             struct btrfs_fs_info *info, int *reinit)
+{
+       struct cache_extent *ce;
+       struct map_lookup *map;
+       struct btrfs_mapping_tree *map_tree = &info->mapping_tree;
+
+       /* this isn't quite working */
+       return 0;
+
+       ce = find_first_cache_extent(&map_tree->cache_tree, 0);
+       while (1) {
+               if (!ce)
+                       break;
+               map = container_of(ce, struct map_lookup, ce);
+               check_block_group(trans, info, map, reinit);
+               ce = next_cache_extent(ce);
+       }
+       return 0;
+}
+
 static int check_extent_refs(struct btrfs_trans_handle *trans,
                             struct btrfs_root *root,
                             struct cache_tree *extent_cache, int repair)
@@ -3149,6 +3199,7 @@ static int check_extent_refs(struct btrfs_trans_handle *trans,
        int err = 0;
        int ret = 0;
        int fixed = 0;
+       int reinit = 0;
 
        if (repair) {
                /*
@@ -3174,6 +3225,9 @@ static int check_extent_refs(struct btrfs_trans_handle *trans,
                        cache = next_cache_extent(cache);
                }
                prune_corrupt_blocks(trans, root->fs_info);
+               check_block_groups(trans, root->fs_info, &reinit);
+               if (reinit)
+                       btrfs_read_block_groups(root->fs_info->extent_root);
        }
        while(1) {
                fixed = 0;
@@ -3356,6 +3410,7 @@ static struct option long_options[] = {
        { "super", 1, NULL, 's' },
        { "repair", 0, NULL, 0 },
        { "init-csum-tree", 0, NULL, 0 },
+       { "init-extent-tree", 0, NULL, 0 },
        { 0, 0, 0, 0}
 };
 
@@ -3444,7 +3499,6 @@ int main(int ac, char **av)
                }
                goto out;
        }
-
        ret = check_extents(trans, root, repair);
        if (ret)
                fprintf(stderr, "Errors found in extent allocation tree\n");
diff --git a/ctree.c b/ctree.c
index a49bce4..2d86b1e 100644 (file)
--- a/ctree.c
+++ b/ctree.c
@@ -151,8 +151,10 @@ int btrfs_fsck_reinit_root(struct btrfs_trans_handle *trans,
                                   btrfs_level_size(root, 0),
                                   root->root_key.objectid,
                                   &disk_key, level, 0, 0);
-       if (IS_ERR(c))
-               return PTR_ERR(c);
+       if (IS_ERR(c)) {
+               c = old;
+               extent_buffer_get(c);
+       }
 
        memset_extent_buffer(c, 0, 0, sizeof(struct btrfs_header));
        btrfs_set_header_level(c, level);
@@ -1262,6 +1264,8 @@ again:
                                                 key->objectid);
 
                        b = read_node_slot(root, b, slot);
+                       if (!extent_buffer_uptodate(b))
+                               return -EIO;
                } else {
                        p->slots[level] = slot;
                        if (ins_len > 0 &&
index ee87f1f..20cdffa 100644 (file)
@@ -1703,7 +1703,6 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
 
                cache = (struct btrfs_block_group_cache *)(unsigned long)ptr;
                ret = write_one_cache_group(trans, root, path, cache);
-               BUG_ON(ret);
        }
        btrfs_free_path(path);
        return 0;
@@ -1894,6 +1893,10 @@ static int update_pinned_extents(struct btrfs_root *root,
        }
        while (num > 0) {
                cache = btrfs_lookup_block_group(fs_info, bytenr);
+               if (!cache) {
+                       len = min((u64)root->sectorsize, num);
+                       goto next;
+               }
                WARN_ON(!cache);
                len = min(num, cache->key.offset -
                          (bytenr - cache->key.objectid));
@@ -1906,6 +1909,7 @@ static int update_pinned_extents(struct btrfs_root *root,
                        cache->space_info->bytes_pinned -= len;
                        fs_info->total_pinned -= len;
                }
+next:
                bytenr += len;
                num -= len;
        }
@@ -2263,9 +2267,7 @@ static int __free_extent(struct btrfs_trans_handle *trans,
                        BUG_ON(ret);
                }
 
-               ret = update_block_group(trans, root, bytenr, num_bytes, 0,
-                                        mark_free);
-               BUG_ON(ret);
+               update_block_group(trans, root, bytenr, num_bytes, 0, mark_free);
        }
 fail:
        btrfs_free_path(path);
@@ -2596,13 +2598,7 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
 
        ret = update_block_group(trans, root, ins->objectid, ins->offset,
                                 1, 0);
-       if (ret) {
-               printk(KERN_ERR "btrfs update block group failed for %llu "
-                      "%llu\n", (unsigned long long)ins->objectid,
-                      (unsigned long long)ins->offset);
-               BUG();
-       }
-       return ret;
+       return 0;
 }
 
 static int alloc_tree_block(struct btrfs_trans_handle *trans,
@@ -3185,7 +3181,6 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
 
        finish_current_insert(trans, extent_root);
        ret = del_pending_extents(trans, extent_root);
-       BUG_ON(ret);
        set_avail_alloc_bits(extent_root->fs_info, type);
        return 0;
 }
index 375713f..8dca5e1 100644 (file)
--- a/volumes.c
+++ b/volumes.c
@@ -35,18 +35,6 @@ struct stripe {
        u64 physical;
 };
 
-struct map_lookup {
-       struct cache_extent ce;
-       u64 type;
-       int io_align;
-       int io_width;
-       int stripe_len;
-       int sector_size;
-       int num_stripes;
-       int sub_stripes;
-       struct btrfs_bio_stripe stripes[];
-};
-
 #define map_lookup_size(n) (sizeof(struct map_lookup) + \
                            (sizeof(struct btrfs_bio_stripe) * (n)))
 
index d7fcef6..9ff6182 100644 (file)
--- a/volumes.h
+++ b/volumes.h
@@ -18,6 +18,7 @@
 
 #ifndef __BTRFS_VOLUMES_
 #define __BTRFS_VOLUMES_
+
 struct btrfs_device {
        struct list_head dev_list;
        struct btrfs_root *dev_root;
@@ -88,6 +89,18 @@ struct btrfs_multi_bio {
        struct btrfs_bio_stripe stripes[];
 };
 
+struct map_lookup {
+       struct cache_extent ce;
+       u64 type;
+       int io_align;
+       int io_width;
+       int stripe_len;
+       int sector_size;
+       int num_stripes;
+       int sub_stripes;
+       struct btrfs_bio_stripe stripes[];
+};
+
 #define btrfs_multi_bio_size(n) (sizeof(struct btrfs_multi_bio) + \
                            (sizeof(struct btrfs_bio_stripe) * (n)))