diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-02-15 11:00:35 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-02-15 11:00:35 -0500 |
commit | 007a14af2649c9ac77f38cd23469518ffb8b355a (patch) | |
tree | d6bc4477c11d7c8fd892f059acf0fc1ed547ba52 | |
parent | 261cd298a8c363d7985e3482946edb4bfedacf98 (diff) | |
parent | c26a920373a983b52223eed5a13b97404d8b4158 (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.c | 8 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 2 | ||||
-rw-r--r-- | fs/btrfs/extent_io.c | 48 | ||||
-rw-r--r-- | fs/btrfs/extent_map.c | 4 | ||||
-rw-r--r-- | fs/btrfs/file.c | 1 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 3 | ||||
-rw-r--r-- | fs/btrfs/ioctl.c | 10 | ||||
-rw-r--r-- | fs/btrfs/relocation.c | 1 | ||||
-rw-r--r-- | fs/btrfs/volumes.c | 2 |
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 | ||
1947 | static void set_page_extent_head(struct page *page, unsigned long len) | 1947 | static 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 | ||
3223 | free_eb: | 3252 | free_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; |