Commit 40ae837b authored by Filipe Manana's avatar Filipe Manana Committed by Chris Mason

Btrfs: don't leak pages and memory on compressed write error

In inode.c:submit_compressed_extents(), if we fail before calling
btrfs_submit_compressed_write(), or when that function fails, we
were freeing the async_extent structure without releasing its pages
and freeing the pages array.
Signed-off-by: default avatarFilipe Manana <fdmanana@suse.com>
Signed-off-by: default avatarChris Mason <clm@fb.com>
parent fce2a4e6
...@@ -633,6 +633,22 @@ static noinline int compress_file_range(struct inode *inode, ...@@ -633,6 +633,22 @@ static noinline int compress_file_range(struct inode *inode,
goto out; goto out;
} }
static void free_async_extent_pages(struct async_extent *async_extent)
{
int i;
if (!async_extent->pages)
return;
for (i = 0; i < async_extent->nr_pages; i++) {
WARN_ON(async_extent->pages[i]->mapping);
page_cache_release(async_extent->pages[i]);
}
kfree(async_extent->pages);
async_extent->nr_pages = 0;
async_extent->pages = NULL;
}
/* /*
* phase two of compressed writeback. This is the ordered portion * phase two of compressed writeback. This is the ordered portion
* of the code, which only gets called in the order the work was * of the code, which only gets called in the order the work was
...@@ -709,15 +725,7 @@ static noinline int submit_compressed_extents(struct inode *inode, ...@@ -709,15 +725,7 @@ static noinline int submit_compressed_extents(struct inode *inode,
async_extent->compressed_size, async_extent->compressed_size,
0, alloc_hint, &ins, 1, 1); 0, alloc_hint, &ins, 1, 1);
if (ret) { if (ret) {
int i; free_async_extent_pages(async_extent);
for (i = 0; i < async_extent->nr_pages; i++) {
WARN_ON(async_extent->pages[i]->mapping);
page_cache_release(async_extent->pages[i]);
}
kfree(async_extent->pages);
async_extent->nr_pages = 0;
async_extent->pages = NULL;
if (ret == -ENOSPC) { if (ret == -ENOSPC) {
unlock_extent(io_tree, async_extent->start, unlock_extent(io_tree, async_extent->start,
...@@ -827,6 +835,7 @@ static noinline int submit_compressed_extents(struct inode *inode, ...@@ -827,6 +835,7 @@ static noinline int submit_compressed_extents(struct inode *inode,
extent_clear_unlock_delalloc(inode, start, end, NULL, 0, extent_clear_unlock_delalloc(inode, start, end, NULL, 0,
PAGE_END_WRITEBACK | PAGE_END_WRITEBACK |
PAGE_SET_ERROR); PAGE_SET_ERROR);
free_async_extent_pages(async_extent);
} }
alloc_hint = ins.objectid + ins.offset; alloc_hint = ins.objectid + ins.offset;
kfree(async_extent); kfree(async_extent);
...@@ -848,6 +857,7 @@ static noinline int submit_compressed_extents(struct inode *inode, ...@@ -848,6 +857,7 @@ static noinline int submit_compressed_extents(struct inode *inode,
PAGE_UNLOCK | PAGE_CLEAR_DIRTY | PAGE_UNLOCK | PAGE_CLEAR_DIRTY |
PAGE_SET_WRITEBACK | PAGE_END_WRITEBACK | PAGE_SET_WRITEBACK | PAGE_END_WRITEBACK |
PAGE_SET_ERROR); PAGE_SET_ERROR);
free_async_extent_pages(async_extent);
kfree(async_extent); kfree(async_extent);
goto again; goto again;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment