Btrfs: use memalloc_nofs and kvzalloc() for free space tree bitmaps

First, instead of open-coding the vmalloc() fallback, use the new
kvzalloc() helper. Second, use memalloc_nofs_{save,restore}() instead of
GFP_NOFS, as vmalloc() uses some GFP_KERNEL allocations internally which
could lead to deadlocks.

Signed-off-by: Omar Sandoval <osandov@fb.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Omar Sandoval 2017-06-05 00:12:31 -07:00 committed by David Sterba
parent 4b5faeac46
commit 25ff17e82f

View File

@ -17,7 +17,7 @@
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/vmalloc.h> #include <linux/sched/mm.h>
#include "ctree.h" #include "ctree.h"
#include "disk-io.h" #include "disk-io.h"
#include "locking.h" #include "locking.h"
@ -153,21 +153,21 @@ static inline u32 free_space_bitmap_size(u64 size, u32 sectorsize)
static u8 *alloc_bitmap(u32 bitmap_size) static u8 *alloc_bitmap(u32 bitmap_size)
{ {
void *mem; u8 *ret;
unsigned int nofs_flag;
/* /*
* The allocation size varies, observed numbers were < 4K up to 16K. * GFP_NOFS doesn't work with kvmalloc(), but we really can't recurse
* Using vmalloc unconditionally would be too heavy, we'll try * into the filesystem as the free space bitmap can be modified in the
* contiguous allocations first. * critical section of a transaction commit.
*
* TODO: push the memalloc_nofs_{save,restore}() to the caller where we
* know that recursion is unsafe.
*/ */
if (bitmap_size <= PAGE_SIZE) nofs_flag = memalloc_nofs_save();
return kzalloc(bitmap_size, GFP_NOFS); ret = kvzalloc(bitmap_size, GFP_KERNEL);
memalloc_nofs_restore(nofs_flag);
mem = kzalloc(bitmap_size, GFP_NOFS | __GFP_NOWARN); return ret;
if (mem)
return mem;
return __vmalloc(bitmap_size, GFP_NOFS | __GFP_ZERO, PAGE_KERNEL);
} }
int convert_free_space_to_bitmaps(struct btrfs_trans_handle *trans, int convert_free_space_to_bitmaps(struct btrfs_trans_handle *trans,