Skip to content

Commit

Permalink
Fix free memory calculation on v3.14+
Browse files Browse the repository at this point in the history
arc_free_memory has been broken since an API change in Linux v3.14:

2016-07-28 599d0c95 mm, vmscan: move LRU lists to node

That 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.

This was /nearly/ fixed in ZoL by:

2017-08-24 2209e40 Linux 4.8+ compatibility fix for vm stats

...which put in place the config infrastructure to detect the API change
and fix an instance of NR_FILE_PAGES in arc_evictable_memory().
Unfortunately the free memory calculation at that time was done in SPL
freemem, and the API fix wasn't applied to the SPL. As a result our free
memory calculation remained broken until it was again /nearly/ fixed by:

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

These two patches copy SPL freemem to arc_free_memory() and do the
global_node_page_state() split, /almost/ correctly...

Unfortunately they assume NR_SLAB_RECLAIMABLE moved to
global_node_page_state() along with NR_INACTIVE_FILE and
NR_INACTIVE_ANON, but NR_SLAB_RECLAIMABLE actually stayed in
global_page_state(), thus leaving our free memory calculation broken for
19 months on Linux v3.14+ - until now!

Additionally, Linux 4.14 changes global_page_state() to
global_zone_page_state(), so fix that as well

Signed-off-by: Chris Dunlop <chris@onthe.net.au>
  • Loading branch information
chrisrd committed Feb 14, 2018
1 parent 9c5167d commit 599e398
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 1 deletion.
21 changes: 21 additions & 0 deletions config/kernel-global_zone_page_state.m4
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
dnl #
dnl # 4.14 API change
dnl #
dnl # linux 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 to use global_zone_page_state])
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,
[using global_zone_page_state()])
],[
AC_MSG_RESULT(no)
])
])
1 change: 1 addition & 0 deletions config/kernel.m4
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ AC_DEFUN([ZFS_AC_CONFIG_KERNEL], [
ZFS_AC_KERNEL_HAVE_GENERIC_SETXATTR
ZFS_AC_KERNEL_CURRENT_TIME
ZFS_AC_KERNEL_VM_NODE_STAT
ZFS_AC_KERNEL_GLOBAL_ZONE_PAGE_STATE
AS_IF([test "$LINUX_OBJ" != "$LINUX"], [
KERNEL_MAKE="$KERNEL_MAKE O=$LINUX_OBJ"
Expand Down
8 changes: 7 additions & 1 deletion module/zfs/arc.c
Original file line number Diff line number Diff line change
Expand Up @@ -4701,9 +4701,15 @@ arc_free_memory(void)
#else
#ifdef ZFS_GLOBAL_NODE_PAGE_STATE
return (ptob(nr_free_pages() +
/* node stats */
global_node_page_state(NR_INACTIVE_FILE) +
global_node_page_state(NR_INACTIVE_ANON) +
global_node_page_state(NR_SLAB_RECLAIMABLE)));
/* zone stats */
#ifdef ZFS_GLOBAL_ZONE_PAGE_STATE
global_zone_page_state(NR_SLAB_RECLAIMABLE)));
#else
global_page_state(NR_SLAB_RECLAIMABLE)));
#endif /* ZFS_GLOBAL_ZONE_PAGE_STATE */
#else
return (ptob(nr_free_pages() +
global_page_state(NR_INACTIVE_FILE) +
Expand Down

0 comments on commit 599e398

Please sign in to comment.