From 6b3a4d60dbf7a60b91d810498e8c212f26718efd Mon Sep 17 00:00:00 2001 From: Shilong Wang Date: Fri, 10 Oct 2014 17:35:59 -0400 Subject: [PATCH] Btrfs: fix allocationg memory failure for btrfsic_state structure size of @btrfsic_state needs more than 2M, it is very likely to fail allocating memory using kzalloc(). see following mesage: [91428.902148] Call Trace: [] dump_stack+0x4d/0x66 [] warn_alloc_failed+0xff/0x170 [] __alloc_pages_nodemask+0x951/0xc30 [] alloc_pages_current+0x11a/0x1f0 [] ? alloc_kmem_pages+0x3b/0xf0 [] alloc_kmem_pages+0x3b/0xf0 [] kmalloc_order+0x18/0x50 [] kmalloc_order_trace+0x24/0x140 [] btrfsic_mount+0x8b/0xae0 [btrfs] [] ? check_preempt_curr+0x85/0xa0 [] ? try_to_wake_up+0x103/0x430 [] open_ctree+0x1bd0/0x2130 [btrfs] [] btrfs_mount+0x62e/0x8b0 [btrfs] [] ? alloc_pages_current+0x11a/0x1f0 [] ? __get_free_pages+0xe/0x50 [] mount_fs+0x39/0x1b0 [] vfs_kern_mount+0x6b/0x150 [] do_mount+0x27b/0xc30 [] ? __get_free_pages+0xe/0x50 [] SyS_mount+0x96/0xf0 [] system_call_fastpath+0x16/0x1b Since we are allocating memory for hash table array, so it will be good if we could allocate continuous pages here. Fix this problem by firstly trying kzalloc(), if we fail, use vzalloc() instead. Signed-off-by: Wang Shilong Signed-off-by: Chris Mason --- fs/btrfs/check-integrity.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/fs/btrfs/check-integrity.c b/fs/btrfs/check-integrity.c index cb7f3fe9c9f6..66e820f7b440 100644 --- a/fs/btrfs/check-integrity.c +++ b/fs/btrfs/check-integrity.c @@ -3130,10 +3130,13 @@ int btrfsic_mount(struct btrfs_root *root, root->sectorsize, PAGE_CACHE_SIZE); return -1; } - state = kzalloc(sizeof(*state), GFP_NOFS); - if (NULL == state) { - printk(KERN_INFO "btrfs check-integrity: kmalloc() failed!\n"); - return -1; + state = kzalloc(sizeof(*state), GFP_KERNEL | __GFP_NOWARN | __GFP_REPEAT); + if (!state) { + state = vzalloc(sizeof(*state)); + if (!state) { + printk(KERN_INFO "btrfs check-integrity: vzalloc() failed!\n"); + return -1; + } } if (!btrfsic_is_initialized) { @@ -3277,5 +3280,8 @@ void btrfsic_unmount(struct btrfs_root *root, mutex_unlock(&btrfsic_mutex); - kfree(state); + if (is_vmalloc_addr(state)) + vfree(state); + else + kfree(state); } -- 2.20.1