diff options
Diffstat (limited to 'fs/btrfs/ctree.c')
-rw-r--r-- | fs/btrfs/ctree.c | 69 |
1 files changed, 48 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 | */ |
1871 | static noinline struct extent_buffer *read_node_slot(struct btrfs_root *root, | 1870 | static 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 | ||
5240 | static void tree_move_down(struct btrfs_root *root, | 5258 | static 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 | ||
5251 | static int tree_move_next_or_upnext(struct btrfs_root *root, | 5275 | static 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 | ||