Commit 098f59c2 authored by Chris Mason's avatar Chris Mason Committed by David Woodhouse

Btrfs: patch queue: fix corruption when splitting large items

Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent 509659cd
...@@ -871,6 +871,7 @@ static int insert_ptr(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -871,6 +871,7 @@ static int insert_ptr(struct btrfs_trans_handle *trans, struct btrfs_root
btrfs_set_node_blockptr(lower, slot, blocknr); btrfs_set_node_blockptr(lower, slot, blocknr);
btrfs_set_header_nritems(&lower->header, nritems + 1); btrfs_set_header_nritems(&lower->header, nritems + 1);
btrfs_mark_buffer_dirty(path->nodes[level]); btrfs_mark_buffer_dirty(path->nodes[level]);
check_node(root, path, level);
return 0; return 0;
} }
...@@ -1101,6 +1102,8 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -1101,6 +1102,8 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
} else { } else {
btrfs_block_release(root, right_buf); btrfs_block_release(root, right_buf);
} }
if (path->nodes[1])
check_node(root, path, 1);
return 0; return 0;
} }
/* /*
...@@ -1216,6 +1219,7 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -1216,6 +1219,7 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
btrfs_mark_buffer_dirty(t); btrfs_mark_buffer_dirty(t);
btrfs_mark_buffer_dirty(right_buf); btrfs_mark_buffer_dirty(right_buf);
wret = fixup_low_keys(trans, root, path, &right->items[0].key, 1); wret = fixup_low_keys(trans, root, path, &right->items[0].key, 1);
if (wret) if (wret)
ret = wret; ret = wret;
...@@ -1231,6 +1235,8 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -1231,6 +1235,8 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
path->slots[0] -= push_items; path->slots[0] -= push_items;
} }
BUG_ON(path->slots[0] < 0); BUG_ON(path->slots[0] < 0);
if (path->nodes[1])
check_node(root, path, 1);
return ret; return ret;
} }
...@@ -1326,13 +1332,12 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -1326,13 +1332,12 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
wret = insert_ptr(trans, root, path, wret = insert_ptr(trans, root, path,
&disk_key, &disk_key,
bh_blocknr(right_buffer), bh_blocknr(right_buffer),
path->slots[1] - 1, 1); path->slots[1], 1);
if (wret) if (wret)
ret = wret; ret = wret;
btrfs_block_release(root, path->nodes[0]); btrfs_block_release(root, path->nodes[0]);
path->nodes[0] = right_buffer; path->nodes[0] = right_buffer;
path->slots[0] = 0; path->slots[0] = 0;
path->slots[1] -= 1;
if (path->slots[1] == 0) { if (path->slots[1] == 0) {
wret = fixup_low_keys(trans, root, wret = fixup_low_keys(trans, root,
path, &disk_key, 1); path, &disk_key, 1);
...@@ -1379,6 +1384,7 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -1379,6 +1384,7 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
} else } else
btrfs_block_release(root, right_buffer); btrfs_block_release(root, right_buffer);
BUG_ON(path->slots[0] < 0); BUG_ON(path->slots[0] < 0);
check_node(root, path, 1);
if (!double_split) if (!double_split)
return ret; return ret;
......
...@@ -1529,7 +1529,8 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans, ...@@ -1529,7 +1529,8 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans,
btrfs_set_file_extent_type(ei, btrfs_set_file_extent_type(ei,
BTRFS_FILE_EXTENT_INLINE); BTRFS_FILE_EXTENT_INLINE);
ptr = btrfs_file_extent_inline_start(ei); ptr = btrfs_file_extent_inline_start(ei);
memcpy(ptr, bh->b_data, offset + write_bytes); btrfs_memcpy(root, path->nodes[0]->b_data,
ptr, bh->b_data, offset + write_bytes);
mark_buffer_dirty(path->nodes[0]); mark_buffer_dirty(path->nodes[0]);
btrfs_free_path(path); btrfs_free_path(path);
} else { } else {
...@@ -1686,9 +1687,9 @@ static int drop_extents(struct btrfs_trans_handle *trans, ...@@ -1686,9 +1687,9 @@ static int drop_extents(struct btrfs_trans_handle *trans,
ret = btrfs_del_item(trans, root, path); ret = btrfs_del_item(trans, root, path);
BUG_ON(ret); BUG_ON(ret);
btrfs_release_path(root, path); btrfs_release_path(root, path);
extent = NULL;
if (found_extent) { if (found_extent) {
inode->i_blocks -= inode->i_blocks -= extent_num_blocks << 3;
btrfs_file_extent_num_blocks(extent) << 3;
ret = btrfs_free_extent(trans, root, ret = btrfs_free_extent(trans, root,
disk_blocknr, disk_blocknr,
disk_num_blocks, 0); disk_num_blocks, 0);
...@@ -1832,7 +1833,6 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf, ...@@ -1832,7 +1833,6 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
u64 alloc_extent_start; u64 alloc_extent_start;
struct btrfs_trans_handle *trans; struct btrfs_trans_handle *trans;
struct btrfs_key ins; struct btrfs_key ins;
pinned[0] = NULL; pinned[0] = NULL;
pinned[1] = NULL; pinned[1] = NULL;
if (file->f_flags & O_DIRECT) if (file->f_flags & O_DIRECT)
......
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