aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/disk-io.c
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 /fs/btrfs/disk-io.c
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>
Diffstat (limited to 'fs/btrfs/disk-io.c')
-rw-r--r--fs/btrfs/disk-io.c19
1 files changed, 17 insertions, 2 deletions
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) {