aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorLiu Bo <bo.li.liu@oracle.com>2016-07-05 15:10:14 -0400
committerDavid Sterba <dsterba@suse.com>2016-07-26 07:52:25 -0400
commitfb770ae414d018255afa7a70b14ba1f8620762dd (patch)
treece23654b16f7de208bb88096b2c0f9208c4a5eca /fs/btrfs
parent876d2cf141b42f9be70a383502a324b64b23f33a (diff)
Btrfs: fix read_node_slot to return errors
We use read_node_slot() to read btree node and it has two cases, a) slot is out of range, which means 'no such entry' b) we fail to read the block, due to checksum fails or corrupted content or not with uptodate flag. But we're returning NULL in both cases, this makes it return -ENOENT in case a) and return -EIO in case b), and this fixes its callers as well as btrfs_search_forward() 's caller to catch the new errors. The problem is reported by Peter Becker, and I can manage to hit the same BUG_ON by mounting my fuzz image. Reported-by: Peter Becker <floyd.net@gmail.com> Signed-off-by: Liu Bo <bo.li.liu@oracle.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/ctree.c69
-rw-r--r--fs/btrfs/tree-log.c4
2 files changed, 52 insertions, 21 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 362879da4f0d..0abed1a0caa7 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -1866,7 +1866,6 @@ static void root_sub_used(struct btrfs_root *root, u32 size)
1866 1866
1867/* given a node and slot number, this reads the blocks it points to. The 1867/* given a node and slot number, this reads the blocks it points to. The
1868 * extent buffer is returned with a reference taken (but unlocked). 1868 * extent buffer is returned with a reference taken (but unlocked).
1869 * NULL is returned on error.
1870 */ 1869 */
1871static noinline struct extent_buffer *read_node_slot(struct btrfs_root *root, 1870static noinline struct extent_buffer *read_node_slot(struct btrfs_root *root,
1872 struct extent_buffer *parent, int slot) 1871 struct extent_buffer *parent, int slot)
@@ -1874,19 +1873,16 @@ static noinline struct extent_buffer *read_node_slot(struct btrfs_root *root,
1874 int level = btrfs_header_level(parent); 1873 int level = btrfs_header_level(parent);
1875 struct extent_buffer *eb; 1874 struct extent_buffer *eb;
1876 1875
1877 if (slot < 0) 1876 if (slot < 0 || slot >= btrfs_header_nritems(parent))
1878 return NULL; 1877 return ERR_PTR(-ENOENT);
1879 if (slot >= btrfs_header_nritems(parent))
1880 return NULL;
1881 1878
1882 BUG_ON(level == 0); 1879 BUG_ON(level == 0);
1883 1880
1884 eb = read_tree_block(root, btrfs_node_blockptr(parent, slot), 1881 eb = read_tree_block(root, btrfs_node_blockptr(parent, slot),
1885 btrfs_node_ptr_generation(parent, slot)); 1882 btrfs_node_ptr_generation(parent, slot));
1886 if (IS_ERR(eb) || !extent_buffer_uptodate(eb)) { 1883 if (!IS_ERR(eb) && !extent_buffer_uptodate(eb)) {
1887 if (!IS_ERR(eb)) 1884 free_extent_buffer(eb);
1888 free_extent_buffer(eb); 1885 eb = ERR_PTR(-EIO);
1889 eb = NULL;
1890 } 1886 }
1891 1887
1892 return eb; 1888 return eb;
@@ -1939,8 +1935,8 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
1939 1935
1940 /* promote the child to a root */ 1936 /* promote the child to a root */
1941 child = read_node_slot(root, mid, 0); 1937 child = read_node_slot(root, mid, 0);
1942 if (!child) { 1938 if (IS_ERR(child)) {
1943 ret = -EROFS; 1939 ret = PTR_ERR(child);
1944 btrfs_handle_fs_error(root->fs_info, ret, NULL); 1940 btrfs_handle_fs_error(root->fs_info, ret, NULL);
1945 goto enospc; 1941 goto enospc;
1946 } 1942 }
@@ -1978,6 +1974,9 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
1978 return 0; 1974 return 0;
1979 1975
1980 left = read_node_slot(root, parent, pslot - 1); 1976 left = read_node_slot(root, parent, pslot - 1);
1977 if (IS_ERR(left))
1978 left = NULL;
1979
1981 if (left) { 1980 if (left) {
1982 btrfs_tree_lock(left); 1981 btrfs_tree_lock(left);
1983 btrfs_set_lock_blocking(left); 1982 btrfs_set_lock_blocking(left);
@@ -1988,7 +1987,11 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
1988 goto enospc; 1987 goto enospc;
1989 } 1988 }
1990 } 1989 }
1990
1991 right = read_node_slot(root, parent, pslot + 1); 1991 right = read_node_slot(root, parent, pslot + 1);
1992 if (IS_ERR(right))
1993 right = NULL;
1994
1992 if (right) { 1995 if (right) {
1993 btrfs_tree_lock(right); 1996 btrfs_tree_lock(right);
1994 btrfs_set_lock_blocking(right); 1997 btrfs_set_lock_blocking(right);
@@ -2143,6 +2146,8 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans,
2143 return 1; 2146 return 1;
2144 2147
2145 left = read_node_slot(root, parent, pslot - 1); 2148 left = read_node_slot(root, parent, pslot - 1);
2149 if (IS_ERR(left))
2150 left = NULL;
2146 2151
2147 /* first, try to make some room in the middle buffer */ 2152 /* first, try to make some room in the middle buffer */
2148 if (left) { 2153 if (left) {
@@ -2193,6 +2198,8 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans,
2193 free_extent_buffer(left); 2198 free_extent_buffer(left);
2194 } 2199 }
2195 right = read_node_slot(root, parent, pslot + 1); 2200 right = read_node_slot(root, parent, pslot + 1);
2201 if (IS_ERR(right))
2202 right = NULL;
2196 2203
2197 /* 2204 /*
2198 * then try to empty the right most buffer into the middle 2205 * then try to empty the right most buffer into the middle
@@ -3781,7 +3788,11 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
3781 btrfs_assert_tree_locked(path->nodes[1]); 3788 btrfs_assert_tree_locked(path->nodes[1]);
3782 3789
3783 right = read_node_slot(root, upper, slot + 1); 3790 right = read_node_slot(root, upper, slot + 1);
3784 if (right == NULL) 3791 /*
3792 * slot + 1 is not valid or we fail to read the right node,
3793 * no big deal, just return.
3794 */
3795 if (IS_ERR(right))
3785 return 1; 3796 return 1;
3786 3797
3787 btrfs_tree_lock(right); 3798 btrfs_tree_lock(right);
@@ -4011,7 +4022,11 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
4011 btrfs_assert_tree_locked(path->nodes[1]); 4022 btrfs_assert_tree_locked(path->nodes[1]);
4012 4023
4013 left = read_node_slot(root, path->nodes[1], slot - 1); 4024 left = read_node_slot(root, path->nodes[1], slot - 1);
4014 if (left == NULL) 4025 /*
4026 * slot - 1 is not valid or we fail to read the left node,
4027 * no big deal, just return.
4028 */
4029 if (IS_ERR(left))
4015 return 1; 4030 return 1;
4016 4031
4017 btrfs_tree_lock(left); 4032 btrfs_tree_lock(left);
@@ -5218,7 +5233,10 @@ find_next_key:
5218 } 5233 }
5219 btrfs_set_path_blocking(path); 5234 btrfs_set_path_blocking(path);
5220 cur = read_node_slot(root, cur, slot); 5235 cur = read_node_slot(root, cur, slot);
5221 BUG_ON(!cur); /* -ENOMEM */ 5236 if (IS_ERR(cur)) {
5237 ret = PTR_ERR(cur);
5238 goto out;
5239 }
5222 5240
5223 btrfs_tree_read_lock(cur); 5241 btrfs_tree_read_lock(cur);
5224 5242
@@ -5237,15 +5255,21 @@ out:
5237 return ret; 5255 return ret;
5238} 5256}
5239 5257
5240static void tree_move_down(struct btrfs_root *root, 5258static int tree_move_down(struct btrfs_root *root,
5241 struct btrfs_path *path, 5259 struct btrfs_path *path,
5242 int *level, int root_level) 5260 int *level, int root_level)
5243{ 5261{
5262 struct extent_buffer *eb;
5263
5244 BUG_ON(*level == 0); 5264 BUG_ON(*level == 0);
5245 path->nodes[*level - 1] = read_node_slot(root, path->nodes[*level], 5265 eb = read_node_slot(root, path->nodes[*level], path->slots[*level]);
5246 path->slots[*level]); 5266 if (IS_ERR(eb))
5267 return PTR_ERR(eb);
5268
5269 path->nodes[*level - 1] = eb;
5247 path->slots[*level - 1] = 0; 5270 path->slots[*level - 1] = 0;
5248 (*level)--; 5271 (*level)--;
5272 return 0;
5249} 5273}
5250 5274
5251static int tree_move_next_or_upnext(struct btrfs_root *root, 5275static int tree_move_next_or_upnext(struct btrfs_root *root,
@@ -5290,8 +5314,7 @@ static int tree_advance(struct btrfs_root *root,
5290 if (*level == 0 || !allow_down) { 5314 if (*level == 0 || !allow_down) {
5291 ret = tree_move_next_or_upnext(root, path, level, root_level); 5315 ret = tree_move_next_or_upnext(root, path, level, root_level);
5292 } else { 5316 } else {
5293 tree_move_down(root, path, level, root_level); 5317 ret = tree_move_down(root, path, level, root_level);
5294 ret = 0;
5295 } 5318 }
5296 if (ret >= 0) { 5319 if (ret >= 0) {
5297 if (*level == 0) 5320 if (*level == 0)
@@ -5465,8 +5488,10 @@ int btrfs_compare_trees(struct btrfs_root *left_root,
5465 left_root_level, 5488 left_root_level,
5466 advance_left != ADVANCE_ONLY_NEXT, 5489 advance_left != ADVANCE_ONLY_NEXT,
5467 &left_key); 5490 &left_key);
5468 if (ret < 0) 5491 if (ret == -1)
5469 left_end_reached = ADVANCE; 5492 left_end_reached = ADVANCE;
5493 else if (ret < 0)
5494 goto out;
5470 advance_left = 0; 5495 advance_left = 0;
5471 } 5496 }
5472 if (advance_right && !right_end_reached) { 5497 if (advance_right && !right_end_reached) {
@@ -5474,8 +5499,10 @@ int btrfs_compare_trees(struct btrfs_root *left_root,
5474 right_root_level, 5499 right_root_level,
5475 advance_right != ADVANCE_ONLY_NEXT, 5500 advance_right != ADVANCE_ONLY_NEXT,
5476 &right_key); 5501 &right_key);
5477 if (ret < 0) 5502 if (ret == -1)
5478 right_end_reached = ADVANCE; 5503 right_end_reached = ADVANCE;
5504 else if (ret < 0)
5505 goto out;
5479 advance_right = 0; 5506 advance_right = 0;
5480 } 5507 }
5481 5508
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index c05f69a8ec42..aa4475e3046b 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -4703,6 +4703,10 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
4703 ins_nr = 0; 4703 ins_nr = 0;
4704 ret = btrfs_search_forward(root, &min_key, 4704 ret = btrfs_search_forward(root, &min_key,
4705 path, trans->transid); 4705 path, trans->transid);
4706 if (ret < 0) {
4707 err = ret;
4708 goto out_unlock;
4709 }
4706 if (ret != 0) 4710 if (ret != 0)
4707 break; 4711 break;
4708again: 4712again: