]> granicus.if.org Git - zfs/commitdiff
Disable vmalloc() direct reclaim
authorBrian Behlendorf <behlendorf1@llnl.gov>
Sun, 20 Mar 2011 22:03:18 +0000 (15:03 -0700)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Sun, 20 Mar 2011 22:12:08 +0000 (15:12 -0700)
As part of vmalloc() a __pte_alloc_kernel() allocation may occur.  This
internal allocation does not honor the gfp flags passed to vmalloc().
This means even when vmalloc(GFP_NOFS) is called it is possible that a
synchronous reclaim will occur.  This reclaim can trigger file IO which
can result in a deadlock.  This issue can be avoided by explicitly
setting PF_MEMALLOC on the process to subvert synchronous reclaim when
vmalloc() is called with !__GFP_FS.

An example stack of the deadlock can be found here (1), along with the
upstream kernel bug (2), and the original bug discussion on the
linux-mm mailing list (3).  This code can be properly autoconf'ed
when the upstream bug is fixed.

1) http://github.com/behlendorf/zfs/issues/labels/Vmalloc#issue/133
2) http://bugzilla.kernel.org/show_bug.cgi?id=30702
3) http://marc.info/?l=linux-mm&m=128942194520631&w=4

module/spl/spl-kmem.c

index 100d674e57abfd8d36c252ad4f1b0602b528fc00..2f533bdf619b6f4f815d3e606aeb6084fb03a118 100644 (file)
@@ -842,11 +842,31 @@ kv_alloc(spl_kmem_cache_t *skc, int size, int flags)
 
        ASSERT(ISP2(size));
 
-       if (skc->skc_flags & KMC_KMEM)
+       if (skc->skc_flags & KMC_KMEM) {
                ptr = (void *)__get_free_pages(flags, get_order(size));
-       else
+       } else {
+               /*
+                * As part of vmalloc() an __pte_alloc_kernel() allocation
+                * may occur.  This internal allocation does not honor the
+                * gfp flags passed to vmalloc().  This means even when
+                * vmalloc(GFP_NOFS) is called it is possible synchronous
+                * reclaim will occur.  This reclaim can trigger file IO
+                * which can result in a deadlock.  This issue can be avoided
+                * by explicitly setting PF_MEMALLOC on the process to
+                * subvert synchronous reclaim.  The following bug has
+                * been filed at kernel.org to track the issue.
+                *
+                * https://bugzilla.kernel.org/show_bug.cgi?id=30702
+                */
+               if (!(flags & __GFP_FS))
+                       current->flags |= PF_MEMALLOC;
+
                ptr = __vmalloc(size, flags | __GFP_HIGHMEM, PAGE_KERNEL);
 
+               if (!(flags & __GFP_FS))
+                       current->flags &= ~PF_MEMALLOC;
+       }
+
        /* Resulting allocated memory will be page aligned */
        ASSERT(IS_P2ALIGNED(ptr, PAGE_SIZE));