aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorForrest Liu <forrestl@synology.com>2015-02-09 04:31:45 -0500
committerChris Mason <clm@fb.com>2015-04-29 16:22:09 -0400
commit5d2361db48899789fb466ff62db5d5fc7b070e86 (patch)
treeccc1158ccc22b0ba31a44ec20f11e08682995ca1 /fs/btrfs
parent6e17d30bfaf43e04d991392d8484f1c556810c33 (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.c51
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