btrfsck: add early code to handle corrupted block groups

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>
master
Chris Mason 2012-02-21 21:20:54 -05:00
parent 8f01235dd8
commit e22827e9bb
6 changed files with 81 additions and 32 deletions

View File

@ -242,11 +242,6 @@ static void btrfs_corrupt_extent_tree(struct btrfs_trans_handle *trans,
if (!eb) if (!eb)
return; return;
if ((rand() % 10) == 0) {
corrupt_keys(trans, root, eb);
return;
}
nr = btrfs_header_nritems(eb); nr = btrfs_header_nritems(eb);
if (btrfs_is_leaf(eb)) { if (btrfs_is_leaf(eb)) {
btrfs_corrupt_extent_leaf(trans, root, eb); btrfs_corrupt_extent_leaf(trans, root, eb);

View File

@ -26,6 +26,7 @@
#include <getopt.h> #include <getopt.h>
#include "kerncompat.h" #include "kerncompat.h"
#include "ctree.h" #include "ctree.h"
#include "volumes.h"
#include "repair.h" #include "repair.h"
#include "disk-io.h" #include "disk-io.h"
#include "print-tree.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, static int check_extent_refs(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
struct cache_tree *extent_cache, int repair) 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 err = 0;
int ret = 0; int ret = 0;
int fixed = 0; int fixed = 0;
int reinit = 0;
if (repair) { if (repair) {
/* /*
@ -3174,6 +3225,9 @@ static int check_extent_refs(struct btrfs_trans_handle *trans,
cache = next_cache_extent(cache); cache = next_cache_extent(cache);
} }
prune_corrupt_blocks(trans, root->fs_info); 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) { while(1) {
fixed = 0; fixed = 0;
@ -3356,6 +3410,7 @@ static struct option long_options[] = {
{ "super", 1, NULL, 's' }, { "super", 1, NULL, 's' },
{ "repair", 0, NULL, 0 }, { "repair", 0, NULL, 0 },
{ "init-csum-tree", 0, NULL, 0 }, { "init-csum-tree", 0, NULL, 0 },
{ "init-extent-tree", 0, NULL, 0 },
{ 0, 0, 0, 0} { 0, 0, 0, 0}
}; };
@ -3444,7 +3499,6 @@ int main(int ac, char **av)
} }
goto out; goto out;
} }
ret = check_extents(trans, root, repair); ret = check_extents(trans, root, repair);
if (ret) if (ret)
fprintf(stderr, "Errors found in extent allocation tree\n"); fprintf(stderr, "Errors found in extent allocation tree\n");

View File

@ -151,8 +151,10 @@ int btrfs_fsck_reinit_root(struct btrfs_trans_handle *trans,
btrfs_level_size(root, 0), btrfs_level_size(root, 0),
root->root_key.objectid, root->root_key.objectid,
&disk_key, level, 0, 0); &disk_key, level, 0, 0);
if (IS_ERR(c)) if (IS_ERR(c)) {
return PTR_ERR(c); c = old;
extent_buffer_get(c);
}
memset_extent_buffer(c, 0, 0, sizeof(struct btrfs_header)); memset_extent_buffer(c, 0, 0, sizeof(struct btrfs_header));
btrfs_set_header_level(c, level); btrfs_set_header_level(c, level);
@ -1262,6 +1264,8 @@ again:
key->objectid); key->objectid);
b = read_node_slot(root, b, slot); b = read_node_slot(root, b, slot);
if (!extent_buffer_uptodate(b))
return -EIO;
} else { } else {
p->slots[level] = slot; p->slots[level] = slot;
if (ins_len > 0 && if (ins_len > 0 &&

View 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; cache = (struct btrfs_block_group_cache *)(unsigned long)ptr;
ret = write_one_cache_group(trans, root, path, cache); ret = write_one_cache_group(trans, root, path, cache);
BUG_ON(ret);
} }
btrfs_free_path(path); btrfs_free_path(path);
return 0; return 0;
@ -1894,6 +1893,10 @@ static int update_pinned_extents(struct btrfs_root *root,
} }
while (num > 0) { while (num > 0) {
cache = btrfs_lookup_block_group(fs_info, bytenr); cache = btrfs_lookup_block_group(fs_info, bytenr);
if (!cache) {
len = min((u64)root->sectorsize, num);
goto next;
}
WARN_ON(!cache); WARN_ON(!cache);
len = min(num, cache->key.offset - len = min(num, cache->key.offset -
(bytenr - cache->key.objectid)); (bytenr - cache->key.objectid));
@ -1906,6 +1909,7 @@ static int update_pinned_extents(struct btrfs_root *root,
cache->space_info->bytes_pinned -= len; cache->space_info->bytes_pinned -= len;
fs_info->total_pinned -= len; fs_info->total_pinned -= len;
} }
next:
bytenr += len; bytenr += len;
num -= len; num -= len;
} }
@ -2263,9 +2267,7 @@ static int __free_extent(struct btrfs_trans_handle *trans,
BUG_ON(ret); BUG_ON(ret);
} }
ret = update_block_group(trans, root, bytenr, num_bytes, 0, update_block_group(trans, root, bytenr, num_bytes, 0, mark_free);
mark_free);
BUG_ON(ret);
} }
fail: fail:
btrfs_free_path(path); 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, ret = update_block_group(trans, root, ins->objectid, ins->offset,
1, 0); 1, 0);
if (ret) { return 0;
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;
} }
static int alloc_tree_block(struct btrfs_trans_handle *trans, 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); finish_current_insert(trans, extent_root);
ret = del_pending_extents(trans, extent_root); ret = del_pending_extents(trans, extent_root);
BUG_ON(ret);
set_avail_alloc_bits(extent_root->fs_info, type); set_avail_alloc_bits(extent_root->fs_info, type);
return 0; return 0;
} }

View File

@ -35,18 +35,6 @@ struct stripe {
u64 physical; 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) + \ #define map_lookup_size(n) (sizeof(struct map_lookup) + \
(sizeof(struct btrfs_bio_stripe) * (n))) (sizeof(struct btrfs_bio_stripe) * (n)))

View File

@ -18,6 +18,7 @@
#ifndef __BTRFS_VOLUMES_ #ifndef __BTRFS_VOLUMES_
#define __BTRFS_VOLUMES_ #define __BTRFS_VOLUMES_
struct btrfs_device { struct btrfs_device {
struct list_head dev_list; struct list_head dev_list;
struct btrfs_root *dev_root; struct btrfs_root *dev_root;
@ -88,6 +89,18 @@ struct btrfs_multi_bio {
struct btrfs_bio_stripe stripes[]; 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) + \ #define btrfs_multi_bio_size(n) (sizeof(struct btrfs_multi_bio) + \
(sizeof(struct btrfs_bio_stripe) * (n))) (sizeof(struct btrfs_bio_stripe) * (n)))