]> git.proxmox.com Git - mirror_spl-debian.git/commitdiff
Detect kernels that honor gfp flags passed to vmalloc()
authorRichard Yao <ryao@cs.stonybrook.edu>
Thu, 7 Jun 2012 02:38:12 +0000 (22:38 -0400)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Wed, 11 Jul 2012 18:44:27 +0000 (11:44 -0700)
zfsonlinux/spl@2092cf68d89a51eb0d6193aeadabb579dfc4b4a0 used
PF_MEMALLOC to workaround a bug in the Linux kernel where
allocations did not honor the gfp flags passed to vmalloc().
Unfortunately, PF_MEMALLOC has the side effect of permitting
allocations to allocate pages outside of ZONE_NORMAL. This
has been observed to result in the depletion of ZONE_DMA32.

A kernel patch is available in the Gentoo bug tracker for
this issue.

  https://bugs.gentoo.org/show_bug.cgi?id=416685

This negates any benefit PF_MEMALLOC provides, so we introduce
an autotools check to disable the use of PF_MEMALLOC on
systems with patched kernels.

Signed-off-by: Richard Yao <ryao@cs.stonybrook.edu>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #126

config/spl-build.m4
configure
module/spl/spl-kmem.c
spl_config.h.in

index 4d02a72ec51a927f122486303b06f6397815c3e1..c28ad0bf2a60dc7fcb760e5cbac44cba287bb5ce 100644 (file)
@@ -88,6 +88,7 @@ AC_DEFUN([SPL_AC_CONFIG_KERNEL], [
        SPL_AC_2ARGS_ZLIB_DEFLATE_WORKSPACESIZE
        SPL_AC_SHRINK_CONTROL_STRUCT
        SPL_AC_RWSEM_SPINLOCK_IS_RAW
+       SPL_AC_PMD_ALLOC_WITH_MASK
 ])
 
 AC_DEFUN([SPL_AC_MODULE_SYMVERS], [
@@ -2079,3 +2080,38 @@ AC_DEFUN([SPL_AC_RWSEM_SPINLOCK_IS_RAW], [
        ])
        EXTRA_KCFLAGS="$tmp_flags"
 ])
