-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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. Signed-off-by: Chris Dunlop <chris@onthe.net.au>
- Loading branch information
Showing
7 changed files
with
247 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,69 @@ | ||
dnl # | ||
dnl # 4.8 API change | ||
dnl # kernel vm counters change | ||
dnl # | ||
AC_DEFUN([ZFS_AC_KERNEL_GLOBAL_NODE_PAGE_STATE], [ | ||
AC_MSG_CHECKING([whether global_none_page_state() exists]) | ||
ZFS_LINUX_TRY_COMPILE_SYMBOL([ | ||
#include <linux/mm.h> | ||
#include <linux/vmstat.h> | ||
],[ | ||
(void) global_node_page_state(0); | ||
], [global_node_page_state], [include/linux/vmstat.h], [ | ||
],[ | ||
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 (c41f012ade) | ||
dnl # 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_SYMBOL([ | ||
#include <linux/mm.h> | ||
#include <linux/vmstat.h> | ||
],[ | ||
(void) global_zone_page_state(0); | ||
], [global_zone_page_state], [include/linux/vmstat.h], [ | ||
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 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(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]) | ||
],[ | ||
AC_MSG_RESULT([no]) | ||
]) | ||
]) | ||
|
||
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]) | ||
]) |
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,111 @@ | ||
#ifndef _ZFS_MM_COMPAT_ZFS_H | ||
#define _ZFS_MM_COMPAT_ZFS_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() | ||
*/ | ||
|
||
/* | ||
* Ensure the config tests are finding one and only one of each enum of interest | ||
*/ | ||
#if defined(ZFS_ENUM_NODE_STAT_ITEM_NR_FILE_PAGES) && \ | ||
defined(ZFS_ENUM_ZONE_STAT_ITEM_NR_FILE_PAGES) | ||
#error NR_FILE_PAGES found in both node_stat_item and zone_stat_item | ||
#elif ! defined(ZFS_ENUM_NODE_STAT_ITEM_NR_FILE_PAGES) && \ | ||
! defined(ZFS_ENUM_ZONE_STAT_ITEM_NR_FILE_PAGES) | ||
#error NR_FILE_PAGES not found in either node_stat_item or zone_stat_item | ||
#endif | ||
|
||
#if defined(ZFS_ENUM_NODE_STAT_ITEM_NR_INACTIVE_ANON) && \ | ||
defined(ZFS_ENUM_ZONE_STAT_ITEM_NR_INACTIVE_ANON) | ||
#error NR_INACTIVE_ANON found in both node_stat_item and zone_stat_item | ||
#elif ! defined(ZFS_ENUM_NODE_STAT_ITEM_NR_INACTIVE_ANON) && \ | ||
! defined(ZFS_ENUM_ZONE_STAT_ITEM_NR_INACTIVE_ANON) | ||
#error NR_INACTIVE_ANON not found in either node_stat_item or zone_stat_item | ||
#endif | ||
|
||
#if defined(ZFS_ENUM_NODE_STAT_ITEM_NR_INACTIVE_FILE) && \ | ||
defined(ZFS_ENUM_ZONE_STAT_ITEM_NR_INACTIVE_FILE) | ||
#error NR_INACTIVE_FILE found in both node_stat_item and zone_stat_item | ||
#elif ! defined(ZFS_ENUM_NODE_STAT_ITEM_NR_INACTIVE_FILE) && \ | ||
! defined(ZFS_ENUM_ZONE_STAT_ITEM_NR_INACTIVE_FILE) | ||
#error NR_INACTIVE_FILE not found in either node_stat_item or zone_stat_item | ||
#endif | ||
|
||
#if defined(ZFS_ENUM_NODE_STAT_ITEM_NR_SLAB_RECLAIMABLE) && \ | ||
defined(ZFS_ENUM_ZONE_STAT_ITEM_NR_SLAB_RECLAIMABLE) | ||
#error NR_SLAB_RECLAIMABLE found in both node_stat_item and zone_stat_item | ||
#elif ! defined(ZFS_ENUM_NODE_STAT_ITEM_NR_SLAB_RECLAIMABLE) && \ | ||
! defined(ZFS_ENUM_ZONE_STAT_ITEM_NR_SLAB_RECLAIMABLE) | ||
#error NR_SLAB_RECLAIMABLE not found in either node_stat_item or zone_stat_item | ||
#endif | ||
|
||
/* | ||
* 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_zone() 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_MM_COMPAT_ZFS_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
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; |