Skip to content
This repository has been archived by the owner on Feb 26, 2020. It is now read-only.

Commit

Permalink
Detect kernels that honor gfp flags passed to vmalloc()
Browse files Browse the repository at this point in the history
2092cf6 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
  • Loading branch information
ryao authored and behlendorf committed Jul 11, 2012
1 parent 973e826 commit 36811b4
Show file tree
Hide file tree
Showing 4 changed files with 199 additions and 0 deletions.
36 changes: 36 additions & 0 deletions config/spl-build.m4
Original file line number Diff line number Diff line change
Expand Up @@ -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], [
Expand Down Expand Up @@ -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)
])
])
156 changes: 156 additions & 0 deletions configure
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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) ;;
*)
Expand Down
4 changes: 4 additions & 0 deletions module/spl/spl-kmem.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 */
Expand Down
3 changes: 3 additions & 0 deletions spl_config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down

0 comments on commit 36811b4

Please sign in to comment.