2c5c7c6753
- rebuild extent records - fix block group accounting - reset csums for rescue nodatasum mount - prune corrupt extent allocation tree blocks - device scanning fixes for dm and multipath - initrd support: move btrfs device scan after block device setup - documentation updates - add csize for file commpressed size - updated restore utility OBS-URL: https://build.opensuse.org/package/show/filesystems/btrfsprogs?expand=0&rev=118
286 lines
7.5 KiB
Diff
286 lines
7.5 KiB
Diff
From 6d1e1b7a4cfd1e0ab93efa42c14759848a26a6d4 Mon Sep 17 00:00:00 2001
|
|
From: Chris Mason <chris.mason@oracle.com>
|
|
Date: Tue, 21 Feb 2012 21:20:54 -0500
|
|
Subject: [PATCH 18/18] 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>
|
|
---
|
|
btrfs-corrupt-block.c | 5 ----
|
|
btrfsck.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++-
|
|
ctree.c | 8 +++++-
|
|
extent-tree.c | 19 ++++++----------
|
|
volumes.c | 12 ----------
|
|
volumes.h | 13 +++++++++++
|
|
6 files changed, 81 insertions(+), 32 deletions(-)
|
|
|
|
diff --git a/btrfs-corrupt-block.c b/btrfs-corrupt-block.c
|
|
index 980a006..7051e99 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 7dc84b5..c1a28bc 100644
|
|
--- 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}
|
|
};
|
|
|
|
@@ -3445,7 +3500,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
|
|
--- 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 ee87f1f..20cdffa 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 e7f4c3e..088f639 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 c34af74..4755176 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;
|
|
@@ -92,6 +93,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)))
|
|
|
|
--
|
|
1.7.6.233.gd79bc
|
|
|