aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorJosef Bacik <jbacik@fusionio.com>2013-04-25 15:55:30 -0400
committerJosef Bacik <jbacik@fusionio.com>2013-05-06 15:55:20 -0400
commitb50c6e250ef91313518dbca96663578237ba8d3c (patch)
tree419d87afe4386be50be15fe5cc0cb0b367eeb1ed /fs/btrfs
parent3d7b5a2882133a04716903b1f4878a64c6610842 (diff)
Btrfs: deal with free space cache errors while replaying log
So everybody who got hit by my fsync bug will still continue to hit this BUG_ON() in the free space cache, which is pretty heavy handed. So I took a file system that had this bug and fixed up all the BUG_ON()'s and leaks that popped up when I tried to mount a broken file system like this. With this patch we just fail to mount instead of panicing. Thanks, Signed-off-by: Josef Bacik <jbacik@fusionio.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/extent-tree.c24
-rw-r--r--fs/btrfs/free-space-cache.c4
-rw-r--r--fs/btrfs/tree-log.c63
3 files changed, 59 insertions, 32 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index ef4ce2c026d6..b0a3fab98713 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -5210,9 +5210,11 @@ int btrfs_pin_extent_for_log_replay(struct btrfs_root *root,
5210 u64 bytenr, u64 num_bytes) 5210 u64 bytenr, u64 num_bytes)
5211{ 5211{
5212 struct btrfs_block_group_cache *cache; 5212 struct btrfs_block_group_cache *cache;
5213 int ret;
5213 5214
5214 cache = btrfs_lookup_block_group(root->fs_info, bytenr); 5215 cache = btrfs_lookup_block_group(root->fs_info, bytenr);
5215 BUG_ON(!cache); /* Logic error */ 5216 if (!cache)
5217 return -EINVAL;
5216 5218
5217 /* 5219 /*
5218 * pull in the free space cache (if any) so that our pin 5220 * pull in the free space cache (if any) so that our pin
@@ -5225,9 +5227,9 @@ int btrfs_pin_extent_for_log_replay(struct btrfs_root *root,
5225 pin_down_extent(root, cache, bytenr, num_bytes, 0); 5227 pin_down_extent(root, cache, bytenr, num_bytes, 0);
5226 5228
5227 /* remove us from the free space cache (if we're there at all) */ 5229 /* remove us from the free space cache (if we're there at all) */
5228 btrfs_remove_free_space(cache, bytenr, num_bytes); 5230 ret = btrfs_remove_free_space(cache, bytenr, num_bytes);
5229 btrfs_put_block_group(cache); 5231 btrfs_put_block_group(cache);
5230 return 0; 5232 return ret;
5231} 5233}
5232 5234
5233/** 5235/**
@@ -6611,40 +6613,42 @@ int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans,
6611 if (!caching_ctl) { 6613 if (!caching_ctl) {
6612 BUG_ON(!block_group_cache_done(block_group)); 6614 BUG_ON(!block_group_cache_done(block_group));
6613 ret = btrfs_remove_free_space(block_group, start, num_bytes); 6615 ret = btrfs_remove_free_space(block_group, start, num_bytes);
6614 BUG_ON(ret); /* -ENOMEM */ 6616 if (ret)
6617 goto out;
6615 } else { 6618 } else {
6616 mutex_lock(&caching_ctl->mutex); 6619 mutex_lock(&caching_ctl->mutex);
6617 6620
6618 if (start >= caching_ctl->progress) { 6621 if (start >= caching_ctl->progress) {
6619 ret = add_excluded_extent(root, start, num_bytes); 6622 ret = add_excluded_extent(root, start, num_bytes);
6620 BUG_ON(ret); /* -ENOMEM */
6621 } else if (start + num_bytes <= caching_ctl->progress) { 6623 } else if (start + num_bytes <= caching_ctl->progress) {
6622 ret = btrfs_remove_free_space(block_group, 6624 ret = btrfs_remove_free_space(block_group,
6623 start, num_bytes); 6625 start, num_bytes);
6624 BUG_ON(ret); /* -ENOMEM */
6625 } else { 6626 } else {
6626 num_bytes = caching_ctl->progress - start; 6627 num_bytes = caching_ctl->progress - start;
6627 ret = btrfs_remove_free_space(block_group, 6628 ret = btrfs_remove_free_space(block_group,
6628 start, num_bytes); 6629 start, num_bytes);
6629 BUG_ON(ret); /* -ENOMEM */ 6630 if (ret)
6631 goto out_lock;
6630 6632
6631 start = caching_ctl->progress; 6633 start = caching_ctl->progress;
6632 num_bytes = ins->objectid + ins->offset - 6634 num_bytes = ins->objectid + ins->offset -
6633 caching_ctl->progress; 6635 caching_ctl->progress;
6634 ret = add_excluded_extent(root, start, num_bytes); 6636 ret = add_excluded_extent(root, start, num_bytes);
6635 BUG_ON(ret); /* -ENOMEM */
6636 } 6637 }
6637 6638out_lock:
6638 mutex_unlock(&caching_ctl->mutex); 6639 mutex_unlock(&caching_ctl->mutex);
6639 put_caching_control(caching_ctl); 6640 put_caching_control(caching_ctl);
6641 if (ret)
6642 goto out;
6640 } 6643 }
6641 6644
6642 ret = btrfs_update_reserved_bytes(block_group, ins->offset, 6645 ret = btrfs_update_reserved_bytes(block_group, ins->offset,
6643 RESERVE_ALLOC_NO_ACCOUNT); 6646 RESERVE_ALLOC_NO_ACCOUNT);
6644 BUG_ON(ret); /* logic error */ 6647 BUG_ON(ret); /* logic error */
6645 btrfs_put_block_group(block_group);
6646 ret = alloc_reserved_file_extent(trans, root, 0, root_objectid, 6648 ret = alloc_reserved_file_extent(trans, root, 0, root_objectid,
6647 0, owner, offset, ins, 1); 6649 0, owner, offset, ins, 1);
6650out:
6651 btrfs_put_block_group(block_group);
6648 return ret; 6652 return ret;
6649} 6653}
6650 6654
diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c
index fa1a8140bfb5..37b2b89a28f6 100644
--- a/fs/btrfs/free-space-cache.c
+++ b/fs/btrfs/free-space-cache.c
@@ -1567,7 +1567,8 @@ again:
1567 search_bytes = ctl->unit; 1567 search_bytes = ctl->unit;
1568 search_bytes = min(search_bytes, end - search_start + 1); 1568 search_bytes = min(search_bytes, end - search_start + 1);
1569 ret = search_bitmap(ctl, bitmap_info, &search_start, &search_bytes); 1569 ret = search_bitmap(ctl, bitmap_info, &search_start, &search_bytes);
1570 BUG_ON(ret < 0 || search_start != *offset); 1570 if (ret < 0 || search_start != *offset)
1571 return -EINVAL;
1571 1572
1572 /* We may have found more bits than what we need */ 1573 /* We may have found more bits than what we need */
1573 search_bytes = min(search_bytes, *bytes); 1574 search_bytes = min(search_bytes, *bytes);
@@ -1973,7 +1974,6 @@ again:
1973 re_search = true; 1974 re_search = true;
1974 goto again; 1975 goto again;
1975 } 1976 }
1976 BUG_ON(ret); /* logic error */
1977out_lock: 1977out_lock:
1978 spin_unlock(&ctl->tree_lock); 1978 spin_unlock(&ctl->tree_lock);
1979out: 1979out:
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index f50137a98fb1..aebfb2d7b7d2 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -277,17 +277,19 @@ static int process_one_buffer(struct btrfs_root *log,
277 struct extent_buffer *eb, 277 struct extent_buffer *eb,
278 struct walk_control *wc, u64 gen) 278 struct walk_control *wc, u64 gen)
279{ 279{
280 int ret = 0;
281
280 if (wc->pin) 282 if (wc->pin)
281 btrfs_pin_extent_for_log_replay(log->fs_info->extent_root, 283 ret = btrfs_pin_extent_for_log_replay(log->fs_info->extent_root,
282 eb->start, eb->len); 284 eb->start, eb->len);
283 285
284 if (btrfs_buffer_uptodate(eb, gen, 0)) { 286 if (!ret && btrfs_buffer_uptodate(eb, gen, 0)) {
285 if (wc->write) 287 if (wc->write)
286 btrfs_write_tree_block(eb); 288 btrfs_write_tree_block(eb);
287 if (wc->wait) 289 if (wc->wait)
288 btrfs_wait_tree_block_writeback(eb); 290 btrfs_wait_tree_block_writeback(eb);
289 } 291 }
290 return 0; 292 return ret;
291} 293}
292 294
293/* 295/*
@@ -623,7 +625,8 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
623 ins.objectid, ins.offset, 625 ins.objectid, ins.offset,
624 0, root->root_key.objectid, 626 0, root->root_key.objectid,
625 key->objectid, offset, 0); 627 key->objectid, offset, 0);
626 BUG_ON(ret); 628 if (ret)
629 goto out;
627 } else { 630 } else {
628 /* 631 /*
629 * insert the extent pointer in the extent 632 * insert the extent pointer in the extent
@@ -632,7 +635,8 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
632 ret = btrfs_alloc_logged_file_extent(trans, 635 ret = btrfs_alloc_logged_file_extent(trans,
633 root, root->root_key.objectid, 636 root, root->root_key.objectid,
634 key->objectid, offset, &ins); 637 key->objectid, offset, &ins);
635 BUG_ON(ret); 638 if (ret)
639 goto out;
636 } 640 }
637 btrfs_release_path(path); 641 btrfs_release_path(path);
638 642
@@ -1952,11 +1956,13 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb,
1952 if (S_ISDIR(mode)) { 1956 if (S_ISDIR(mode)) {
1953 ret = replay_dir_deletes(wc->trans, 1957 ret = replay_dir_deletes(wc->trans,
1954 root, log, path, key.objectid, 0); 1958 root, log, path, key.objectid, 0);
1955 BUG_ON(ret); 1959 if (ret)
1960 break;
1956 } 1961 }
1957 ret = overwrite_item(wc->trans, root, path, 1962 ret = overwrite_item(wc->trans, root, path,
1958 eb, i, &key); 1963 eb, i, &key);
1959 BUG_ON(ret); 1964 if (ret)
1965 break;
1960 1966
1961 /* for regular files, make sure corresponding 1967 /* for regular files, make sure corresponding
1962 * orhpan item exist. extents past the new EOF 1968 * orhpan item exist. extents past the new EOF
@@ -1965,12 +1971,14 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb,
1965 if (S_ISREG(mode)) { 1971 if (S_ISREG(mode)) {
1966 ret = insert_orphan_item(wc->trans, root, 1972 ret = insert_orphan_item(wc->trans, root,
1967 key.objectid); 1973 key.objectid);
1968 BUG_ON(ret); 1974 if (ret)
1975 break;
1969 } 1976 }
1970 1977
1971 ret = link_to_fixup_dir(wc->trans, root, 1978 ret = link_to_fixup_dir(wc->trans, root,
1972 path, key.objectid); 1979 path, key.objectid);
1973 BUG_ON(ret); 1980 if (ret)
1981 break;
1974 } 1982 }
1975 if (wc->stage < LOG_WALK_REPLAY_ALL) 1983 if (wc->stage < LOG_WALK_REPLAY_ALL)
1976 continue; 1984 continue;
@@ -1979,28 +1987,35 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb,
1979 if (key.type == BTRFS_XATTR_ITEM_KEY) { 1987 if (key.type == BTRFS_XATTR_ITEM_KEY) {
1980 ret = overwrite_item(wc->trans, root, path, 1988 ret = overwrite_item(wc->trans, root, path,
1981 eb, i, &key); 1989 eb, i, &key);
1982 BUG_ON(ret); 1990 if (ret)
1991 break;
1983 } else if (key.type == BTRFS_INODE_REF_KEY) { 1992 } else if (key.type == BTRFS_INODE_REF_KEY) {
1984 ret = add_inode_ref(wc->trans, root, log, path, 1993 ret = add_inode_ref(wc->trans, root, log, path,
1985 eb, i, &key); 1994 eb, i, &key);
1986 BUG_ON(ret && ret != -ENOENT); 1995 if (ret && ret != -ENOENT)
1996 break;
1997 ret = 0;
1987 } else if (key.type == BTRFS_INODE_EXTREF_KEY) { 1998 } else if (key.type == BTRFS_INODE_EXTREF_KEY) {
1988 ret = add_inode_ref(wc->trans, root, log, path, 1999 ret = add_inode_ref(wc->trans, root, log, path,
1989 eb, i, &key); 2000 eb, i, &key);
1990 BUG_ON(ret && ret != -ENOENT); 2001 if (ret && ret != -ENOENT)
2002 break;
2003 ret = 0;
1991 } else if (key.type == BTRFS_EXTENT_DATA_KEY) { 2004 } else if (key.type == BTRFS_EXTENT_DATA_KEY) {
1992 ret = replay_one_extent(wc->trans, root, path, 2005 ret = replay_one_extent(wc->trans, root, path,
1993 eb, i, &key); 2006 eb, i, &key);
1994 BUG_ON(ret); 2007 if (ret)
2008 break;
1995 } else if (key.type == BTRFS_DIR_ITEM_KEY || 2009 } else if (key.type == BTRFS_DIR_ITEM_KEY ||
1996 key.type == BTRFS_DIR_INDEX_KEY) { 2010 key.type == BTRFS_DIR_INDEX_KEY) {
1997 ret = replay_one_dir_item(wc->trans, root, path, 2011 ret = replay_one_dir_item(wc->trans, root, path,
1998 eb, i, &key); 2012 eb, i, &key);
1999 BUG_ON(ret); 2013 if (ret)
2014 break;
2000 } 2015 }
2001 } 2016 }
2002 btrfs_free_path(path); 2017 btrfs_free_path(path);
2003 return 0; 2018 return ret;
2004} 2019}
2005 2020
2006static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans, 2021static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans,
@@ -2045,8 +2060,10 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans,
2045 2060
2046 if (*level == 1) { 2061 if (*level == 1) {
2047 ret = wc->process_func(root, next, wc, ptr_gen); 2062 ret = wc->process_func(root, next, wc, ptr_gen);
2048 if (ret) 2063 if (ret) {
2064 free_extent_buffer(next);
2049 return ret; 2065 return ret;
2066 }
2050 2067
2051 path->slots[*level]++; 2068 path->slots[*level]++;
2052 if (wc->free) { 2069 if (wc->free) {
@@ -3970,6 +3987,9 @@ again:
3970 wc.replay_dest = btrfs_read_fs_root_no_name(fs_info, &tmp_key); 3987 wc.replay_dest = btrfs_read_fs_root_no_name(fs_info, &tmp_key);
3971 if (IS_ERR(wc.replay_dest)) { 3988 if (IS_ERR(wc.replay_dest)) {
3972 ret = PTR_ERR(wc.replay_dest); 3989 ret = PTR_ERR(wc.replay_dest);
3990 free_extent_buffer(log->node);
3991 free_extent_buffer(log->commit_root);
3992 kfree(log);
3973 btrfs_error(fs_info, ret, "Couldn't read target root " 3993 btrfs_error(fs_info, ret, "Couldn't read target root "
3974 "for tree log recovery."); 3994 "for tree log recovery.");
3975 goto error; 3995 goto error;
@@ -3978,12 +3998,10 @@ again:
3978 wc.replay_dest->log_root = log; 3998 wc.replay_dest->log_root = log;
3979 btrfs_record_root_in_trans(trans, wc.replay_dest); 3999 btrfs_record_root_in_trans(trans, wc.replay_dest);
3980 ret = walk_log_tree(trans, log, &wc); 4000 ret = walk_log_tree(trans, log, &wc);
3981 BUG_ON(ret);
3982 4001
3983 if (wc.stage == LOG_WALK_REPLAY_ALL) { 4002 if (!ret && wc.stage == LOG_WALK_REPLAY_ALL) {
3984 ret = fixup_inode_link_counts(trans, wc.replay_dest, 4003 ret = fixup_inode_link_counts(trans, wc.replay_dest,
3985 path); 4004 path);
3986 BUG_ON(ret);
3987 } 4005 }
3988 4006
3989 key.offset = found_key.offset - 1; 4007 key.offset = found_key.offset - 1;
@@ -3992,6 +4010,9 @@ again:
3992 free_extent_buffer(log->commit_root); 4010 free_extent_buffer(log->commit_root);
3993 kfree(log); 4011 kfree(log);
3994 4012
4013 if (ret)
4014 goto error;
4015
3995 if (found_key.offset == 0) 4016 if (found_key.offset == 0)
3996 break; 4017 break;
3997 } 4018 }
@@ -4024,6 +4045,8 @@ again:
4024 4045
4025 return 0; 4046 return 0;
4026error: 4047error:
4048 if (wc.trans)
4049 btrfs_end_transaction(wc.trans, fs_info->tree_root);
4027 btrfs_free_path(path); 4050 btrfs_free_path(path);
4028 return ret; 4051 return ret;
4029} 4052}