+
+dnl #
+dnl # Proposed VM Subsystem Bug Fix
+dnl # https://bugs.gentoo.org/show_bug.cgi?id=416685
+dnl #
+dnl # Make __pte_alloc_kernel() honor gfp flags passed to vmalloc()
+dnl # This is detected by checking a macro that is changed to support this.
+dnl #
+AC_DEFUN([SPL_AC_PMD_ALLOC_WITH_MASK], [
+       AC_MSG_CHECKING([whether pmd_alloc_with_mask exists])
+       SPL_LINUX_TRY_COMPILE([
+               #if !defined(CONFIG_MMU)
+               #define CONFIG_MMU
+               #endif
+
+               #if defined(RCH_HAS_4LEVEL_HACK)
+               #undef RCH_HAS_4LEVEL_HACK
+               #endif
+
+               #include <linux/mm.h>
+       ],[
+               struct mm_struct init_mm;
+               pud_t *pud = NULL;
+               unsigned long addr = 0;
+               gfp_t gfp_mask = GFP_KERNEL;
+
+               pmd_alloc_with_mask(&init_mm, pud, addr, gfp_mask);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_PMD_ALLOC_WITH_MASK, 1,
+                         [pmd_alloc_with_mask exists])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
index 761fdc1ccce7c67f366ca26a55f1c2711980242a..2a50279839a47cfdb441877af9fa2b6b0df8a042 100755 (executable)
--- a/configure
+++ b/configure
 
        EXTRA_KCFLAGS="$tmp_flags"
 
+
+       { $as_echo "$as_me:$LINENO: checking whether pmd_alloc_with_mask exists" >&5
+$as_echo_n "checking whether pmd_alloc_with_mask exists... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+
+               #if !defined(CONFIG_MMU)
+               #define CONFIG_MMU
+               #endif
+
+               #if defined(RCH_HAS_4LEVEL_HACK)
+               #undef RCH_HAS_4LEVEL_HACK
+               #endif
+
+               #include <linux/mm.h>
+
+int
+main (void)
+{
+
+               struct mm_struct init_mm;
+               pud_t *pud = NULL;
+               unsigned long addr = 0;
+               gfp_t gfp_mask = GFP_KERNEL;
+
+               pmd_alloc_with_mask(&init_mm, pud, addr, gfp_mask);
+
+  ;
+  return 0;
+}
+
+_ACEOF
+
+
+       rm -Rf build && mkdir -p build
+       echo "obj-m := conftest.o" >build/Makefile
+       if { ac_try='cp conftest.c build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } >/dev/null && { ac_try='test -s build/conftest.o'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+
+               { $as_echo "$as_me:$LINENO: result: yes" >&5
+$as_echo "yes" >&6; }
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_PMD_ALLOC_WITH_MASK 1
+_ACEOF
+
+
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+               { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+
+
+
+fi
+
+       rm -Rf build
+
+
+
  ;;
                 user)      ;;
                 all)
        EXTRA_KCFLAGS="$tmp_flags"
 
 
+       { $as_echo "$as_me:$LINENO: checking whether pmd_alloc_with_mask exists" >&5
+$as_echo_n "checking whether pmd_alloc_with_mask exists... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+
+               #if !defined(CONFIG_MMU)
+               #define CONFIG_MMU
+               #endif
+
+               #if defined(RCH_HAS_4LEVEL_HACK)
+               #undef RCH_HAS_4LEVEL_HACK
+               #endif
+
+               #include <linux/mm.h>
+
+int
+main (void)
+{
+
+               struct mm_struct init_mm;
+               pud_t *pud = NULL;
+               unsigned long addr = 0;
+               gfp_t gfp_mask = GFP_KERNEL;
+
+               pmd_alloc_with_mask(&init_mm, pud, addr, gfp_mask);
+
+  ;
+  return 0;
+}
+
+_ACEOF
+
+
+       rm -Rf build && mkdir -p build
+       echo "obj-m := conftest.o" >build/Makefile
+       if { ac_try='cp conftest.c build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } >/dev/null && { ac_try='test -s build/conftest.o'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+
+               { $as_echo "$as_me:$LINENO: result: yes" >&5
+$as_echo "yes" >&6; }
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_PMD_ALLOC_WITH_MASK 1
+_ACEOF
+
+
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+               { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+
+
+
+fi
+
+       rm -Rf build
+
+
+
+
                            ;;
                srpm)                        ;;
                 *)
index a6d09f9a25752681c8f5fc1c4b2b62b3c655bebb..80c4ff4b9fcdfad80f7df71db989d87551a5fcad 100644 (file)
@@ -843,6 +843,9 @@ kv_alloc(spl_kmem_cache_t *skc, int size, int flags)
        if (skc->skc_flags & KMC_KMEM) {
                ptr = (void *)__get_free_pages(flags, get_order(size));
        } else {
+#ifdef HAVE_PMD_ALLOC_WITH_MASK
+               ptr = __vmalloc(size, flags|__GFP_HIGHMEM, PAGE_KERNEL);
+#else
                /*
                 * As part of vmalloc() an __pte_alloc_kernel() allocation
                 * may occur.  This internal allocation does not honor the
@@ -866,6 +869,7 @@ kv_alloc(spl_kmem_cache_t *skc, int size, int flags)
                } else {
                        ptr = __vmalloc(size, flags|__GFP_HIGHMEM, PAGE_KERNEL);
                }
+#endif
        }
 
        /* Resulting allocated memory will be page aligned */
index 92c11df26b7c3e1535ff6ff60cd1bcb4f86fdcce..1b4a129b2e7d989093d56a943cf690447e573ab3 100644 (file)
 /* pgdat_list is available */
 #undef HAVE_PGDAT_LIST
 
+/* pmd_alloc_with_mask exists */
+#undef HAVE_PMD_ALLOC_WITH_MASK
+
 /* __put_task_struct() is available */
 #undef HAVE_PUT_TASK_STRUCT