diff --git a/btrfs-corrupt-block.c b/btrfs-corrupt-block.c index 980a006d..7051e99c 100644 --- a/btrfs-corrupt-block.c +++ b/btrfs-corrupt-block.c @@ -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); diff --git a/btrfsck.c b/btrfsck.c index 127f1192..7aac736a 100644 --- a/btrfsck.c +++ b/btrfsck.c @@ -26,6 +26,7 @@ #include #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 a49bce48..2d86b1e7 100644 --- 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 && diff --git a/extent-tree.c b/extent-tree.c index ee87f1f1..20cdffa8 100644 --- a/extent-tree.c +++ b/extent-tree.c @@ -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; } diff --git a/volumes.c b/volumes.c index 375713f2..8dca5e10 100644 --- 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))) diff --git a/volumes.h b/volumes.h index d7fcef66..9ff6182e 100644 --- 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)))