summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Yao <[email protected]>2012-06-06 22:38:12 -0400
committerBrian Behlendorf <[email protected]>2012-07-11 11:44:27 -0700
commit36811b4430aaea8c8b91bbe7d812a26799865499 (patch)
treeb61719801e34ed403f48987c7f557a047639424f
parent973e8269bd99f9440149892d598f8914113d0278 (diff)
Detect kernels that honor gfp flags passed to vmalloc()
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 <[email protected]> Signed-off-by: Brian Behlendorf <[email protected]> Closes #126
-rw-r--r--config/spl-build.m436
-rwxr-xr-xconfigure156
-rw-r--r--module/spl/spl-kmem.c4
-rw-r--r--spl_config.h.in3
4 files changed, 199 insertions, 0 deletions
diff --git a/config/spl-build.m4 b/config/spl-build.m4
index 4d02a72ec..c28ad0bf2 100644
--- a/config/spl-build.m4
+++ b/config/spl-build.m4
@@ -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)
+ ])
+])
diff --git a/configure b/configure
index 761fdc1cc..2a5027983 100755
--- a/configure
+++ b/configure
@@ -16231,6 +16231,84 @@ fi
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)
@@ -20730,6 +20808,84 @@ fi
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) ;;
*)
diff --git a/module/spl/spl-kmem.c b/module/spl/spl-kmem.c
index a6d09f9a2..80c4ff4b9 100644
--- a/module/spl/spl-kmem.c
+++ b/module/spl/spl-kmem.c
@@ -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 */
diff --git a/spl_config.h.in b/spl_config.h.in
index 92c11df26..1b4a129b2 100644
--- a/spl_config.h.in
+++ b/spl_config.h.in
@@ -165,6 +165,9 @@
/* 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