aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorLiu Bo <bo.li.liu@oracle.com>2016-06-06 15:01:23 -0400
committerDavid Sterba <dsterba@suse.com>2016-06-17 12:32:40 -0400
commitc871b0f2fd27e7f9097d507f47de5270f88003b9 (patch)
tree76635b17aa4948c8a8af7f9da1a3a8225ac2d518 /fs
parent16ff4b454f1b56e8d89a9075feed0dd6ac510c3d (diff)
Btrfs: check if extent buffer is aligned to sectorsize
Thanks to fuzz testing, we can pass an invalid bytenr to extent buffer via alloc_extent_buffer(). An unaligned eb can have more pages than it should have, which ends up extent buffer's leak or some corrupted content in extent buffer. This adds a warning to let us quickly know what was happening. Now that alloc_extent_buffer() no more returns NULL, this changes its caller and callers of its caller to match with the new error handling. 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')
-rw-r--r--fs/btrfs/ctree.c2
-rw-r--r--fs/btrfs/disk-io.c8
-rw-r--r--fs/btrfs/extent-tree.c10
-rw-r--r--fs/btrfs/extent_io.c15
-rw-r--r--fs/btrfs/tree-log.c4
-rw-r--r--fs/btrfs/volumes.c4
6 files changed, 28 insertions, 15 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 46025688f1d0..827c949fa4bc 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -2512,6 +2512,8 @@ read_block_for_search(struct btrfs_trans_handle *trans,
2512 if (!btrfs_buffer_uptodate(tmp, 0, 0)) 2512 if (!btrfs_buffer_uptodate(tmp, 0, 0))
2513 ret = -EIO; 2513 ret = -EIO;
2514 free_extent_buffer(tmp); 2514 free_extent_buffer(tmp);
2515 } else {
2516 ret = PTR_ERR(tmp);
2515 } 2517 }
2516 return ret; 2518 return ret;
2517} 2519}
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 1142127f6e5e..7b5d5e8efde6 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -1098,7 +1098,7 @@ void readahead_tree_block(struct btrfs_root *root, u64 bytenr)
1098 struct inode *btree_inode = root->fs_info->btree_inode; 1098 struct inode *btree_inode = root->fs_info->btree_inode;
1099 1099
1100 buf = btrfs_find_create_tree_block(root, bytenr); 1100 buf = btrfs_find_create_tree_block(root, bytenr);
1101 if (!buf) 1101 if (IS_ERR(buf))
1102 return; 1102 return;
1103 read_extent_buffer_pages(&BTRFS_I(btree_inode)->io_tree, 1103 read_extent_buffer_pages(&BTRFS_I(btree_inode)->io_tree,
1104 buf, 0, WAIT_NONE, btree_get_extent, 0); 1104 buf, 0, WAIT_NONE, btree_get_extent, 0);
@@ -1114,7 +1114,7 @@ int reada_tree_block_flagged(struct btrfs_root *root, u64 bytenr,
1114 int ret; 1114 int ret;
1115 1115
1116 buf = btrfs_find_create_tree_block(root, bytenr); 1116 buf = btrfs_find_create_tree_block(root, bytenr);
1117 if (!buf) 1117 if (IS_ERR(buf))
1118 return 0; 1118 return 0;
1119 1119
1120 set_bit(EXTENT_BUFFER_READAHEAD, &buf->bflags); 1120 set_bit(EXTENT_BUFFER_READAHEAD, &buf->bflags);
@@ -1172,8 +1172,8 @@ struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr,
1172 int ret; 1172 int ret;
1173 1173
1174 buf = btrfs_find_create_tree_block(root, bytenr); 1174 buf = btrfs_find_create_tree_block(root, bytenr);
1175 if (!buf) 1175 if (IS_ERR(buf))
1176 return ERR_PTR(-ENOMEM); 1176 return buf;
1177 1177
1178 ret = btree_read_extent_buffer_pages(root, buf, 0, parent_transid); 1178 ret = btree_read_extent_buffer_pages(root, buf, 0, parent_transid);
1179 if (ret) { 1179 if (ret) {
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 689d25ac6a68..5439e85c4813 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -8016,8 +8016,9 @@ btrfs_init_new_buffer(struct btrfs_trans_handle *trans, struct btrfs_root *root,
8016 struct extent_buffer *buf; 8016 struct extent_buffer *buf;
8017 8017
8018 buf = btrfs_find_create_tree_block(root, bytenr); 8018 buf = btrfs_find_create_tree_block(root, bytenr);
8019 if (!buf) 8019 if (IS_ERR(buf))
8020 return ERR_PTR(-ENOMEM); 8020 return buf;
8021
8021 btrfs_set_header_generation(buf, trans->transid); 8022 btrfs_set_header_generation(buf, trans->transid);
8022 btrfs_set_buffer_lockdep_class(root->root_key.objectid, buf, level); 8023 btrfs_set_buffer_lockdep_class(root->root_key.objectid, buf, level);
8023 btrfs_tree_lock(buf); 8024 btrfs_tree_lock(buf);
@@ -8659,8 +8660,9 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
8659 next = btrfs_find_tree_block(root->fs_info, bytenr); 8660 next = btrfs_find_tree_block(root->fs_info, bytenr);
8660 if (!next) { 8661 if (!next) {
8661 next = btrfs_find_create_tree_block(root, bytenr); 8662 next = btrfs_find_create_tree_block(root, bytenr);
8662 if (!next) 8663 if (IS_ERR(next))
8663 return -ENOMEM; 8664 return PTR_ERR(next);
8665
8664 btrfs_set_buffer_lockdep_class(root->root_key.objectid, next, 8666 btrfs_set_buffer_lockdep_class(root->root_key.objectid, next,
8665 level - 1); 8667 level - 1);
8666 reada = 1; 8668 reada = 1;
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index a3412d68ad37..aaee3ef55ed8 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -4892,18 +4892,25 @@ struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info,
4892 int uptodate = 1; 4892 int uptodate = 1;
4893 int ret; 4893 int ret;
4894 4894
4895 if (!IS_ALIGNED(start, fs_info->tree_root->sectorsize)) {
4896 btrfs_err(fs_info, "bad tree block start %llu", start);
4897 return ERR_PTR(-EINVAL);
4898 }
4899
4895 eb = find_extent_buffer(fs_info, start); 4900 eb = find_extent_buffer(fs_info, start);
4896 if (eb) 4901 if (eb)
4897 return eb; 4902 return eb;
4898 4903
4899 eb = __alloc_extent_buffer(fs_info, start, len); 4904 eb = __alloc_extent_buffer(fs_info, start, len);
4900 if (!eb) 4905 if (!eb)
4901 return NULL; 4906 return ERR_PTR(-ENOMEM);
4902 4907
4903 for (i = 0; i < num_pages; i++, index++) { 4908 for (i = 0; i < num_pages; i++, index++) {
4904 p = find_or_create_page(mapping, index, GFP_NOFS|__GFP_NOFAIL); 4909 p = find_or_create_page(mapping, index, GFP_NOFS|__GFP_NOFAIL);
4905 if (!p) 4910 if (!p) {
4911 exists = ERR_PTR(-ENOMEM);
4906 goto free_eb; 4912 goto free_eb;
4913 }
4907 4914
4908 spin_lock(&mapping->private_lock); 4915 spin_lock(&mapping->private_lock);
4909 if (PagePrivate(p)) { 4916 if (PagePrivate(p)) {
@@ -4948,8 +4955,10 @@ struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info,
4948 set_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags); 4955 set_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags);
4949again: 4956again:
4950 ret = radix_tree_preload(GFP_NOFS); 4957 ret = radix_tree_preload(GFP_NOFS);
4951 if (ret) 4958 if (ret) {
4959 exists = ERR_PTR(ret);
4952 goto free_eb; 4960 goto free_eb;
4961 }
4953 4962
4954 spin_lock(&fs_info->buffer_lock); 4963 spin_lock(&fs_info->buffer_lock);
4955 ret = radix_tree_insert(&fs_info->buffer_radix, 4964 ret = radix_tree_insert(&fs_info->buffer_radix,
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index aa8fed11f749..8ab1dc64cbba 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -2422,8 +2422,8 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans,
2422 root_owner = btrfs_header_owner(parent); 2422 root_owner = btrfs_header_owner(parent);
2423 2423
2424 next = btrfs_find_create_tree_block(root, bytenr); 2424 next = btrfs_find_create_tree_block(root, bytenr);
2425 if (!next) 2425 if (IS_ERR(next))
2426 return -ENOMEM; 2426 return PTR_ERR(next);
2427 2427
2428 if (*level == 1) { 2428 if (*level == 1) {
2429 ret = wc->process_func(root, next, wc, ptr_gen); 2429 ret = wc->process_func(root, next, wc, ptr_gen);
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index fcbda4341f7d..c3a2900c6030 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -6607,8 +6607,8 @@ int btrfs_read_sys_array(struct btrfs_root *root)
6607 * overallocate but we can keep it as-is, only the first page is used. 6607 * overallocate but we can keep it as-is, only the first page is used.
6608 */ 6608 */
6609 sb = btrfs_find_create_tree_block(root, BTRFS_SUPER_INFO_OFFSET); 6609 sb = btrfs_find_create_tree_block(root, BTRFS_SUPER_INFO_OFFSET);
6610 if (!sb) 6610 if (IS_ERR(sb))
6611 return -ENOMEM; 6611 return PTR_ERR(sb);
6612 set_extent_buffer_uptodate(sb); 6612 set_extent_buffer_uptodate(sb);
6613 btrfs_set_buffer_lockdep_class(root->root_key.objectid, sb, 0); 6613 btrfs_set_buffer_lockdep_class(root->root_key.objectid, sb, 0);
6614 /* 6614 /*