mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-02 10:23:55 +08:00
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>
This commit is contained in:
parent
6e17d30bfa
commit
5d2361db48
@ -4560,36 +4560,37 @@ static void btrfs_release_extent_buffer_page(struct extent_buffer *eb)
|
||||
do {
|
||||
index--;
|
||||
page = eb->pages[index];
|
||||
if (page && mapped) {
|
||||
if (!page)
|
||||
continue;
|
||||
if (mapped)
|
||||
spin_lock(&page->mapping->private_lock);
|
||||
/*
|
||||
* We do this since we'll remove the pages after we've
|
||||
* removed the eb from the radix tree, so we could race
|
||||
* and have this page now attached to the new eb. So
|
||||
* only clear page_private if it's still connected to
|
||||
* this eb.
|
||||
*/
|
||||
if (PagePrivate(page) &&
|
||||
page->private == (unsigned long)eb) {
|
||||
BUG_ON(test_bit(EXTENT_BUFFER_DIRTY, &eb->bflags));
|
||||
BUG_ON(PageDirty(page));
|
||||
BUG_ON(PageWriteback(page));
|
||||
/*
|
||||
* We do this since we'll remove the pages after we've
|
||||
* removed the eb from the radix tree, so we could race
|
||||
* and have this page now attached to the new eb. So
|
||||
* only clear page_private if it's still connected to
|
||||
* this eb.
|
||||
* We need to make sure we haven't be attached
|
||||
* to a new eb.
|
||||
*/
|
||||
if (PagePrivate(page) &&
|
||||
page->private == (unsigned long)eb) {
|
||||
BUG_ON(test_bit(EXTENT_BUFFER_DIRTY, &eb->bflags));
|
||||
BUG_ON(PageDirty(page));
|
||||
BUG_ON(PageWriteback(page));
|
||||
/*
|
||||
* We need to make sure we haven't be attached
|
||||
* to a new eb.
|
||||
*/
|
||||
ClearPagePrivate(page);
|
||||
set_page_private(page, 0);
|
||||
/* One for the page private */
|
||||
page_cache_release(page);
|
||||
}
|
||||
spin_unlock(&page->mapping->private_lock);
|
||||
|
||||
}
|
||||
if (page) {
|
||||
/* One for when we alloced the page */
|
||||
ClearPagePrivate(page);
|
||||
set_page_private(page, 0);
|
||||
/* One for the page private */
|
||||
page_cache_release(page);
|
||||
}
|
||||
|
||||
if (mapped)
|
||||
spin_unlock(&page->mapping->private_lock);
|
||||
|
||||
/* One for when we alloced the page */
|
||||
page_cache_release(page);
|
||||
} while (index != 0);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user