forked from openzfs/zfs
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix free memory calculation on v3.14+
Provide infrastructure to auto-configure to enum and API changes in the global page stats used for our free memory calculations. arc_free_memory has been broken since an API change in Linux v3.14: 2016-07-28 v4.8 599d0c95 mm, vmscan: move LRU lists to node 2016-07-28 v4.8 75ef7184 mm, vmstat: add infrastructure for per-node vmstats These commits moved some of global_page_state() into global_node_page_state(). The API change was particularly egregious as, instead of breaking the old code, it silently did the wrong thing and we continued using global_page_state() where we should have been using global_node_page_state(), thus indexing into the wrong array via NR_SLAB_RECLAIMABLE et al. There have been further API changes along the way: 2017-07-06 v4.13 385386cf mm: vmstat: move slab statistics from zone to node counters 2017-09-06 v4.14 c41f012a mm: rename global_page_state to global_zone_page_state ...and various (incomplete, as it turns out) attempts to accomodate these changes in ZoL: 2017-08-24 2209e40 Linux 4.8+ compatibility fix for vm stats 2017-09-16 787acae Linux 3.14 compat: IO acct, global_page_state, etc 2017-09-19 661907e Linux 4.14 compat: IO acct, global_page_state, etc The config infrastructure provided here resolves these issues going back to the original API change in v3.14 and is robust against further Linux changes in this area. Reviewed-by: Giuseppe Di Natale <[email protected]> Reviewed-by: Brian Behlendorf <[email protected]> Reviewed-by: George Melikov <[email protected]> Signed-off-by: Chris Dunlop <[email protected]> Closes openzfs#7170
- Loading branch information
1 parent
5767323
commit c82dc52
Showing
8 changed files
with
256 additions
and
41 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
dnl # | ||
dnl # 4.8 API change | ||
dnl # | ||
dnl # 75ef71840539 mm, vmstat: add infrastructure for per-node vmstats | ||
dnl # 599d0c954f91 mm, vmscan: move LRU lists to node | ||
dnl # | ||
AC_DEFUN([ZFS_AC_KERNEL_GLOBAL_NODE_PAGE_STATE], [ | ||
AC_MSG_CHECKING([whether global_node_page_state() exists]) | ||
ZFS_LINUX_TRY_COMPILE([ | ||
#include <linux/mm.h> | ||
#include <linux/vmstat.h> | ||
],[ | ||
(void) global_node_page_state(0); | ||
],[ | ||
AC_MSG_RESULT(yes) | ||
AC_DEFINE(ZFS_GLOBAL_NODE_PAGE_STATE, 1, [global_node_page_state() exists]) | ||
],[ | ||
AC_MSG_RESULT(no) | ||
]) | ||
]) | ||
|
||
dnl # | ||
dnl # 4.14 API change | ||
dnl # | ||
dnl # c41f012ade0b mm: rename global_page_state to global_zone_page_state | ||
dnl # | ||
AC_DEFUN([ZFS_AC_KERNEL_GLOBAL_ZONE_PAGE_STATE], [ | ||
AC_MSG_CHECKING([whether global_zone_page_state() exists]) | ||
ZFS_LINUX_TRY_COMPILE([ | ||
#include <linux/mm.h> | ||
#include <linux/vmstat.h> | ||
],[ | ||
(void) global_zone_page_state(0); | ||
],[ | ||
AC_MSG_RESULT(yes) | ||
AC_DEFINE(ZFS_GLOBAL_ZONE_PAGE_STATE, 1, [global_zone_page_state() exists]) | ||
],[ | ||
AC_MSG_RESULT(no) | ||
]) | ||
]) | ||
|
||
dnl # | ||
dnl # Create a define and autoconf variable for an enum member | ||
dnl # | ||
AC_DEFUN([ZFS_AC_KERNEL_ENUM_MEMBER], [ | ||
AC_MSG_CHECKING([whether enum $2 contains $1]) | ||
AS_IF([AC_TRY_COMMAND("${srcdir}/scripts/enum-extract.pl" "$2" "$3" | egrep -qx $1)],[ | ||
AC_MSG_RESULT([yes]) | ||
AC_DEFINE(m4_join([_], [ZFS_ENUM], m4_toupper($2), $1), 1, [enum $2 contains $1]) | ||
m4_join([_], [ZFS_ENUM], m4_toupper($2), $1)=1 | ||
],[ | ||
AC_MSG_RESULT([no]) | ||
]) | ||
]) | ||
|
||
dnl # | ||
dnl # Sanity check helpers | ||
dnl # | ||
AC_DEFUN([ZFS_AC_KERNEL_GLOBAL_PAGE_STATE_ENUM_ERROR],[ | ||
AC_MSG_RESULT(no) | ||
AC_MSG_RESULT([$1 in either node_stat_item or zone_stat_item: $2]) | ||
AC_MSG_RESULT([configure needs updating, see: config/kernel-global_page_state.m4]) | ||
AC_MSG_FAILURE([SHUT 'ER DOWN CLANCY, SHE'S PUMPIN' MUD!]) | ||
]) | ||
|
||
AC_DEFUN([ZFS_AC_KERNEL_GLOBAL_PAGE_STATE_ENUM_CHECK], [ | ||
enum_check_a="m4_join([_], [$ZFS_ENUM_NODE_STAT_ITEM], $1)" | ||
enum_check_b="m4_join([_], [$ZFS_ENUM_ZONE_STAT_ITEM], $1)" | ||
AS_IF([test -n "$enum_check_a" -a -n "$enum_check_b"],[ | ||
ZFS_AC_KERNEL_GLOBAL_PAGE_STATE_ENUM_ERROR([$1], [DUPLICATE]) | ||
]) | ||
AS_IF([test -z "$enum_check_a" -a -z "$enum_check_b"],[ | ||
ZFS_AC_KERNEL_GLOBAL_PAGE_STATE_ENUM_ERROR([$1], [NOT FOUND]) | ||
]) | ||
]) | ||
|
||
dnl # | ||
dnl # Ensure the config tests are finding one and only one of each enum of interest | ||
dnl # | ||
AC_DEFUN([ZFS_AC_KERNEL_GLOBAL_ZONE_PAGE_STATE_SANITY], [ | ||
AC_MSG_CHECKING([global_page_state enums are sane]) | ||
ZFS_AC_KERNEL_GLOBAL_PAGE_STATE_ENUM_CHECK([NR_FILE_PAGES]) | ||
ZFS_AC_KERNEL_GLOBAL_PAGE_STATE_ENUM_CHECK([NR_INACTIVE_ANON]) | ||
ZFS_AC_KERNEL_GLOBAL_PAGE_STATE_ENUM_CHECK([NR_INACTIVE_FILE]) | ||
ZFS_AC_KERNEL_GLOBAL_PAGE_STATE_ENUM_CHECK([NR_SLAB_RECLAIMABLE]) | ||
AC_MSG_RESULT(yes) | ||
]) | ||
|
||
dnl # | ||
dnl # enum members in which we're interested | ||
dnl # | ||
AC_DEFUN([ZFS_AC_KERNEL_GLOBAL_PAGE_STATE], [ | ||
ZFS_AC_KERNEL_GLOBAL_NODE_PAGE_STATE | ||
ZFS_AC_KERNEL_GLOBAL_ZONE_PAGE_STATE | ||
ZFS_AC_KERNEL_ENUM_MEMBER([NR_FILE_PAGES], [node_stat_item], [$LINUX/include/linux/mmzone.h]) | ||
ZFS_AC_KERNEL_ENUM_MEMBER([NR_INACTIVE_ANON], [node_stat_item], [$LINUX/include/linux/mmzone.h]) | ||
ZFS_AC_KERNEL_ENUM_MEMBER([NR_INACTIVE_FILE], [node_stat_item], [$LINUX/include/linux/mmzone.h]) | ||
ZFS_AC_KERNEL_ENUM_MEMBER([NR_SLAB_RECLAIMABLE], [node_stat_item], [$LINUX/include/linux/mmzone.h]) | ||
ZFS_AC_KERNEL_ENUM_MEMBER([NR_FILE_PAGES], [zone_stat_item], [$LINUX/include/linux/mmzone.h]) | ||
ZFS_AC_KERNEL_ENUM_MEMBER([NR_INACTIVE_ANON], [zone_stat_item], [$LINUX/include/linux/mmzone.h]) | ||
ZFS_AC_KERNEL_ENUM_MEMBER([NR_INACTIVE_FILE], [zone_stat_item], [$LINUX/include/linux/mmzone.h]) | ||
ZFS_AC_KERNEL_ENUM_MEMBER([NR_SLAB_RECLAIMABLE], [zone_stat_item], [$LINUX/include/linux/mmzone.h]) | ||
ZFS_AC_KERNEL_GLOBAL_ZONE_PAGE_STATE_SANITY | ||
]) |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
#ifndef _ZFS_PAGE_COMPAT_H | ||
#define _ZFS_PAGE_COMPAT_H | ||
|
||
/* | ||
* We have various enum members moving between two separate enum types, | ||
* and accessed by different functions at various times. Centralise the | ||
* insanity. | ||
* | ||
* < v4.8: all enums in zone_stat_item, via global_page_state() | ||
* v4.8: some enums moved to node_stat_item, global_node_page_state() introduced | ||
* v4.13: some enums moved from zone_stat_item to node_state_item | ||
* v4.14: global_page_state() rename to global_zone_page_state() | ||
* | ||
* The defines used here are created by config/kernel-global_page_state.m4 | ||
*/ | ||
|
||
/* | ||
* Create our own accessor functions to follow the Linux API changes | ||
*/ | ||
#if defined(ZFS_GLOBAL_ZONE_PAGE_STATE) | ||
|
||
/* global_zone_page_state() introduced */ | ||
#if defined(ZFS_ENUM_NODE_STAT_ITEM_NR_FILE_PAGES) | ||
#define nr_file_pages() global_node_page_state(NR_FILE_PAGES) | ||
#else | ||
#define nr_file_pages() global_zone_page_state(NR_FILE_PAGES) | ||
#endif | ||
#if defined(ZFS_ENUM_NODE_STAT_ITEM_NR_INACTIVE_ANON) | ||
#define nr_inactive_anon_pages() global_node_page_state(NR_INACTIVE_ANON) | ||
#else | ||
#define nr_inactive_anon_pages() global_zone_page_state(NR_INACTIVE_ANON) | ||
#endif | ||
#if defined(ZFS_ENUM_NODE_STAT_ITEM_NR_INACTIVE_FILE) | ||
#define nr_inactive_file_pages() global_node_page_state(NR_INACTIVE_FILE) | ||
#else | ||
#define nr_inactive_file_pages() global_zone_page_state(NR_INACTIVE_FILE) | ||
#endif | ||
#if defined(ZFS_ENUM_NODE_STAT_ITEM_NR_SLAB_RECLAIMABLE) | ||
#define nr_slab_reclaimable_pages() global_node_page_state(NR_SLAB_RECLAIMABLE) | ||
#else | ||
#define nr_slab_reclaimable_pages() global_zone_page_state(NR_SLAB_RECLAIMABLE) | ||
#endif | ||
|
||
#elif defined(ZFS_GLOBAL_NODE_PAGE_STATE) | ||
|
||
/* global_node_page_state() introduced */ | ||
#if defined(ZFS_ENUM_NODE_STAT_ITEM_NR_FILE_PAGES) | ||
#define nr_file_pages() global_node_page_state(NR_FILE_PAGES) | ||
#else | ||
#define nr_file_pages() global_page_state(NR_FILE_PAGES) | ||
#endif | ||
#if defined(ZFS_ENUM_NODE_STAT_ITEM_NR_INACTIVE_ANON) | ||
#define nr_inactive_anon_pages() global_node_page_state(NR_INACTIVE_ANON) | ||
#else | ||
#define nr_inactive_anon_pages() global_page_state(NR_INACTIVE_ANON) | ||
#endif | ||
#if defined(ZFS_ENUM_NODE_STAT_ITEM_NR_INACTIVE_FILE) | ||
#define nr_inactive_file_pages() global_node_page_state(NR_INACTIVE_FILE) | ||
#else | ||
#define nr_inactive_file_pages() global_page_state(NR_INACTIVE_FILE) | ||
#endif | ||
#if defined(ZFS_ENUM_NODE_STAT_ITEM_NR_SLAB_RECLAIMABLE) | ||
#define nr_slab_reclaimable_pages() global_node_page_state(NR_SLAB_RECLAIMABLE) | ||
#else | ||
#define nr_slab_reclaimable_pages() global_page_state(NR_SLAB_RECLAIMABLE) | ||
#endif | ||
|
||
#else | ||
|
||
/* global_page_state() only */ | ||
#define nr_file_pages() global_page_state(NR_FILE_PAGES) | ||
#define nr_inactive_anon_pages() global_page_state(NR_INACTIVE_ANON) | ||
#define nr_inactive_file_pages() global_page_state(NR_INACTIVE_FILE) | ||
#define nr_slab_reclaimable_pages() global_page_state(NR_SLAB_RECLAIMABLE) | ||
|
||
#endif /* ZFS_GLOBAL_ZONE_PAGE_STATE */ | ||
|
||
#endif /* _ZFS_PAGE_COMPAT_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
#!/usr/bin/perl -w | ||
|
||
my $usage = <<EOT; | ||
usage: config-enum enum [file ...] | ||
Returns the elements from an enum declaration. | ||
"Best effort": we're not building an entire C interpreter here! | ||
EOT | ||
|
||
use warnings; | ||
use strict; | ||
use Getopt::Std; | ||
|
||
my %opts; | ||
|
||
if (!getopts("", \%opts) || @ARGV < 1) { | ||
print $usage; | ||
exit 2; | ||
} | ||
|
||
my $enum = shift; | ||
|
||
my $in_enum = 0; | ||
|
||
while (<>) { | ||
# comments | ||
s/\/\*.*\*\///; | ||
if (m/\/\*/) { | ||
while ($_ .= <>) { | ||
last if s/\/\*.*\*\///s; | ||
} | ||
} | ||
|
||
# preprocessor stuff | ||
next if /^#/; | ||
|
||
# find our enum | ||
$in_enum = 1 if s/^\s*enum\s+${enum}(?:\s|$)//; | ||
next unless $in_enum; | ||
|
||
# remove explicit values | ||
s/\s*=[^,]+,/,/g; | ||
|
||
# extract each identifier | ||
while (m/\b([a-z_][a-z0-9_]*)\b/ig) { | ||
print $1, "\n"; | ||
} | ||
|
||
# | ||
# don't exit: there may be multiple versions of the same enum, e.g. | ||
# inside different #ifdef blocks. Let's explicitly return all of | ||
# them and let external tooling deal with it. | ||
# | ||
$in_enum = 0 if m/}\s*;/; | ||
} | ||
|
||
exit 0; |