History

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.

Nikolay Borisov committed 7 years ago

Commit b1c16ac1 parent 74475551 file · +7 −2Browse files

Unified · Split

fs/btrfs/inode.c+7−2
@@ -28,6 +28,7 @@ · 27 unmodified lines
2828 #include <linux/magic.h>
2929 #include <linux/iversion.h>
3030 #include <linux/swap.h>
31+#include <linux/sched/mm.h>
3132 #include <asm/unaligned.h>
3233 #include "ctree.h"
3334 #include "disk-io.h"
@@ -1172,7 +1173,7 @@ static noinline void async_cow_free(struct btrfs_work *work) · 1138 unmodified lines
11721173 * async_chunk's, freeing it ensures the whole array has been freed.
11731174 */
11741175 if (atomic_dec_and_test(async_chunk->pending))
1175− kfree(async_chunk->pending);
1176+ kvfree(async_chunk->pending);
11761177 }
11771178
11781179 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, · 9 unmodified lines
11881189 u64 num_chunks = DIV_ROUND_UP(end - start, SZ_512K);
11891190 int i;
11901191 bool should_compress;
1192+ unsigned nofs_flag;
11911193
11921194 unlock_extent(&BTRFS_I(inode)->io_tree, start, end);
11931195
@@ -1199,7 +1201,10 @@ static int cow_file_range_async(struct inode *inode, struct page *locked_page, · 5 unmodified lines
11991201 should_compress = true;
12001202 }
12011203
1202− ctx = kmalloc(struct_size(ctx, chunks, num_chunks), GFP_NOFS);
1204+ nofs_flag = memalloc_nofs_save();
1205+ ctx = kvmalloc(struct_size(ctx, chunks, num_chunks), GFP_KERNEL);
1206+ memalloc_nofs_restore(nofs_flag);
1207+
12031208 if (!ctx) {
12041209 unsigned clear_bits = EXTENT_LOCKED | EXTENT_DELALLOC |
12051210 EXTENT_DELALLOC_NEW | EXTENT_DEFRAG |