Detect kernels that honor gfp flags passed to vmalloc()
zfsonlinux/spl@2092cf68d8 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
This commit is contained in:
parent
973e8269bd
commit
36811b4430
|
@ -88,6 +88,7 @@ AC_DEFUN([SPL_AC_CONFIG_KERNEL], [
|
||||||
SPL_AC_2ARGS_ZLIB_DEFLATE_WORKSPACESIZE
|
SPL_AC_2ARGS_ZLIB_DEFLATE_WORKSPACESIZE
|
||||||
SPL_AC_SHRINK_CONTROL_STRUCT
|
SPL_AC_SHRINK_CONTROL_STRUCT
|
||||||
SPL_AC_RWSEM_SPINLOCK_IS_RAW
|
SPL_AC_RWSEM_SPINLOCK_IS_RAW
|
||||||
|
SPL_AC_PMD_ALLOC_WITH_MASK
|
||||||
])
|
])
|
||||||
|
|
||||||
AC_DEFUN([SPL_AC_MODULE_SYMVERS], [
|
AC_DEFUN([SPL_AC_MODULE_SYMVERS], [
|
||||||
|
@ -2079,3 +2080,38 @@ AC_DEFUN([SPL_AC_RWSEM_SPINLOCK_IS_RAW], [
|
||||||
])
|
])
|
||||||
EXTRA_KCFLAGS="$tmp_flags"
|
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)
|
||||||
|
])
|
||||||
|
])
|
||||||
|
|
|
@ -16231,6 +16231,84 @@ fi
|
||||||
|
|
||||||
EXTRA_KCFLAGS="$tmp_flags"
|
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) ;;
|
user) ;;
|
||||||
all)
|
all)
|
||||||
|
@ -20730,6 +20808,84 @@ fi
|
||||||
EXTRA_KCFLAGS="$tmp_flags"
|
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) ;;
|
srpm) ;;
|
||||||
*)
|
*)
|
||||||
|
|
|
@ -843,6 +843,9 @@ kv_alloc(spl_kmem_cache_t *skc, int size, int flags)
|
||||||
if (skc->skc_flags & KMC_KMEM) {
|
if (skc->skc_flags & KMC_KMEM) {
|
||||||
ptr = (void *)__get_free_pages(flags, get_order(size));
|
ptr = (void *)__get_free_pages(flags, get_order(size));
|
||||||
} else {
|
} 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
|
* As part of vmalloc() an __pte_alloc_kernel() allocation
|
||||||
* may occur. This internal allocation does not honor the
|
* 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 {
|
} else {
|
||||||
ptr = __vmalloc(size, flags|__GFP_HIGHMEM, PAGE_KERNEL);
|
ptr = __vmalloc(size, flags|__GFP_HIGHMEM, PAGE_KERNEL);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Resulting allocated memory will be page aligned */
|
/* Resulting allocated memory will be page aligned */
|
||||||
|
|
|
@ -165,6 +165,9 @@
|
||||||
/* pgdat_list is available */
|
/* pgdat_list is available */
|
||||||
#undef HAVE_PGDAT_LIST
|
#undef HAVE_PGDAT_LIST
|
||||||
|
|
||||||
|
/* pmd_alloc_with_mask exists */
|
||||||
|
#undef HAVE_PMD_ALLOC_WITH_MASK
|
||||||
|
|
||||||
/* __put_task_struct() is available */
|
/* __put_task_struct() is available */
|
||||||
#undef HAVE_PUT_TASK_STRUCT
|
#undef HAVE_PUT_TASK_STRUCT
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue