summaryrefslogtreecommitdiff
path: root/disk-io.c
diff options
context:
space:
mode:
authorJosef Bacik <jbacik@fusionio.com>2013-10-01 09:00:19 -0400
committerChris Mason <chris.mason@fusionio.com>2013-10-16 08:23:12 -0400
commitc64485544baa9ffc5fbedd5661a05bdee1b37598 (patch)
tree4461ef770a41b3056a0f0763d308d4f6a53e07b6 /disk-io.c
parent2454473dd1647e83d6eba9852eeb08d331e9ea9a (diff)
Btrfs-progs: keep track of transid failures and fix them if possible
A user was reporting an issue with bad transid errors on his blocks. The thing is that btrfs-progs will ignore transid failures for things like restore and fsck so we can do a best effort to fix a users file system. So fsck can put together a coherent view of the file system with stale blocks. So if everything else is ok in the mind of fsck then we can recow these blocks to fix the generation and the user can get their file system back. Thanks, Signed-off-by: Josef Bacik <jbacik@fusionio.com> Signed-off-by: David Sterba <dsterba@suse.cz> Signed-off-by: Chris Mason <chris.mason@fusionio.com>
Diffstat (limited to 'disk-io.c')
-rw-r--r--disk-io.c15
1 files changed, 15 insertions, 0 deletions
diff --git a/disk-io.c b/disk-io.c
index 5f3f4847..b06eb035 100644
--- a/disk-io.c
+++ b/disk-io.c
@@ -180,6 +180,7 @@ static int verify_parent_transid(struct extent_io_tree *io_tree,
(unsigned long long)parent_transid,
(unsigned long long)btrfs_header_generation(eb));
if (ignore) {
+ eb->flags |= EXTENT_BAD_TRANSID;
printk("Ignoring transid failure\n");
return 0;
}
@@ -274,6 +275,12 @@ struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr,
csum_tree_block(root, eb, 1) == 0 &&
verify_parent_transid(eb->tree, eb, parent_transid, ignore)
== 0) {
+ if (eb->flags & EXTENT_BAD_TRANSID &&
+ list_empty(&eb->recow)) {
+ list_add_tail(&eb->recow,
+ &root->fs_info->recow_ebs);
+ eb->refs++;
+ }
btrfs_set_buffer_uptodate(eb);
return eb;
}
@@ -749,6 +756,7 @@ struct btrfs_fs_info *btrfs_new_fs_info(int writable, u64 sb_bytenr)
mutex_init(&fs_info->fs_mutex);
INIT_LIST_HEAD(&fs_info->dirty_cowonly_roots);
INIT_LIST_HEAD(&fs_info->space_info);
+ INIT_LIST_HEAD(&fs_info->recow_ebs);
if (!writable)
fs_info->readonly = 1;
@@ -900,6 +908,13 @@ FREE_EXTENT_CACHE_BASED_TREE(mapping_cache, free_map_lookup);
void btrfs_cleanup_all_caches(struct btrfs_fs_info *fs_info)
{
+ while (!list_empty(&fs_info->recow_ebs)) {
+ struct extent_buffer *eb;
+ eb = list_first_entry(&fs_info->recow_ebs,
+ struct extent_buffer, recow);
+ list_del_init(&eb->recow);
+ free_extent_buffer(eb);
+ }
free_mapping_cache_tree(&fs_info->mapping_tree.cache_tree);
extent_io_tree_cleanup(&fs_info->extent_cache);
extent_io_tree_cleanup(&fs_info->free_space_cache);