aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-02-15 11:00:35 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2011-02-15 11:00:35 -0500
commit007a14af2649c9ac77f38cd23469518ffb8b355a (patch)
treed6bc4477c11d7c8fd892f059acf0fc1ed547ba52
parent261cd298a8c363d7985e3482946edb4bfedacf98 (diff)
parentc26a920373a983b52223eed5a13b97404d8b4158 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable
* git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable: Btrfs: check return value of alloc_extent_map() Btrfs - Fix memory leak in btrfs_init_new_device() btrfs: prevent heap corruption in btrfs_ioctl_space_info() Btrfs: Fix balance panic Btrfs: don't release pages when we can't clear the uptodate bits Btrfs: fix page->private races
-rw-r--r--fs/btrfs/disk-io.c8
-rw-r--r--fs/btrfs/extent-tree.c2
-rw-r--r--fs/btrfs/extent_io.c48
-rw-r--r--fs/btrfs/extent_map.c4
-rw-r--r--fs/btrfs/file.c1
-rw-r--r--fs/btrfs/inode.c3
-rw-r--r--fs/btrfs/ioctl.c10
-rw-r--r--fs/btrfs/relocation.c1
-rw-r--r--fs/btrfs/volumes.c2
9 files changed, 68 insertions, 11 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index fdce8799b98d..e1aa8d607bc7 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -359,10 +359,14 @@ static int csum_dirty_buffer(struct btrfs_root *root, struct page *page)
359 359
360 tree = &BTRFS_I(page->mapping->host)->io_tree; 360 tree = &BTRFS_I(page->mapping->host)->io_tree;
361 361
362 if (page->private == EXTENT_PAGE_PRIVATE) 362 if (page->private == EXTENT_PAGE_PRIVATE) {
363 WARN_ON(1);
363 goto out; 364 goto out;
364 if (!page->private) 365 }
366 if (!page->private) {
367 WARN_ON(1);
365 goto out; 368 goto out;
369 }
366 len = page->private >> 2; 370 len = page->private >> 2;
367 WARN_ON(len == 0); 371 WARN_ON(len == 0);
368 372
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 4e7e012ad667..f3c96fc01439 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -6583,7 +6583,7 @@ static noinline int relocate_data_extent(struct inode *reloc_inode,
6583 u64 end = start + extent_key->offset - 1; 6583 u64 end = start + extent_key->offset - 1;
6584 6584
6585 em = alloc_extent_map(GFP_NOFS); 6585 em = alloc_extent_map(GFP_NOFS);
6586 BUG_ON(!em || IS_ERR(em)); 6586 BUG_ON(!em);
6587 6587
6588 em->start = start; 6588 em->start = start;
6589 em->len = extent_key->offset; 6589 em->len = extent_key->offset;
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index 5e76a474cb7e..92ac5192c518 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -1946,6 +1946,7 @@ void set_page_extent_mapped(struct page *page)
1946 1946
1947static void set_page_extent_head(struct page *page, unsigned long len) 1947static void set_page_extent_head(struct page *page, unsigned long len)
1948{ 1948{
1949 WARN_ON(!PagePrivate(page));
1949 set_page_private(page, EXTENT_PAGE_PRIVATE_FIRST_PAGE | len << 2); 1950 set_page_private(page, EXTENT_PAGE_PRIVATE_FIRST_PAGE | len << 2);
1950} 1951}
1951 1952
@@ -2821,9 +2822,17 @@ int try_release_extent_state(struct extent_map_tree *map,
2821 * at this point we can safely clear everything except the 2822 * at this point we can safely clear everything except the
2822 * locked bit and the nodatasum bit 2823 * locked bit and the nodatasum bit
2823 */ 2824 */
2824 clear_extent_bit(tree, start, end, 2825 ret = clear_extent_bit(tree, start, end,
2825 ~(EXTENT_LOCKED | EXTENT_NODATASUM), 2826 ~(EXTENT_LOCKED | EXTENT_NODATASUM),
2826 0, 0, NULL, mask); 2827 0, 0, NULL, mask);
2828
2829 /* if clear_extent_bit failed for enomem reasons,
2830 * we can't allow the release to continue.
2831 */
2832 if (ret < 0)
2833 ret = 0;
2834 else
2835 ret = 1;
2827 } 2836 }
2828 return ret; 2837 return ret;
2829} 2838}
@@ -3194,7 +3203,13 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree,
3194 } 3203 }
3195 if (!PageUptodate(p)) 3204 if (!PageUptodate(p))
3196 uptodate = 0; 3205 uptodate = 0;
3197 unlock_page(p); 3206
3207 /*
3208 * see below about how we avoid a nasty race with release page
3209 * and why we unlock later
3210 */
3211 if (i != 0)
3212 unlock_page(p);
3198 } 3213 }
3199 if (uptodate) 3214 if (uptodate)
3200 set_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags); 3215 set_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags);
@@ -3218,9 +3233,26 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree,
3218 atomic_inc(&eb->refs); 3233 atomic_inc(&eb->refs);
3219 spin_unlock(&tree->buffer_lock); 3234 spin_unlock(&tree->buffer_lock);
3220 radix_tree_preload_end(); 3235 radix_tree_preload_end();
3236
3237 /*
3238 * there is a race where release page may have
3239 * tried to find this extent buffer in the radix
3240 * but failed. It will tell the VM it is safe to
3241 * reclaim the, and it will clear the page private bit.
3242 * We must make sure to set the page private bit properly
3243 * after the extent buffer is in the radix tree so
3244 * it doesn't get lost
3245 */
3246 set_page_extent_mapped(eb->first_page);
3247 set_page_extent_head(eb->first_page, eb->len);
3248 if (!page0)
3249 unlock_page(eb->first_page);
3221 return eb; 3250 return eb;
3222 3251
3223free_eb: 3252free_eb:
3253 if (eb->first_page && !page0)
3254 unlock_page(eb->first_page);
3255
3224 if (!atomic_dec_and_test(&eb->refs)) 3256 if (!atomic_dec_and_test(&eb->refs))
3225 return exists; 3257 return exists;
3226 btrfs_release_extent_buffer(eb); 3258 btrfs_release_extent_buffer(eb);
@@ -3271,10 +3303,11 @@ int clear_extent_buffer_dirty(struct extent_io_tree *tree,
3271 continue; 3303 continue;
3272 3304
3273 lock_page(page); 3305 lock_page(page);
3306 WARN_ON(!PagePrivate(page));
3307
3308 set_page_extent_mapped(page);
3274 if (i == 0) 3309 if (i == 0)
3275 set_page_extent_head(page, eb->len); 3310 set_page_extent_head(page, eb->len);
3276 else
3277 set_page_private(page, EXTENT_PAGE_PRIVATE);
3278 3311
3279 clear_page_dirty_for_io(page); 3312 clear_page_dirty_for_io(page);
3280 spin_lock_irq(&page->mapping->tree_lock); 3313 spin_lock_irq(&page->mapping->tree_lock);
@@ -3464,6 +3497,13 @@ int read_extent_buffer_pages(struct extent_io_tree *tree,
3464 3497
3465 for (i = start_i; i < num_pages; i++) { 3498 for (i = start_i; i < num_pages; i++) {
3466 page = extent_buffer_page(eb, i); 3499 page = extent_buffer_page(eb, i);
3500
3501 WARN_ON(!PagePrivate(page));
3502
3503 set_page_extent_mapped(page);
3504 if (i == 0)
3505 set_page_extent_head(page, eb->len);
3506
3467 if (inc_all_pages) 3507 if (inc_all_pages)
3468 page_cache_get(page); 3508 page_cache_get(page);
3469 if (!PageUptodate(page)) { 3509 if (!PageUptodate(page)) {
diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c
index b0e1fce12530..2b6c12e983b3 100644
--- a/fs/btrfs/extent_map.c
+++ b/fs/btrfs/extent_map.c
@@ -51,8 +51,8 @@ struct extent_map *alloc_extent_map(gfp_t mask)
51{ 51{
52 struct extent_map *em; 52 struct extent_map *em;
53 em = kmem_cache_alloc(extent_map_cache, mask); 53 em = kmem_cache_alloc(extent_map_cache, mask);
54 if (!em || IS_ERR(em)) 54 if (!em)
55 return em; 55 return NULL;
56 em->in_tree = 0; 56 em->in_tree = 0;
57 em->flags = 0; 57 em->flags = 0;
58 em->compress_type = BTRFS_COMPRESS_NONE; 58 em->compress_type = BTRFS_COMPRESS_NONE;
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index c1d3a818731a..7084140d5940 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -186,6 +186,7 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
186 split = alloc_extent_map(GFP_NOFS); 186 split = alloc_extent_map(GFP_NOFS);
187 if (!split2) 187 if (!split2)
188 split2 = alloc_extent_map(GFP_NOFS); 188 split2 = alloc_extent_map(GFP_NOFS);
189 BUG_ON(!split || !split2);
189 190
190 write_lock(&em_tree->lock); 191 write_lock(&em_tree->lock);
191 em = lookup_extent_mapping(em_tree, start, len); 192 em = lookup_extent_mapping(em_tree, start, len);
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index bcc461a9695f..fb9bd7832b6d 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -644,6 +644,7 @@ retry:
644 async_extent->ram_size - 1, 0); 644 async_extent->ram_size - 1, 0);
645 645
646 em = alloc_extent_map(GFP_NOFS); 646 em = alloc_extent_map(GFP_NOFS);
647 BUG_ON(!em);
647 em->start = async_extent->start; 648 em->start = async_extent->start;
648 em->len = async_extent->ram_size; 649 em->len = async_extent->ram_size;
649 em->orig_start = em->start; 650 em->orig_start = em->start;
@@ -820,6 +821,7 @@ static noinline int cow_file_range(struct inode *inode,
820 BUG_ON(ret); 821 BUG_ON(ret);
821 822
822 em = alloc_extent_map(GFP_NOFS); 823 em = alloc_extent_map(GFP_NOFS);
824 BUG_ON(!em);
823 em->start = start; 825 em->start = start;
824 em->orig_start = em->start; 826 em->orig_start = em->start;
825 ram_size = ins.offset; 827 ram_size = ins.offset;
@@ -1169,6 +1171,7 @@ out_check:
1169 struct extent_map_tree *em_tree; 1171 struct extent_map_tree *em_tree;
1170 em_tree = &BTRFS_I(inode)->extent_tree; 1172 em_tree = &BTRFS_I(inode)->extent_tree;
1171 em = alloc_extent_map(GFP_NOFS); 1173 em = alloc_extent_map(GFP_NOFS);
1174 BUG_ON(!em);
1172 em->start = cur_offset; 1175 em->start = cur_offset;
1173 em->orig_start = em->start; 1176 em->orig_start = em->start;
1174 em->len = num_bytes; 1177 em->len = num_bytes;
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 02d224e8c83f..be2d4f6aaa5e 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -2208,7 +2208,7 @@ long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg)
2208 int num_types = 4; 2208 int num_types = 4;
2209 int alloc_size; 2209 int alloc_size;
2210 int ret = 0; 2210 int ret = 0;
2211 int slot_count = 0; 2211 u64 slot_count = 0;
2212 int i, c; 2212 int i, c;
2213 2213
2214 if (copy_from_user(&space_args, 2214 if (copy_from_user(&space_args,
@@ -2247,7 +2247,7 @@ long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg)
2247 goto out; 2247 goto out;
2248 } 2248 }
2249 2249
2250 slot_count = min_t(int, space_args.space_slots, slot_count); 2250 slot_count = min_t(u64, space_args.space_slots, slot_count);
2251 2251
2252 alloc_size = sizeof(*dest) * slot_count; 2252 alloc_size = sizeof(*dest) * slot_count;
2253 2253
@@ -2267,6 +2267,9 @@ long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg)
2267 for (i = 0; i < num_types; i++) { 2267 for (i = 0; i < num_types; i++) {
2268 struct btrfs_space_info *tmp; 2268 struct btrfs_space_info *tmp;
2269 2269
2270 if (!slot_count)
2271 break;
2272
2270 info = NULL; 2273 info = NULL;
2271 rcu_read_lock(); 2274 rcu_read_lock();
2272 list_for_each_entry_rcu(tmp, &root->fs_info->space_info, 2275 list_for_each_entry_rcu(tmp, &root->fs_info->space_info,
@@ -2288,7 +2291,10 @@ long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg)
2288 memcpy(dest, &space, sizeof(space)); 2291 memcpy(dest, &space, sizeof(space));
2289 dest++; 2292 dest++;
2290 space_args.total_spaces++; 2293 space_args.total_spaces++;
2294 slot_count--;
2291 } 2295 }
2296 if (!slot_count)
2297 break;
2292 } 2298 }
2293 up_read(&info->groups_sem); 2299 up_read(&info->groups_sem);
2294 } 2300 }
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
index 1f5556acb530..0825e4ed9447 100644
--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -1157,6 +1157,7 @@ static int clone_backref_node(struct btrfs_trans_handle *trans,
1157 new_node->bytenr = dest->node->start; 1157 new_node->bytenr = dest->node->start;
1158 new_node->level = node->level; 1158 new_node->level = node->level;
1159 new_node->lowest = node->lowest; 1159 new_node->lowest = node->lowest;
1160 new_node->checked = 1;
1160 new_node->root = dest; 1161 new_node->root = dest;
1161 1162
1162 if (!node->lowest) { 1163 if (!node->lowest) {
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 2636a051e4b2..af7dbca15276 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -1605,12 +1605,14 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
1605 1605
1606 ret = find_next_devid(root, &device->devid); 1606 ret = find_next_devid(root, &device->devid);
1607 if (ret) { 1607 if (ret) {
1608 kfree(device->name);
1608 kfree(device); 1609 kfree(device);
1609 goto error; 1610 goto error;
1610 } 1611 }
1611 1612
1612 trans = btrfs_start_transaction(root, 0); 1613 trans = btrfs_start_transaction(root, 0);
1613 if (IS_ERR(trans)) { 1614 if (IS_ERR(trans)) {
1615 kfree(device->name);
1614 kfree(device); 1616 kfree(device);
1615 ret = PTR_ERR(trans); 1617 ret = PTR_ERR(trans);
1616 goto error; 1618 goto error;