aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosef Bacik <jbacik@fusionio.com>2013-04-23 14:17:42 -0400
committerJosef Bacik <jbacik@fusionio.com>2013-05-06 15:55:07 -0400
commit416bc6580bb01ddf67befaaeb94f087b392e7f47 (patch)
tree28a781ba1559a3021cb2aea8bbeebcfb20653115
parent51bf5f0bc4d132a3646ce36061e83fdc8b77f302 (diff)
Btrfs: fix all callers of read_tree_block
We kept leaking extent buffers when mounting a broken file system and it turns out it's because not everybody uses read_tree_block properly. You need to check and make sure the extent_buffer is uptodate before you use it. This patch fixes everybody who calls read_tree_block directly to make sure they check that it is uptodate and free it and return an error if it is not. With this we no longer leak EB's when things go horribly wrong. Thanks, Signed-off-by: Josef Bacik <jbacik@fusionio.com>
-rw-r--r--fs/btrfs/backref.c10
-rw-r--r--fs/btrfs/ctree.c21
-rw-r--r--fs/btrfs/disk-io.c19
-rw-r--r--fs/btrfs/extent-tree.c4
-rw-r--r--fs/btrfs/relocation.c18
5 files changed, 59 insertions, 13 deletions
diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c
index 23e927b191c9..04b5b3093893 100644
--- a/fs/btrfs/backref.c
+++ b/fs/btrfs/backref.c
@@ -423,7 +423,10 @@ static int __add_missing_keys(struct btrfs_fs_info *fs_info,
423 BUG_ON(!ref->wanted_disk_byte); 423 BUG_ON(!ref->wanted_disk_byte);
424 eb = read_tree_block(fs_info->tree_root, ref->wanted_disk_byte, 424 eb = read_tree_block(fs_info->tree_root, ref->wanted_disk_byte,
425 fs_info->tree_root->leafsize, 0); 425 fs_info->tree_root->leafsize, 0);
426 BUG_ON(!eb); 426 if (!eb || !extent_buffer_uptodate(eb)) {
427 free_extent_buffer(eb);
428 return -EIO;
429 }
427 btrfs_tree_read_lock(eb); 430 btrfs_tree_read_lock(eb);
428 if (btrfs_header_level(eb) == 0) 431 if (btrfs_header_level(eb) == 0)
429 btrfs_item_key_to_cpu(eb, &ref->key_for_search, 0); 432 btrfs_item_key_to_cpu(eb, &ref->key_for_search, 0);
@@ -913,7 +916,10 @@ again:
913 info_level); 916 info_level);
914 eb = read_tree_block(fs_info->extent_root, 917 eb = read_tree_block(fs_info->extent_root,
915 ref->parent, bsz, 0); 918 ref->parent, bsz, 0);
916 BUG_ON(!eb); 919 if (!eb || !extent_buffer_uptodate(eb)) {
920 free_extent_buffer(eb);
921 return -EIO;
922 }
917 ret = find_extent_in_eb(eb, bytenr, 923 ret = find_extent_in_eb(eb, bytenr,
918 *extent_item_pos, &eie); 924 *extent_item_pos, &eie);
919 ref->inode_list = eie; 925 ref->inode_list = eie;
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 566d99b51bef..2bc34408872d 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -1281,7 +1281,8 @@ get_old_root(struct btrfs_root *root, u64 time_seq)
1281 free_extent_buffer(eb_root); 1281 free_extent_buffer(eb_root);
1282 blocksize = btrfs_level_size(root, old_root->level); 1282 blocksize = btrfs_level_size(root, old_root->level);
1283 old = read_tree_block(root, logical, blocksize, 0); 1283 old = read_tree_block(root, logical, blocksize, 0);
1284 if (!old) { 1284 if (!old || !extent_buffer_uptodate(old)) {
1285 free_extent_buffer(old);
1285 pr_warn("btrfs: failed to read tree block %llu from get_old_root\n", 1286 pr_warn("btrfs: failed to read tree block %llu from get_old_root\n",
1286 logical); 1287 logical);
1287 WARN_ON(1); 1288 WARN_ON(1);
@@ -1526,8 +1527,10 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
1526 if (!cur) { 1527 if (!cur) {
1527 cur = read_tree_block(root, blocknr, 1528 cur = read_tree_block(root, blocknr,
1528 blocksize, gen); 1529 blocksize, gen);
1529 if (!cur) 1530 if (!cur || !extent_buffer_uptodate(cur)) {
1531 free_extent_buffer(cur);
1530 return -EIO; 1532 return -EIO;
1533 }
1531 } else if (!uptodate) { 1534 } else if (!uptodate) {
1532 err = btrfs_read_buffer(cur, gen); 1535 err = btrfs_read_buffer(cur, gen);
1533 if (err) { 1536 if (err) {
@@ -1692,6 +1695,8 @@ static noinline struct extent_buffer *read_node_slot(struct btrfs_root *root,
1692 struct extent_buffer *parent, int slot) 1695 struct extent_buffer *parent, int slot)
1693{ 1696{
1694 int level = btrfs_header_level(parent); 1697 int level = btrfs_header_level(parent);
1698 struct extent_buffer *eb;
1699
1695 if (slot < 0) 1700 if (slot < 0)
1696 return NULL; 1701 return NULL;
1697 if (slot >= btrfs_header_nritems(parent)) 1702 if (slot >= btrfs_header_nritems(parent))
@@ -1699,9 +1704,15 @@ static noinline struct extent_buffer *read_node_slot(struct btrfs_root *root,
1699 1704
1700 BUG_ON(level == 0); 1705 BUG_ON(level == 0);
1701 1706
1702 return read_tree_block(root, btrfs_node_blockptr(parent, slot), 1707 eb = read_tree_block(root, btrfs_node_blockptr(parent, slot),
1703 btrfs_level_size(root, level - 1), 1708 btrfs_level_size(root, level - 1),
1704 btrfs_node_ptr_generation(parent, slot)); 1709 btrfs_node_ptr_generation(parent, slot));
1710 if (eb && !extent_buffer_uptodate(eb)) {
1711 free_extent_buffer(eb);
1712 eb = NULL;
1713 }
1714
1715 return eb;
1705} 1716}
1706 1717
1707/* 1718/*
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index c7d8fb0dbff6..deb6e3d07281 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -1496,6 +1496,14 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root,
1496 blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item)); 1496 blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item));
1497 root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item), 1497 root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item),
1498 blocksize, generation); 1498 blocksize, generation);
1499 if (!root->node || !extent_buffer_uptodate(root->node)) {
1500 ret = (!root->node) ? -ENOMEM : -EIO;
1501
1502 free_extent_buffer(root->node);
1503 kfree(root);
1504 return ERR_PTR(ret);
1505 }
1506
1499 root->commit_root = btrfs_root_node(root); 1507 root->commit_root = btrfs_root_node(root);
1500 BUG_ON(!root->node); /* -ENOMEM */ 1508 BUG_ON(!root->node); /* -ENOMEM */
1501out: 1509out:
@@ -2515,8 +2523,8 @@ int open_ctree(struct super_block *sb,
2515 chunk_root->node = read_tree_block(chunk_root, 2523 chunk_root->node = read_tree_block(chunk_root,
2516 btrfs_super_chunk_root(disk_super), 2524 btrfs_super_chunk_root(disk_super),
2517 blocksize, generation); 2525 blocksize, generation);
2518 BUG_ON(!chunk_root->node); /* -ENOMEM */ 2526 if (!chunk_root->node ||
2519 if (!test_bit(EXTENT_BUFFER_UPTODATE, &chunk_root->node->bflags)) { 2527 !test_bit(EXTENT_BUFFER_UPTODATE, &chunk_root->node->bflags)) {
2520 printk(KERN_WARNING "btrfs: failed to read chunk root on %s\n", 2528 printk(KERN_WARNING "btrfs: failed to read chunk root on %s\n",
2521 sb->s_id); 2529 sb->s_id);
2522 goto fail_tree_roots; 2530 goto fail_tree_roots;
@@ -2701,6 +2709,13 @@ retry_root_backup:
2701 log_tree_root->node = read_tree_block(tree_root, bytenr, 2709 log_tree_root->node = read_tree_block(tree_root, bytenr,
2702 blocksize, 2710 blocksize,
2703 generation + 1); 2711 generation + 1);
2712 if (!log_tree_root->node ||
2713 !extent_buffer_uptodate(log_tree_root->node)) {
2714 printk(KERN_ERR "btrfs: failed to read log tree\n");
2715 free_extent_buffer(log_tree_root->node);
2716 kfree(log_tree_root);
2717 goto fail_trans_kthread;
2718 }
2704 /* returns with log_tree_root freed on success */ 2719 /* returns with log_tree_root freed on success */
2705 ret = btrfs_recover_log_trees(log_tree_root); 2720 ret = btrfs_recover_log_trees(log_tree_root);
2706 if (ret) { 2721 if (ret) {
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 94bed61b799f..6526f1faf6c2 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -7087,8 +7087,10 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
7087 if (reada && level == 1) 7087 if (reada && level == 1)
7088 reada_walk_down(trans, root, wc, path); 7088 reada_walk_down(trans, root, wc, path);
7089 next = read_tree_block(root, bytenr, blocksize, generation); 7089 next = read_tree_block(root, bytenr, blocksize, generation);
7090 if (!next) 7090 if (!next || !extent_buffer_uptodate(next)) {
7091 free_extent_buffer(next);
7091 return -EIO; 7092 return -EIO;
7093 }
7092 btrfs_tree_lock(next); 7094 btrfs_tree_lock(next);
7093 btrfs_set_lock_blocking(next); 7095 btrfs_set_lock_blocking(next);
7094 } 7096 }
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
index 208154986c4c..63cdd9246c70 100644
--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -1771,7 +1771,11 @@ again:
1771 1771
1772 eb = read_tree_block(dest, old_bytenr, blocksize, 1772 eb = read_tree_block(dest, old_bytenr, blocksize,
1773 old_ptr_gen); 1773 old_ptr_gen);
1774 BUG_ON(!eb); 1774 if (!eb || !extent_buffer_uptodate(eb)) {
1775 ret = (!eb) ? -ENOMEM : -EIO;
1776 free_extent_buffer(eb);
1777 return ret;
1778 }
1775 btrfs_tree_lock(eb); 1779 btrfs_tree_lock(eb);
1776 if (cow) { 1780 if (cow) {
1777 ret = btrfs_cow_block(trans, dest, eb, parent, 1781 ret = btrfs_cow_block(trans, dest, eb, parent,
@@ -1924,6 +1928,10 @@ int walk_down_reloc_tree(struct btrfs_root *root, struct btrfs_path *path,
1924 bytenr = btrfs_node_blockptr(eb, path->slots[i]); 1928 bytenr = btrfs_node_blockptr(eb, path->slots[i]);
1925 blocksize = btrfs_level_size(root, i - 1); 1929 blocksize = btrfs_level_size(root, i - 1);
1926 eb = read_tree_block(root, bytenr, blocksize, ptr_gen); 1930 eb = read_tree_block(root, bytenr, blocksize, ptr_gen);
1931 if (!eb || !extent_buffer_uptodate(eb)) {
1932 free_extent_buffer(eb);
1933 return -EIO;
1934 }
1927 BUG_ON(btrfs_header_level(eb) != i - 1); 1935 BUG_ON(btrfs_header_level(eb) != i - 1);
1928 path->nodes[i - 1] = eb; 1936 path->nodes[i - 1] = eb;
1929 path->slots[i - 1] = 0; 1937 path->slots[i - 1] = 0;
@@ -2601,7 +2609,8 @@ static int do_relocation(struct btrfs_trans_handle *trans,
2601 blocksize = btrfs_level_size(root, node->level); 2609 blocksize = btrfs_level_size(root, node->level);
2602 generation = btrfs_node_ptr_generation(upper->eb, slot); 2610 generation = btrfs_node_ptr_generation(upper->eb, slot);
2603 eb = read_tree_block(root, bytenr, blocksize, generation); 2611 eb = read_tree_block(root, bytenr, blocksize, generation);
2604 if (!eb) { 2612 if (!eb || !extent_buffer_uptodate(eb)) {
2613 free_extent_buffer(eb);
2605 err = -EIO; 2614 err = -EIO;
2606 goto next; 2615 goto next;
2607 } 2616 }
@@ -2762,7 +2771,10 @@ static int get_tree_block_key(struct reloc_control *rc,
2762 BUG_ON(block->key_ready); 2771 BUG_ON(block->key_ready);
2763 eb = read_tree_block(rc->extent_root, block->bytenr, 2772 eb = read_tree_block(rc->extent_root, block->bytenr,
2764 block->key.objectid, block->key.offset); 2773 block->key.objectid, block->key.offset);
2765 BUG_ON(!eb); 2774 if (!eb || !extent_buffer_uptodate(eb)) {
2775 free_extent_buffer(eb);
2776 return -EIO;
2777 }
2766 WARN_ON(btrfs_header_level(eb) != block->level); 2778 WARN_ON(btrfs_header_level(eb) != block->level);
2767 if (block->level == 0) 2779 if (block->level == 0)
2768 btrfs_item_key_to_cpu(eb, &block->key, 0); 2780 btrfs_item_key_to_cpu(eb, &block->key, 0);