From ba929aa2f16e48820b59309b5f14a206567af73a 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 cb7f3fe9c9f6f..66e820f7b4402 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.39.5