]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Btrfs: fix allocationg memory failure for btrfsic_state structure
authorShilong Wang <wangshilong1991@gmail.com>
Fri, 10 Oct 2014 21:35:59 +0000 (17:35 -0400)
committerChris Mason <clm@fb.com>
Fri, 21 Nov 2014 01:14:28 +0000 (17:14 -0800)
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:
[<ffffffff816f6e0f>] dump_stack+0x4d/0x66
[<ffffffff811b1c7f>] warn_alloc_failed+0xff/0x170
[<ffffffff811b66e1>] __alloc_pages_nodemask+0x951/0xc30
[<ffffffff811fd9da>] alloc_pages_current+0x11a/0x1f0
[<ffffffff811b1e0b>] ? alloc_kmem_pages+0x3b/0xf0
[<ffffffff811b1e0b>] alloc_kmem_pages+0x3b/0xf0
[<ffffffff811d1018>] kmalloc_order+0x18/0x50
[<ffffffff811d1074>] kmalloc_order_trace+0x24/0x140
[<ffffffffa06c097b>] btrfsic_mount+0x8b/0xae0 [btrfs]
[<ffffffff810af555>] ? check_preempt_curr+0x85/0xa0
[<ffffffff810b2de3>] ? try_to_wake_up+0x103/0x430
[<ffffffffa063d200>] open_ctree+0x1bd0/0x2130 [btrfs]
[<ffffffffa060fdde>] btrfs_mount+0x62e/0x8b0 [btrfs]
[<ffffffff811fd9da>] ? alloc_pages_current+0x11a/0x1f0
[<ffffffff811b0a5e>] ? __get_free_pages+0xe/0x50
[<ffffffff81230429>] mount_fs+0x39/0x1b0
[<ffffffff812509fb>] vfs_kern_mount+0x6b/0x150
[<ffffffff812537fb>] do_mount+0x27b/0xc30
[<ffffffff811b0a5e>] ? __get_free_pages+0xe/0x50
[<ffffffff812544f6>] SyS_mount+0x96/0xf0
[<ffffffff81701970>] 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 <wangshilong1991@gmail.com>
Signed-off-by: Chris Mason <clm@fb.com>
fs/btrfs/check-integrity.c

index cb7f3fe9c9f6ff21bacffd3ab5a4a2bc7eccf1f0..66e820f7b44020d0240a0510f02178471ab9827a 100644 (file)
@@ -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);
 }