diff options
author | Forrest Liu <forrestl@synology.com> | 2015-02-09 04:31:45 -0500 |
---|---|---|
committer | Chris Mason <clm@fb.com> | 2015-04-29 16:22:09 -0400 |
commit | 5d2361db48899789fb466ff62db5d5fc7b070e86 (patch) | |
tree | ccc1158ccc22b0ba31a44ec20f11e08682995ca1 /fs/btrfs | |
parent | 6e17d30bfaf43e04d991392d8484f1c556810c33 (diff) |
Btrfs: btrfs_release_extent_buffer_page didn't free pages of dummy extent
btrfs_release_extent_buffer_page() can't handle dummy extent that
allocated by btrfs_clone_extent_buffer() properly. That is because
reference count of pages that allocated by btrfs_clone_extent_buffer()
was 2, 1 by alloc_page(), and another by attach_extent_buffer_page().
Running following command repeatly can check this memory leak problem
btrfs inspect-internal inode-resolve 256 /mnt/btrfs
Signed-off-by: Chien-Kuan Yeh <ckya@synology.com>
Signed-off-by: Forrest Liu <forrestl@synology.com>
Reviewed-by: Filipe Manana <fdmanana@suse.com>
Tested-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: Chris Mason <clm@fb.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/extent_io.c | 51 |
1 files changed, 26 insertions, 25 deletions
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index ea100eb188de..43af5a61ad25 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c | |||
@@ -4560,36 +4560,37 @@ static void btrfs_release_extent_buffer_page(struct extent_buffer *eb) | |||
4560 | do { | 4560 | do { |
4561 | index--; | 4561 | index--; |
4562 | page = eb->pages[index]; | 4562 | page = eb->pages[index]; |
4563 | if (page && mapped) { | 4563 | if (!page) |
4564 | continue; | ||
4565 | if (mapped) | ||
4564 | spin_lock(&page->mapping->private_lock); | 4566 | spin_lock(&page->mapping->private_lock); |
4567 | /* | ||
4568 | * We do this since we'll remove the pages after we've | ||
4569 | * removed the eb from the radix tree, so we could race | ||
4570 | * and have this page now attached to the new eb. So | ||
4571 | * only clear page_private if it's still connected to | ||
4572 | * this eb. | ||
4573 | */ | ||
4574 | if (PagePrivate(page) && | ||
4575 | page->private == (unsigned long)eb) { | ||
4576 | BUG_ON(test_bit(EXTENT_BUFFER_DIRTY, &eb->bflags)); | ||
4577 | BUG_ON(PageDirty(page)); | ||
4578 | BUG_ON(PageWriteback(page)); | ||
4565 | /* | 4579 | /* |
4566 | * We do this since we'll remove the pages after we've | 4580 | * We need to make sure we haven't be attached |
4567 | * removed the eb from the radix tree, so we could race | 4581 | * to a new eb. |
4568 | * and have this page now attached to the new eb. So | ||
4569 | * only clear page_private if it's still connected to | ||
4570 | * this eb. | ||
4571 | */ | 4582 | */ |
4572 | if (PagePrivate(page) && | 4583 | ClearPagePrivate(page); |
4573 | page->private == (unsigned long)eb) { | 4584 | set_page_private(page, 0); |
4574 | BUG_ON(test_bit(EXTENT_BUFFER_DIRTY, &eb->bflags)); | 4585 | /* One for the page private */ |
4575 | BUG_ON(PageDirty(page)); | ||
4576 | BUG_ON(PageWriteback(page)); | ||
4577 | /* | ||
4578 | * We need to make sure we haven't be attached | ||
4579 | * to a new eb. | ||
4580 | */ | ||
4581 | ClearPagePrivate(page); | ||
4582 | set_page_private(page, 0); | ||
4583 | /* One for the page private */ | ||
4584 | page_cache_release(page); | ||
4585 | } | ||
4586 | spin_unlock(&page->mapping->private_lock); | ||
4587 | |||
4588 | } | ||
4589 | if (page) { | ||
4590 | /* One for when we alloced the page */ | ||
4591 | page_cache_release(page); | 4586 | page_cache_release(page); |
4592 | } | 4587 | } |
4588 | |||
4589 | if (mapped) | ||
4590 | spin_unlock(&page->mapping->private_lock); | ||
4591 | |||
4592 | /* One for when we alloced the page */ | ||
4593 | page_cache_release(page); | ||
4593 | } while (index != 0); | 4594 | } while (index != 0); |
4594 | } | 4595 | } |
4595 | 4596 | ||