--- /dev/null
+From 30d6e0a4190d37740e9447e4e4815f06992dd8c3 Mon Sep 17 00:00:00 2001
+From: Jiri Slaby <jslaby@suse.cz>
+Date: Thu, 24 Aug 2017 09:31:05 +0200
+Subject: futex: Remove duplicated code and fix undefined behaviour
+
+From: Jiri Slaby <jslaby@suse.cz>
+
+commit 30d6e0a4190d37740e9447e4e4815f06992dd8c3 upstream.
+
+There is code duplicated over all architecture's headers for
+futex_atomic_op_inuser. Namely op decoding, access_ok check for uaddr,
+and comparison of the result.
+
+Remove this duplication and leave up to the arches only the needed
+assembly which is now in arch_futex_atomic_op_inuser.
+
+This effectively distributes the Will Deacon's arm64 fix for undefined
+behaviour reported by UBSAN to all architectures. The fix was done in
+commit 5f16a046f8e1 (arm64: futex: Fix undefined behaviour with
+FUTEX_OP_OPARG_SHIFT usage). Look there for an example dump.
+
+And as suggested by Thomas, check for negative oparg too, because it was
+also reported to cause undefined behaviour report.
+
+Note that s390 removed access_ok check in d12a29703 ("s390/uaccess:
+remove pointless access_ok() checks") as access_ok there returns true.
+We introduce it back to the helper for the sake of simplicity (it gets
+optimized away anyway).
+
+Signed-off-by: Jiri Slaby <jslaby@suse.cz>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Acked-by: Russell King <rmk+kernel@armlinux.org.uk>
+Acked-by: Michael Ellerman <mpe@ellerman.id.au> (powerpc)
+Acked-by: Heiko Carstens <heiko.carstens@de.ibm.com> [s390]
+Acked-by: Chris Metcalf <cmetcalf@mellanox.com> [for tile]
+Reviewed-by: Darren Hart (VMware) <dvhart@infradead.org>
+Reviewed-by: Will Deacon <will.deacon@arm.com> [core/arm64]
+Cc: linux-mips@linux-mips.org
+Cc: Rich Felker <dalias@libc.org>
+Cc: linux-ia64@vger.kernel.org
+Cc: linux-sh@vger.kernel.org
+Cc: peterz@infradead.org
+Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
+Cc: Max Filippov <jcmvbkbc@gmail.com>
+Cc: Paul Mackerras <paulus@samba.org>
+Cc: sparclinux@vger.kernel.org
+Cc: Jonas Bonn <jonas@southpole.se>
+Cc: linux-s390@vger.kernel.org
+Cc: linux-arch@vger.kernel.org
+Cc: Yoshinori Sato <ysato@users.sourceforge.jp>
+Cc: linux-hexagon@vger.kernel.org
+Cc: Helge Deller <deller@gmx.de>
+Cc: "James E.J. Bottomley" <jejb@parisc-linux.org>
+Cc: Catalin Marinas <catalin.marinas@arm.com>
+Cc: Matt Turner <mattst88@gmail.com>
+Cc: linux-snps-arc@lists.infradead.org
+Cc: Fenghua Yu <fenghua.yu@intel.com>
+Cc: Arnd Bergmann <arnd@arndb.de>
+Cc: linux-xtensa@linux-xtensa.org
+Cc: Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
+Cc: openrisc@lists.librecores.org
+Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
+Cc: Stafford Horne <shorne@gmail.com>
+Cc: linux-arm-kernel@lists.infradead.org
+Cc: Richard Henderson <rth@twiddle.net>
+Cc: Chris Zankel <chris@zankel.net>
+Cc: Michal Simek <monstr@monstr.eu>
+Cc: Tony Luck <tony.luck@intel.com>
+Cc: linux-parisc@vger.kernel.org
+Cc: Vineet Gupta <vgupta@synopsys.com>
+Cc: Ralf Baechle <ralf@linux-mips.org>
+Cc: Richard Kuo <rkuo@codeaurora.org>
+Cc: linux-alpha@vger.kernel.org
+Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Cc: linuxppc-dev@lists.ozlabs.org
+Cc: "David S. Miller" <davem@davemloft.net>
+Link: http://lkml.kernel.org/r/20170824073105.3901-1-jslaby@suse.cz
+Cc: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/alpha/include/asm/futex.h | 26 +++---------------
+ arch/arc/include/asm/futex.h | 40 +++-------------------------
+ arch/arm/include/asm/futex.h | 26 ++----------------
+ arch/arm64/include/asm/futex.h | 27 ++-----------------
+ arch/frv/include/asm/futex.h | 3 +-
+ arch/frv/kernel/futex.c | 27 ++-----------------
+ arch/hexagon/include/asm/futex.h | 38 ++-------------------------
+ arch/ia64/include/asm/futex.h | 25 ++----------------
+ arch/microblaze/include/asm/futex.h | 38 ++-------------------------
+ arch/mips/include/asm/futex.h | 25 ++----------------
+ arch/parisc/include/asm/futex.h | 26 ++----------------
+ arch/powerpc/include/asm/futex.h | 26 +++---------------
+ arch/s390/include/asm/futex.h | 23 +++-------------
+ arch/sh/include/asm/futex.h | 26 ++----------------
+ arch/sparc/include/asm/futex_64.h | 26 +++---------------
+ arch/tile/include/asm/futex.h | 40 +++-------------------------
+ arch/x86/include/asm/futex.h | 40 +++-------------------------
+ arch/xtensa/include/asm/futex.h | 27 +++----------------
+ include/asm-generic/futex.h | 50 ++++++------------------------------
+ kernel/futex.c | 39 ++++++++++++++++++++++++++++
+ 20 files changed, 126 insertions(+), 472 deletions(-)
+
+--- a/arch/alpha/include/asm/futex.h
++++ b/arch/alpha/include/asm/futex.h
+@@ -29,18 +29,10 @@
+ : "r" (uaddr), "r"(oparg) \
+ : "memory")
+
+-static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
++static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
++ u32 __user *uaddr)
+ {
+- int op = (encoded_op >> 28) & 7;
+- int cmp = (encoded_op >> 24) & 15;
+- int oparg = (encoded_op << 8) >> 20;
+- int cmparg = (encoded_op << 20) >> 20;
+ int oldval = 0, ret;
+- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+- oparg = 1 << oparg;
+-
+- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
+- return -EFAULT;
+
+ pagefault_disable();
+
+@@ -66,17 +58,9 @@ static inline int futex_atomic_op_inuser
+
+ pagefault_enable();
+
+- if (!ret) {
+- switch (cmp) {
+- case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+- case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+- case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+- case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+- case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+- case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+- default: ret = -ENOSYS;
+- }
+- }
++ if (!ret)
++ *oval = oldval;
++
+ return ret;
+ }
+
+--- a/arch/arc/include/asm/futex.h
++++ b/arch/arc/include/asm/futex.h
+@@ -73,20 +73,11 @@
+
+ #endif
+
+-static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
++static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
++ u32 __user *uaddr)
+ {
+- int op = (encoded_op >> 28) & 7;
+- int cmp = (encoded_op >> 24) & 15;
+- int oparg = (encoded_op << 8) >> 20;
+- int cmparg = (encoded_op << 20) >> 20;
+ int oldval = 0, ret;
+
+- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+- oparg = 1 << oparg;
+-
+- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+- return -EFAULT;
+-
+ #ifndef CONFIG_ARC_HAS_LLSC
+ preempt_disable(); /* to guarantee atomic r-m-w of futex op */
+ #endif
+@@ -118,30 +109,9 @@ static inline int futex_atomic_op_inuser
+ preempt_enable();
+ #endif
+
+- if (!ret) {
+- switch (cmp) {
+- case FUTEX_OP_CMP_EQ:
+- ret = (oldval == cmparg);
+- break;
+- case FUTEX_OP_CMP_NE:
+- ret = (oldval != cmparg);
+- break;
+- case FUTEX_OP_CMP_LT:
+- ret = (oldval < cmparg);
+- break;
+- case FUTEX_OP_CMP_GE:
+- ret = (oldval >= cmparg);
+- break;
+- case FUTEX_OP_CMP_LE:
+- ret = (oldval <= cmparg);
+- break;
+- case FUTEX_OP_CMP_GT:
+- ret = (oldval > cmparg);
+- break;
+- default:
+- ret = -ENOSYS;
+- }
+- }
++ if (!ret)
++ *oval = oldval;
++
+ return ret;
+ }
+
+--- a/arch/arm/include/asm/futex.h
++++ b/arch/arm/include/asm/futex.h
+@@ -128,20 +128,10 @@ futex_atomic_cmpxchg_inatomic(u32 *uval,
+ #endif /* !SMP */
+
+ static inline int
+-futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
++arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
+ {
+- int op = (encoded_op >> 28) & 7;
+- int cmp = (encoded_op >> 24) & 15;
+- int oparg = (encoded_op << 8) >> 20;
+- int cmparg = (encoded_op << 20) >> 20;
+ int oldval = 0, ret, tmp;
+
+- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+- oparg = 1 << oparg;
+-
+- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
+- return -EFAULT;
+-
+ #ifndef CONFIG_SMP
+ preempt_disable();
+ #endif
+@@ -172,17 +162,9 @@ futex_atomic_op_inuser (int encoded_op,
+ preempt_enable();
+ #endif
+
+- if (!ret) {
+- switch (cmp) {
+- case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+- case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+- case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+- case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+- case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+- case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+- default: ret = -ENOSYS;
+- }
+- }
++ if (!ret)
++ *oval = oldval;
++
+ return ret;
+ }
+
+--- a/arch/arm64/include/asm/futex.h
++++ b/arch/arm64/include/asm/futex.h
+@@ -51,20 +51,9 @@
+ : "memory")
+
+ static inline int
+-futex_atomic_op_inuser(unsigned int encoded_op, u32 __user *_uaddr)
++arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
+ {
+- int op = (encoded_op >> 28) & 7;
+- int cmp = (encoded_op >> 24) & 15;
+- int oparg = (int)(encoded_op << 8) >> 20;
+- int cmparg = (int)(encoded_op << 20) >> 20;
+ int oldval = 0, ret, tmp;
+- u32 __user *uaddr = __uaccess_mask_ptr(_uaddr);
+-
+- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+- oparg = 1U << (oparg & 0x1f);
+-
+- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
+- return -EFAULT;
+
+ pagefault_disable();
+
+@@ -95,17 +84,9 @@ futex_atomic_op_inuser(unsigned int enco
+
+ pagefault_enable();
+
+- if (!ret) {
+- switch (cmp) {
+- case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+- case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+- case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+- case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+- case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+- case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+- default: ret = -ENOSYS;
+- }
+- }
++ if (!ret)
++ *oval = oldval;
++
+ return ret;
+ }
+
+--- a/arch/frv/include/asm/futex.h
++++ b/arch/frv/include/asm/futex.h
+@@ -7,7 +7,8 @@
+ #include <asm/errno.h>
+ #include <asm/uaccess.h>
+
+-extern int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr);
++extern int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
++ u32 __user *uaddr);
+
+ static inline int
+ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+--- a/arch/frv/kernel/futex.c
++++ b/arch/frv/kernel/futex.c
+@@ -186,20 +186,10 @@ static inline int atomic_futex_op_xchg_x
+ /*
+ * do the futex operations
+ */
+-int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
++int arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
+ {
+- int op = (encoded_op >> 28) & 7;
+- int cmp = (encoded_op >> 24) & 15;
+- int oparg = (encoded_op << 8) >> 20;
+- int cmparg = (encoded_op << 20) >> 20;
+ int oldval = 0, ret;
+
+- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+- oparg = 1 << oparg;
+-
+- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
+- return -EFAULT;
+-
+ pagefault_disable();
+
+ switch (op) {
+@@ -225,18 +215,9 @@ int futex_atomic_op_inuser(int encoded_o
+
+ pagefault_enable();
+
+- if (!ret) {
+- switch (cmp) {
+- case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+- case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+- case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+- case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+- case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+- case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+- default: ret = -ENOSYS; break;
+- }
+- }
++ if (!ret)
++ *oval = oldval;
+
+ return ret;
+
+-} /* end futex_atomic_op_inuser() */
++} /* end arch_futex_atomic_op_inuser() */
+--- a/arch/hexagon/include/asm/futex.h
++++ b/arch/hexagon/include/asm/futex.h
+@@ -31,18 +31,9 @@
+
+
+ static inline int
+-futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
++arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
+ {
+- int op = (encoded_op >> 28) & 7;
+- int cmp = (encoded_op >> 24) & 15;
+- int oparg = (encoded_op << 8) >> 20;
+- int cmparg = (encoded_op << 20) >> 20;
+ int oldval = 0, ret;
+- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+- oparg = 1 << oparg;
+-
+- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+- return -EFAULT;
+
+ pagefault_disable();
+
+@@ -72,30 +63,9 @@ futex_atomic_op_inuser(int encoded_op, i
+
+ pagefault_enable();
+
+- if (!ret) {
+- switch (cmp) {
+- case FUTEX_OP_CMP_EQ:
+- ret = (oldval == cmparg);
+- break;
+- case FUTEX_OP_CMP_NE:
+- ret = (oldval != cmparg);
+- break;
+- case FUTEX_OP_CMP_LT:
+- ret = (oldval < cmparg);
+- break;
+- case FUTEX_OP_CMP_GE:
+- ret = (oldval >= cmparg);
+- break;
+- case FUTEX_OP_CMP_LE:
+- ret = (oldval <= cmparg);
+- break;
+- case FUTEX_OP_CMP_GT:
+- ret = (oldval > cmparg);
+- break;
+- default:
+- ret = -ENOSYS;
+- }
+- }
++ if (!ret)
++ *oval = oldval;
++
+ return ret;
+ }
+
+--- a/arch/ia64/include/asm/futex.h
++++ b/arch/ia64/include/asm/futex.h
+@@ -45,18 +45,9 @@ do { \
+ } while (0)
+
+ static inline int
+-futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
++arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
+ {
+- int op = (encoded_op >> 28) & 7;
+- int cmp = (encoded_op >> 24) & 15;
+- int oparg = (encoded_op << 8) >> 20;
+- int cmparg = (encoded_op << 20) >> 20;
+ int oldval = 0, ret;
+- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+- oparg = 1 << oparg;
+-
+- if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
+- return -EFAULT;
+
+ pagefault_disable();
+
+@@ -84,17 +75,9 @@ futex_atomic_op_inuser (int encoded_op,
+
+ pagefault_enable();
+
+- if (!ret) {
+- switch (cmp) {
+- case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+- case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+- case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+- case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+- case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+- case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+- default: ret = -ENOSYS;
+- }
+- }
++ if (!ret)
++ *oval = oldval;
++
+ return ret;
+ }
+
+--- a/arch/microblaze/include/asm/futex.h
++++ b/arch/microblaze/include/asm/futex.h
+@@ -29,18 +29,9 @@
+ })
+
+ static inline int
+-futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
++arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
+ {
+- int op = (encoded_op >> 28) & 7;
+- int cmp = (encoded_op >> 24) & 15;
+- int oparg = (encoded_op << 8) >> 20;
+- int cmparg = (encoded_op << 20) >> 20;
+ int oldval = 0, ret;
+- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+- oparg = 1 << oparg;
+-
+- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
+- return -EFAULT;
+
+ pagefault_disable();
+
+@@ -66,30 +57,9 @@ futex_atomic_op_inuser(int encoded_op, u
+
+ pagefault_enable();
+
+- if (!ret) {
+- switch (cmp) {
+- case FUTEX_OP_CMP_EQ:
+- ret = (oldval == cmparg);
+- break;
+- case FUTEX_OP_CMP_NE:
+- ret = (oldval != cmparg);
+- break;
+- case FUTEX_OP_CMP_LT:
+- ret = (oldval < cmparg);
+- break;
+- case FUTEX_OP_CMP_GE:
+- ret = (oldval >= cmparg);
+- break;
+- case FUTEX_OP_CMP_LE:
+- ret = (oldval <= cmparg);
+- break;
+- case FUTEX_OP_CMP_GT:
+- ret = (oldval > cmparg);
+- break;
+- default:
+- ret = -ENOSYS;
+- }
+- }
++ if (!ret)
++ *oval = oldval;
++
+ return ret;
+ }
+
+--- a/arch/mips/include/asm/futex.h
++++ b/arch/mips/include/asm/futex.h
+@@ -83,18 +83,9 @@
+ }
+
+ static inline int
+-futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
++arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
+ {
+- int op = (encoded_op >> 28) & 7;
+- int cmp = (encoded_op >> 24) & 15;
+- int oparg = (encoded_op << 8) >> 20;
+- int cmparg = (encoded_op << 20) >> 20;
+ int oldval = 0, ret;
+- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+- oparg = 1 << oparg;
+-
+- if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
+- return -EFAULT;
+
+ pagefault_disable();
+
+@@ -125,17 +116,9 @@ futex_atomic_op_inuser(int encoded_op, u
+
+ pagefault_enable();
+
+- if (!ret) {
+- switch (cmp) {
+- case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+- case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+- case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+- case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+- case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+- case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+- default: ret = -ENOSYS;
+- }
+- }
++ if (!ret)
++ *oval = oldval;
++
+ return ret;
+ }
+
+--- a/arch/parisc/include/asm/futex.h
++++ b/arch/parisc/include/asm/futex.h
+@@ -32,22 +32,12 @@ _futex_spin_unlock_irqrestore(u32 __user
+ }
+
+ static inline int
+-futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
++arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
+ {
+ unsigned long int flags;
+- int op = (encoded_op >> 28) & 7;
+- int cmp = (encoded_op >> 24) & 15;
+- int oparg = (encoded_op << 8) >> 20;
+- int cmparg = (encoded_op << 20) >> 20;
+ int oldval, ret;
+ u32 tmp;
+
+- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+- oparg = 1 << oparg;
+-
+- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(*uaddr)))
+- return -EFAULT;
+-
+ _futex_spin_lock_irqsave(uaddr, &flags);
+ pagefault_disable();
+
+@@ -85,17 +75,9 @@ out_pagefault_enable:
+ pagefault_enable();
+ _futex_spin_unlock_irqrestore(uaddr, &flags);
+
+- if (ret == 0) {
+- switch (cmp) {
+- case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+- case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+- case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+- case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+- case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+- case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+- default: ret = -ENOSYS;
+- }
+- }
++ if (!ret)
++ *oval = oldval;
++
+ return ret;
+ }
+
+--- a/arch/powerpc/include/asm/futex.h
++++ b/arch/powerpc/include/asm/futex.h
+@@ -31,18 +31,10 @@
+ : "b" (uaddr), "i" (-EFAULT), "r" (oparg) \
+ : "cr0", "memory")
+
+-static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
++static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
++ u32 __user *uaddr)
+ {
+- int op = (encoded_op >> 28) & 7;
+- int cmp = (encoded_op >> 24) & 15;
+- int oparg = (encoded_op << 8) >> 20;
+- int cmparg = (encoded_op << 20) >> 20;
+ int oldval = 0, ret;
+- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+- oparg = 1 << oparg;
+-
+- if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
+- return -EFAULT;
+
+ pagefault_disable();
+
+@@ -68,17 +60,9 @@ static inline int futex_atomic_op_inuser
+
+ pagefault_enable();
+
+- if (!ret) {
+- switch (cmp) {
+- case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+- case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+- case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+- case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+- case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+- case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+- default: ret = -ENOSYS;
+- }
+- }
++ if (!ret)
++ *oval = oldval;
++
+ return ret;
+ }
+
+--- a/arch/s390/include/asm/futex.h
++++ b/arch/s390/include/asm/futex.h
+@@ -21,17 +21,12 @@
+ : "0" (-EFAULT), "d" (oparg), "a" (uaddr), \
+ "m" (*uaddr) : "cc");
+
+-static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
++static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
++ u32 __user *uaddr)
+ {
+- int op = (encoded_op >> 28) & 7;
+- int cmp = (encoded_op >> 24) & 15;
+- int oparg = (encoded_op << 8) >> 20;
+- int cmparg = (encoded_op << 20) >> 20;
+ int oldval = 0, newval, ret;
+
+ load_kernel_asce();
+- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+- oparg = 1 << oparg;
+
+ pagefault_disable();
+ switch (op) {
+@@ -60,17 +55,9 @@ static inline int futex_atomic_op_inuser
+ }
+ pagefault_enable();
+
+- if (!ret) {
+- switch (cmp) {
+- case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+- case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+- case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+- case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+- case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+- case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+- default: ret = -ENOSYS;
+- }
+- }
++ if (!ret)
++ *oval = oldval;
++
+ return ret;
+ }
+
+--- a/arch/sh/include/asm/futex.h
++++ b/arch/sh/include/asm/futex.h
+@@ -27,21 +27,12 @@ futex_atomic_cmpxchg_inatomic(u32 *uval,
+ return atomic_futex_op_cmpxchg_inatomic(uval, uaddr, oldval, newval);
+ }
+
+-static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
++static inline int arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval,
++ u32 __user *uaddr)
+ {
+- int op = (encoded_op >> 28) & 7;
+- int cmp = (encoded_op >> 24) & 15;
+- u32 oparg = (encoded_op << 8) >> 20;
+- u32 cmparg = (encoded_op << 20) >> 20;
+ u32 oldval, newval, prev;
+ int ret;
+
+- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+- oparg = 1 << oparg;
+-
+- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
+- return -EFAULT;
+-
+ pagefault_disable();
+
+ do {
+@@ -80,17 +71,8 @@ static inline int futex_atomic_op_inuser
+
+ pagefault_enable();
+
+- if (!ret) {
+- switch (cmp) {
+- case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+- case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+- case FUTEX_OP_CMP_LT: ret = ((int)oldval < (int)cmparg); break;
+- case FUTEX_OP_CMP_GE: ret = ((int)oldval >= (int)cmparg); break;
+- case FUTEX_OP_CMP_LE: ret = ((int)oldval <= (int)cmparg); break;
+- case FUTEX_OP_CMP_GT: ret = ((int)oldval > (int)cmparg); break;
+- default: ret = -ENOSYS;
+- }
+- }
++ if (!ret)
++ *oval = oldval;
+
+ return ret;
+ }
+--- a/arch/sparc/include/asm/futex_64.h
++++ b/arch/sparc/include/asm/futex_64.h
+@@ -29,22 +29,14 @@
+ : "r" (uaddr), "r" (oparg), "i" (-EFAULT) \
+ : "memory")
+
+-static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
++static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
++ u32 __user *uaddr)
+ {
+- int op = (encoded_op >> 28) & 7;
+- int cmp = (encoded_op >> 24) & 15;
+- int oparg = (encoded_op << 8) >> 20;
+- int cmparg = (encoded_op << 20) >> 20;
+ int oldval = 0, ret, tem;
+
+- if (unlikely(!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))))
+- return -EFAULT;
+ if (unlikely((((unsigned long) uaddr) & 0x3UL)))
+ return -EINVAL;
+
+- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+- oparg = 1 << oparg;
+-
+ pagefault_disable();
+
+ switch (op) {
+@@ -69,17 +61,9 @@ static inline int futex_atomic_op_inuser
+
+ pagefault_enable();
+
+- if (!ret) {
+- switch (cmp) {
+- case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+- case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+- case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+- case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+- case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+- case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+- default: ret = -ENOSYS;
+- }
+- }
++ if (!ret)
++ *oval = oldval;
++
+ return ret;
+ }
+
+--- a/arch/tile/include/asm/futex.h
++++ b/arch/tile/include/asm/futex.h
+@@ -106,12 +106,9 @@
+ lock = __atomic_hashed_lock((int __force *)uaddr)
+ #endif
+
+-static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
++static inline int arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval,
++ u32 __user *uaddr)
+ {
+- int op = (encoded_op >> 28) & 7;
+- int cmp = (encoded_op >> 24) & 15;
+- int oparg = (encoded_op << 8) >> 20;
+- int cmparg = (encoded_op << 20) >> 20;
+ int uninitialized_var(val), ret;
+
+ __futex_prolog();
+@@ -119,12 +116,6 @@ static inline int futex_atomic_op_inuser
+ /* The 32-bit futex code makes this assumption, so validate it here. */
+ BUILD_BUG_ON(sizeof(atomic_t) != sizeof(int));
+
+- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+- oparg = 1 << oparg;
+-
+- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
+- return -EFAULT;
+-
+ pagefault_disable();
+ switch (op) {
+ case FUTEX_OP_SET:
+@@ -148,30 +139,9 @@ static inline int futex_atomic_op_inuser
+ }
+ pagefault_enable();
+
+- if (!ret) {
+- switch (cmp) {
+- case FUTEX_OP_CMP_EQ:
+- ret = (val == cmparg);
+- break;
+- case FUTEX_OP_CMP_NE:
+- ret = (val != cmparg);
+- break;
+- case FUTEX_OP_CMP_LT:
+- ret = (val < cmparg);
+- break;
+- case FUTEX_OP_CMP_GE:
+- ret = (val >= cmparg);
+- break;
+- case FUTEX_OP_CMP_LE:
+- ret = (val <= cmparg);
+- break;
+- case FUTEX_OP_CMP_GT:
+- ret = (val > cmparg);
+- break;
+- default:
+- ret = -ENOSYS;
+- }
+- }
++ if (!ret)
++ *oval = val;
++
+ return ret;
+ }
+
+--- a/arch/x86/include/asm/futex.h
++++ b/arch/x86/include/asm/futex.h
+@@ -41,20 +41,11 @@
+ "+m" (*uaddr), "=&r" (tem) \
+ : "r" (oparg), "i" (-EFAULT), "1" (0))
+
+-static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
++static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
++ u32 __user *uaddr)
+ {
+- int op = (encoded_op >> 28) & 7;
+- int cmp = (encoded_op >> 24) & 15;
+- int oparg = (encoded_op << 8) >> 20;
+- int cmparg = (encoded_op << 20) >> 20;
+ int oldval = 0, ret, tem;
+
+- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+- oparg = 1 << oparg;
+-
+- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
+- return -EFAULT;
+-
+ pagefault_disable();
+
+ switch (op) {
+@@ -80,30 +71,9 @@ static inline int futex_atomic_op_inuser
+
+ pagefault_enable();
+
+- if (!ret) {
+- switch (cmp) {
+- case FUTEX_OP_CMP_EQ:
+- ret = (oldval == cmparg);
+- break;
+- case FUTEX_OP_CMP_NE:
+- ret = (oldval != cmparg);
+- break;
+- case FUTEX_OP_CMP_LT:
+- ret = (oldval < cmparg);
+- break;
+- case FUTEX_OP_CMP_GE:
+- ret = (oldval >= cmparg);
+- break;
+- case FUTEX_OP_CMP_LE:
+- ret = (oldval <= cmparg);
+- break;
+- case FUTEX_OP_CMP_GT:
+- ret = (oldval > cmparg);
+- break;
+- default:
+- ret = -ENOSYS;
+- }
+- }
++ if (!ret)
++ *oval = oldval;
++
+ return ret;
+ }
+
+--- a/arch/xtensa/include/asm/futex.h
++++ b/arch/xtensa/include/asm/futex.h
+@@ -44,18 +44,10 @@
+ : "r" (uaddr), "I" (-EFAULT), "r" (oparg) \
+ : "memory")
+
+-static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
++static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
++ u32 __user *uaddr)
+ {
+- int op = (encoded_op >> 28) & 7;
+- int cmp = (encoded_op >> 24) & 15;
+- int oparg = (encoded_op << 8) >> 20;
+- int cmparg = (encoded_op << 20) >> 20;
+ int oldval = 0, ret;
+- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+- oparg = 1 << oparg;
+-
+- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
+- return -EFAULT;
+
+ #if !XCHAL_HAVE_S32C1I
+ return -ENOSYS;
+@@ -89,19 +81,10 @@ static inline int futex_atomic_op_inuser
+
+ pagefault_enable();
+
+- if (ret)
+- return ret;
+-
+- switch (cmp) {
+- case FUTEX_OP_CMP_EQ: return (oldval == cmparg);
+- case FUTEX_OP_CMP_NE: return (oldval != cmparg);
+- case FUTEX_OP_CMP_LT: return (oldval < cmparg);
+- case FUTEX_OP_CMP_GE: return (oldval >= cmparg);
+- case FUTEX_OP_CMP_LE: return (oldval <= cmparg);
+- case FUTEX_OP_CMP_GT: return (oldval > cmparg);
+- }
++ if (!ret)
++ *oval = oldval;
+
+- return -ENOSYS;
++ return ret;
+ }
+
+ static inline int
+--- a/include/asm-generic/futex.h
++++ b/include/asm-generic/futex.h
+@@ -13,7 +13,7 @@
+ */
+
+ /**
+- * futex_atomic_op_inuser() - Atomic arithmetic operation with constant
++ * arch_futex_atomic_op_inuser() - Atomic arithmetic operation with constant
+ * argument and comparison of the previous
+ * futex value with another constant.
+ *
+@@ -25,18 +25,11 @@
+ * <0 - On error
+ */
+ static inline int
+-futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
++arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr)
+ {
+- int op = (encoded_op >> 28) & 7;
+- int cmp = (encoded_op >> 24) & 15;
+- int oparg = (encoded_op << 8) >> 20;
+- int cmparg = (encoded_op << 20) >> 20;
+ int oldval, ret;
+ u32 tmp;
+
+- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+- oparg = 1 << oparg;
+-
+ preempt_disable();
+ pagefault_disable();
+
+@@ -74,17 +67,9 @@ out_pagefault_enable:
+ pagefault_enable();
+ preempt_enable();
+
+- if (ret == 0) {
+- switch (cmp) {
+- case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+- case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+- case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+- case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+- case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+- case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+- default: ret = -ENOSYS;
+- }
+- }
++ if (ret == 0)
++ *oval = oldval;
++
+ return ret;
+ }
+
+@@ -126,18 +111,9 @@ futex_atomic_cmpxchg_inatomic(u32 *uval,
+
+ #else
+ static inline int
+-futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
++arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr)
+ {
+- int op = (encoded_op >> 28) & 7;
+- int cmp = (encoded_op >> 24) & 15;
+- int oparg = (encoded_op << 8) >> 20;
+- int cmparg = (encoded_op << 20) >> 20;
+ int oldval = 0, ret;
+- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+- oparg = 1 << oparg;
+-
+- if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
+- return -EFAULT;
+
+ pagefault_disable();
+
+@@ -153,17 +129,9 @@ futex_atomic_op_inuser (int encoded_op,
+
+ pagefault_enable();
+
+- if (!ret) {
+- switch (cmp) {
+- case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+- case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+- case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+- case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+- case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+- case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+- default: ret = -ENOSYS;
+- }
+- }
++ if (!ret)
++ *oval = oldval;
++
+ return ret;
+ }
+
+--- a/kernel/futex.c
++++ b/kernel/futex.c
+@@ -1458,6 +1458,45 @@ out:
+ return ret;
+ }
+
++static int futex_atomic_op_inuser(unsigned int encoded_op, u32 __user *uaddr)
++{
++ unsigned int op = (encoded_op & 0x70000000) >> 28;
++ unsigned int cmp = (encoded_op & 0x0f000000) >> 24;
++ int oparg = sign_extend32((encoded_op & 0x00fff000) >> 12, 12);
++ int cmparg = sign_extend32(encoded_op & 0x00000fff, 12);
++ int oldval, ret;
++
++ if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) {
++ if (oparg < 0 || oparg > 31)
++ return -EINVAL;
++ oparg = 1 << oparg;
++ }
++
++ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
++ return -EFAULT;
++
++ ret = arch_futex_atomic_op_inuser(op, oparg, &oldval, uaddr);
++ if (ret)
++ return ret;
++
++ switch (cmp) {
++ case FUTEX_OP_CMP_EQ:
++ return oldval == cmparg;
++ case FUTEX_OP_CMP_NE:
++ return oldval != cmparg;
++ case FUTEX_OP_CMP_LT:
++ return oldval < cmparg;
++ case FUTEX_OP_CMP_GE:
++ return oldval >= cmparg;
++ case FUTEX_OP_CMP_LE:
++ return oldval <= cmparg;
++ case FUTEX_OP_CMP_GT:
++ return oldval > cmparg;
++ default:
++ return -ENOSYS;
++ }
++}
++
+ /*
+ * Wake up all waiters hashed on the physical page that is mapped
+ * to this virtual address:
--- /dev/null
+From b2bd8598195f1b2a72130592125ac6b4218988a2 Mon Sep 17 00:00:00 2001
+From: David Rientjes <rientjes@google.com>
+Date: Wed, 3 May 2017 14:52:59 -0700
+Subject: mm, vmstat: print non-populated zones in zoneinfo
+
+From: David Rientjes <rientjes@google.com>
+
+commit b2bd8598195f1b2a72130592125ac6b4218988a2 upstream.
+
+Initscripts can use the information (protection levels) from
+/proc/zoneinfo to configure vm.lowmem_reserve_ratio at boot.
+
+vm.lowmem_reserve_ratio is an array of ratios for each configured zone
+on the system. If a zone is not populated on an arch, /proc/zoneinfo
+suppresses its output.
+
+This results in there not being a 1:1 mapping between the set of zones
+emitted by /proc/zoneinfo and the zones configured by
+vm.lowmem_reserve_ratio.
+
+This patch shows statistics for non-populated zones in /proc/zoneinfo.
+The zones exist and hold a spot in the vm.lowmem_reserve_ratio array.
+Without this patch, it is not possible to determine which index in the
+array controls which zone if one or more zones on the system are not
+populated.
+
+Remaining users of walk_zones_in_node() are unchanged. Files such as
+/proc/pagetypeinfo require certain zone data to be initialized properly
+for display, which is not done for unpopulated zones.
+
+Link: http://lkml.kernel.org/r/alpine.DEB.2.10.1703031451310.98023@chino.kir.corp.google.com
+Signed-off-by: David Rientjes <rientjes@google.com>
+Reviewed-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
+Cc: Vlastimil Babka <vbabka@suse.cz>
+Cc: Mel Gorman <mgorman@techsingularity.net>
+Cc: Johannes Weiner <hannes@cmpxchg.org>
+Cc: Michal Hocko <mhocko@kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Jisheng Zhang <Jisheng.Zhang@synaptics.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ mm/vmstat.c | 27 +++++++++++++++++----------
+ 1 file changed, 17 insertions(+), 10 deletions(-)
+
+--- a/mm/vmstat.c
++++ b/mm/vmstat.c
+@@ -1120,8 +1120,12 @@ static void frag_stop(struct seq_file *m
+ {
+ }
+
+-/* Walk all the zones in a node and print using a callback */
++/*
++ * Walk zones in a node and print using a callback.
++ * If @assert_populated is true, only use callback for zones that are populated.
++ */
+ static void walk_zones_in_node(struct seq_file *m, pg_data_t *pgdat,
++ bool assert_populated,
+ void (*print)(struct seq_file *m, pg_data_t *, struct zone *))
+ {
+ struct zone *zone;
+@@ -1129,7 +1133,7 @@ static void walk_zones_in_node(struct se
+ unsigned long flags;
+
+ for (zone = node_zones; zone - node_zones < MAX_NR_ZONES; ++zone) {
+- if (!populated_zone(zone))
++ if (assert_populated && !populated_zone(zone))
+ continue;
+
+ spin_lock_irqsave(&zone->lock, flags);
+@@ -1157,7 +1161,7 @@ static void frag_show_print(struct seq_f
+ static int frag_show(struct seq_file *m, void *arg)
+ {
+ pg_data_t *pgdat = (pg_data_t *)arg;
+- walk_zones_in_node(m, pgdat, frag_show_print);
++ walk_zones_in_node(m, pgdat, true, frag_show_print);
+ return 0;
+ }
+
+@@ -1198,7 +1202,7 @@ static int pagetypeinfo_showfree(struct
+ seq_printf(m, "%6d ", order);
+ seq_putc(m, '\n');
+
+- walk_zones_in_node(m, pgdat, pagetypeinfo_showfree_print);
++ walk_zones_in_node(m, pgdat, true, pagetypeinfo_showfree_print);
+
+ return 0;
+ }
+@@ -1250,7 +1254,7 @@ static int pagetypeinfo_showblockcount(s
+ for (mtype = 0; mtype < MIGRATE_TYPES; mtype++)
+ seq_printf(m, "%12s ", migratetype_names[mtype]);
+ seq_putc(m, '\n');
+- walk_zones_in_node(m, pgdat, pagetypeinfo_showblockcount_print);
++ walk_zones_in_node(m, pgdat, true, pagetypeinfo_showblockcount_print);
+
+ return 0;
+ }
+@@ -1276,7 +1280,7 @@ static void pagetypeinfo_showmixedcount(
+ seq_printf(m, "%12s ", migratetype_names[mtype]);
+ seq_putc(m, '\n');
+
+- walk_zones_in_node(m, pgdat, pagetypeinfo_showmixedcount_print);
++ walk_zones_in_node(m, pgdat, true, pagetypeinfo_showmixedcount_print);
+ #endif /* CONFIG_PAGE_OWNER */
+ }
+
+@@ -1432,12 +1436,15 @@ static void zoneinfo_show_print(struct s
+ }
+
+ /*
+- * Output information about zones in @pgdat.
++ * Output information about zones in @pgdat. All zones are printed regardless
++ * of whether they are populated or not: lowmem_reserve_ratio operates on the
++ * set of all zones and userspace would not be aware of such zones if they are
++ * suppressed here (zoneinfo displays the effect of lowmem_reserve_ratio).
+ */
+ static int zoneinfo_show(struct seq_file *m, void *arg)
+ {
+ pg_data_t *pgdat = (pg_data_t *)arg;
+- walk_zones_in_node(m, pgdat, zoneinfo_show_print);
++ walk_zones_in_node(m, pgdat, false, zoneinfo_show_print);
+ return 0;
+ }
+
+@@ -1865,7 +1872,7 @@ static int unusable_show(struct seq_file
+ if (!node_state(pgdat->node_id, N_MEMORY))
+ return 0;
+
+- walk_zones_in_node(m, pgdat, unusable_show_print);
++ walk_zones_in_node(m, pgdat, true, unusable_show_print);
+
+ return 0;
+ }
+@@ -1917,7 +1924,7 @@ static int extfrag_show(struct seq_file
+ {
+ pg_data_t *pgdat = (pg_data_t *)arg;
+
+- walk_zones_in_node(m, pgdat, extfrag_show_print);
++ walk_zones_in_node(m, pgdat, true, extfrag_show_print);
+
+ return 0;
+ }