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: Filipe Manana <fdmanana@suse.com> Signed-off-by: Chris Mason <clm@fb.com>
This commit is contained in:
Родитель
fce2a4e6b2
Коммит
40ae837b43
|
@ -633,6 +633,22 @@ free_pages_out:
|
||||||
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 @@ retry:
|
||||||
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 @@ retry:
|
||||||
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 @@ out_free:
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче