Commit b1c16ac9 authored by Nikolay Borisov's avatar Nikolay Borisov Committed by David Sterba

btrfs: Use kvmalloc for allocating compressed path context

Recent refactoring of cow_file_range_async means it's now possible to
request a rather large physically contiguous memory via kmalloc. The
size is dependent on the number of 512k chunks that the compressed range
consists of. David reported multiple OOM messages on such large
allocations. Fix it by switching to using kvmalloc.
Signed-off-by: default avatarNikolay Borisov <nborisov@suse.com>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent 7447555f
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/magic.h> #include <linux/magic.h>
#include <linux/iversion.h> #include <linux/iversion.h>
#include <linux/swap.h> #include <linux/swap.h>
#include <linux/sched/mm.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
#include "ctree.h" #include "ctree.h"
#include "disk-io.h" #include "disk-io.h"
...@@ -1172,7 +1173,7 @@ static noinline void async_cow_free(struct btrfs_work *work) ...@@ -1172,7 +1173,7 @@ static noinline void async_cow_free(struct btrfs_work *work)
* async_chunk's, freeing it ensures the whole array has been freed. * async_chunk's, freeing it ensures the whole array has been freed.
*/ */
if (atomic_dec_and_test(async_chunk->pending)) if (atomic_dec_and_test(async_chunk->pending))
kfree(async_chunk->pending); kvfree(async_chunk->pending);
} }
static int cow_file_range_async(struct inode *inode, struct page *locked_page, static int cow_file_range_async(struct inode *inode, struct page *locked_page,
...@@ -1188,6 +1189,7 @@ static int cow_file_range_async(struct inode *inode, struct page *locked_page, ...@@ -1188,6 +1189,7 @@ static int cow_file_range_async(struct inode *inode, struct page *locked_page,
u64 num_chunks = DIV_ROUND_UP(end - start, SZ_512K); u64 num_chunks = DIV_ROUND_UP(end - start, SZ_512K);
int i; int i;
bool should_compress; bool should_compress;
unsigned nofs_flag;
unlock_extent(&BTRFS_I(inode)->io_tree, start, end); unlock_extent(&BTRFS_I(inode)->io_tree, start, end);
...@@ -1199,7 +1201,10 @@ static int cow_file_range_async(struct inode *inode, struct page *locked_page, ...@@ -1199,7 +1201,10 @@ static int cow_file_range_async(struct inode *inode, struct page *locked_page,
should_compress = true; should_compress = true;
} }
ctx = kmalloc(struct_size(ctx, chunks, num_chunks), GFP_NOFS); nofs_flag = memalloc_nofs_save();
ctx = kvmalloc(struct_size(ctx, chunks, num_chunks), GFP_KERNEL);
memalloc_nofs_restore(nofs_flag);
if (!ctx) { if (!ctx) {
unsigned clear_bits = EXTENT_LOCKED | EXTENT_DELALLOC | unsigned clear_bits = EXTENT_LOCKED | EXTENT_DELALLOC |
EXTENT_DELALLOC_NEW | EXTENT_DEFRAG | EXTENT_DELALLOC_NEW | EXTENT_DEFRAG |
......
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