Commit 83d4cfd4 authored by Josef Bacik's avatar Josef Bacik Committed by Chris Mason

Btrfs: fixup error handling in btrfs_reloc_cow

If we failed to actually allocate the correct size of the extent to relocate we
will end up in an infinite loop because we won't return an error, we'll just
move on to the next extent.  So fix this up by returning an error, and then fix
all the callers to return an error up the stack rather than BUG_ON()'ing.
Thanks,
Signed-off-by: default avatarJosef Bacik <jbacik@fusionio.com>
Signed-off-by: default avatarChris Mason <chris.mason@fusionio.com>
parent 07f0e62e
...@@ -1005,8 +1005,11 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans, ...@@ -1005,8 +1005,11 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
return ret; return ret;
} }
if (root->ref_cows) if (root->ref_cows) {
btrfs_reloc_cow_block(trans, root, buf, cow); ret = btrfs_reloc_cow_block(trans, root, buf, cow);
if (ret)
return ret;
}
if (buf == root->node) { if (buf == root->node) {
WARN_ON(parent && parent != buf); WARN_ON(parent && parent != buf);
......
...@@ -3939,9 +3939,9 @@ int btrfs_update_reloc_root(struct btrfs_trans_handle *trans, ...@@ -3939,9 +3939,9 @@ int btrfs_update_reloc_root(struct btrfs_trans_handle *trans,
struct btrfs_root *root); struct btrfs_root *root);
int btrfs_recover_relocation(struct btrfs_root *root); int btrfs_recover_relocation(struct btrfs_root *root);
int btrfs_reloc_clone_csums(struct inode *inode, u64 file_pos, u64 len); int btrfs_reloc_clone_csums(struct inode *inode, u64 file_pos, u64 len);
void btrfs_reloc_cow_block(struct btrfs_trans_handle *trans, int btrfs_reloc_cow_block(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct extent_buffer *buf, struct btrfs_root *root, struct extent_buffer *buf,
struct extent_buffer *cow); struct extent_buffer *cow);
void btrfs_reloc_pre_snapshot(struct btrfs_trans_handle *trans, void btrfs_reloc_pre_snapshot(struct btrfs_trans_handle *trans,
struct btrfs_pending_snapshot *pending, struct btrfs_pending_snapshot *pending,
u64 *bytes_to_reserve); u64 *bytes_to_reserve);
......
...@@ -1548,7 +1548,7 @@ static int get_new_location(struct inode *reloc_inode, u64 *new_bytenr, ...@@ -1548,7 +1548,7 @@ static int get_new_location(struct inode *reloc_inode, u64 *new_bytenr,
btrfs_file_extent_other_encoding(leaf, fi)); btrfs_file_extent_other_encoding(leaf, fi));
if (num_bytes != btrfs_file_extent_disk_num_bytes(leaf, fi)) { if (num_bytes != btrfs_file_extent_disk_num_bytes(leaf, fi)) {
ret = 1; ret = -EINVAL;
goto out; goto out;
} }
...@@ -1579,7 +1579,7 @@ int replace_file_extents(struct btrfs_trans_handle *trans, ...@@ -1579,7 +1579,7 @@ int replace_file_extents(struct btrfs_trans_handle *trans,
u64 end; u64 end;
u32 nritems; u32 nritems;
u32 i; u32 i;
int ret; int ret = 0;
int first = 1; int first = 1;
int dirty = 0; int dirty = 0;
...@@ -1642,11 +1642,13 @@ int replace_file_extents(struct btrfs_trans_handle *trans, ...@@ -1642,11 +1642,13 @@ int replace_file_extents(struct btrfs_trans_handle *trans,
ret = get_new_location(rc->data_inode, &new_bytenr, ret = get_new_location(rc->data_inode, &new_bytenr,
bytenr, num_bytes); bytenr, num_bytes);
if (ret > 0) { if (ret) {
WARN_ON(1); /*
continue; * Don't have to abort since we've not changed anything
* in the file extent yet.
*/
break;
} }
BUG_ON(ret < 0);
btrfs_set_file_extent_disk_bytenr(leaf, fi, new_bytenr); btrfs_set_file_extent_disk_bytenr(leaf, fi, new_bytenr);
dirty = 1; dirty = 1;
...@@ -1656,18 +1658,24 @@ int replace_file_extents(struct btrfs_trans_handle *trans, ...@@ -1656,18 +1658,24 @@ int replace_file_extents(struct btrfs_trans_handle *trans,
num_bytes, parent, num_bytes, parent,
btrfs_header_owner(leaf), btrfs_header_owner(leaf),
key.objectid, key.offset, 1); key.objectid, key.offset, 1);
BUG_ON(ret); if (ret) {
btrfs_abort_transaction(trans, root, ret);
break;
}
ret = btrfs_free_extent(trans, root, bytenr, num_bytes, ret = btrfs_free_extent(trans, root, bytenr, num_bytes,
parent, btrfs_header_owner(leaf), parent, btrfs_header_owner(leaf),
key.objectid, key.offset, 1); key.objectid, key.offset, 1);
BUG_ON(ret); if (ret) {
btrfs_abort_transaction(trans, root, ret);
break;
}
} }
if (dirty) if (dirty)
btrfs_mark_buffer_dirty(leaf); btrfs_mark_buffer_dirty(leaf);
if (inode) if (inode)
btrfs_add_delayed_iput(inode); btrfs_add_delayed_iput(inode);
return 0; return ret;
} }
static noinline_for_stack static noinline_for_stack
...@@ -4499,19 +4507,19 @@ int btrfs_reloc_clone_csums(struct inode *inode, u64 file_pos, u64 len) ...@@ -4499,19 +4507,19 @@ int btrfs_reloc_clone_csums(struct inode *inode, u64 file_pos, u64 len)
return ret; return ret;
} }
void btrfs_reloc_cow_block(struct btrfs_trans_handle *trans, int btrfs_reloc_cow_block(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct extent_buffer *buf, struct btrfs_root *root, struct extent_buffer *buf,
struct extent_buffer *cow) struct extent_buffer *cow)
{ {
struct reloc_control *rc; struct reloc_control *rc;
struct backref_node *node; struct backref_node *node;
int first_cow = 0; int first_cow = 0;
int level; int level;
int ret; int ret = 0;
rc = root->fs_info->reloc_ctl; rc = root->fs_info->reloc_ctl;
if (!rc) if (!rc)
return; return 0;
BUG_ON(rc->stage == UPDATE_DATA_PTRS && BUG_ON(rc->stage == UPDATE_DATA_PTRS &&
root->root_key.objectid == BTRFS_DATA_RELOC_TREE_OBJECTID); root->root_key.objectid == BTRFS_DATA_RELOC_TREE_OBJECTID);
...@@ -4547,10 +4555,9 @@ void btrfs_reloc_cow_block(struct btrfs_trans_handle *trans, ...@@ -4547,10 +4555,9 @@ void btrfs_reloc_cow_block(struct btrfs_trans_handle *trans,
rc->nodes_relocated += buf->len; rc->nodes_relocated += buf->len;
} }
if (level == 0 && first_cow && rc->stage == UPDATE_DATA_PTRS) { if (level == 0 && first_cow && rc->stage == UPDATE_DATA_PTRS)
ret = replace_file_extents(trans, rc, root, cow); ret = replace_file_extents(trans, rc, root, cow);
BUG_ON(ret); return ret;
}
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment