diff options
author | Qu Wenruo <wqu@suse.com> | 2021-11-20 16:34:11 +0800 |
---|---|---|
committer | David Sterba <dsterba@suse.com> | 2021-11-26 16:10:05 +0100 |
commit | daf87e953527b03c0bd4c0f41d704ba71186256d (patch) | |
tree | 28e8dbee575ea177897e2b62e6b834fab5d11616 /fs/btrfs | |
parent | 6c405b24097c24cbb11570b47fd382676014f72e (diff) | |
download | linux-stable-daf87e953527b03c0bd4c0f41d704ba71186256d.tar.gz linux-stable-daf87e953527b03c0bd4c0f41d704ba71186256d.tar.bz2 linux-stable-daf87e953527b03c0bd4c0f41d704ba71186256d.zip |
btrfs: fix the memory leak caused in lzo_compress_pages()
[BUG]
Fstests generic/027 is pretty easy to trigger a slow but steady memory
leak if run with "-o compress=lzo" mount option.
Normally one single run of generic/027 is enough to eat up at least 4G ram.
[CAUSE]
In commit d4088803f511 ("btrfs: subpage: make lzo_compress_pages()
compatible") we changed how @page_in is released.
But that refactoring makes @page_in only released after all pages being
compressed.
This leaves error path not releasing @page_in. And by "error path"
things like incompressible data will also be treated as an error
(-E2BIG).
Thus it can cause a memory leak if even nothing wrong happened.
[FIX]
Add check under @out label to release @page_in when needed, so when we
hit any error, the input page is properly released.
Reported-by: Josef Bacik <josef@toxicpanda.com>
Fixes: d4088803f511 ("btrfs: subpage: make lzo_compress_pages() compatible")
Reviewed-and-tested-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/lzo.c | 2 |
1 files changed, 2 insertions, 0 deletions
diff --git a/fs/btrfs/lzo.c b/fs/btrfs/lzo.c index f410ceabcdbd..e61f00a192db 100644 --- a/fs/btrfs/lzo.c +++ b/fs/btrfs/lzo.c @@ -276,6 +276,8 @@ int lzo_compress_pages(struct list_head *ws, struct address_space *mapping, *total_out = cur_out; *total_in = cur_in - start; out: + if (page_in) + put_page(page_in); *out_pages = DIV_ROUND_UP(cur_out, PAGE_SIZE); return ret; } |