From c71d227fc4133f949dae620ed5e3a250b43f2415 Mon Sep 17 00:00:00 2001
From: Al Viro <viro@zeniv.linux.org.uk>
Date: Wed, 29 Nov 2017 19:00:41 -0500
Subject: [PATCH] make kernel-side POLL... arch-independent

mangle/demangle on the way to/from userland

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 arch/blackfin/include/uapi/asm/poll.h | 19 ++++++++++++++++++-
 arch/frv/include/uapi/asm/poll.h      | 19 +++++++++++++++++--
 arch/m68k/include/uapi/asm/poll.h     | 17 +++++++++++++++++
 arch/mips/include/uapi/asm/poll.h     | 17 +++++++++++++++++
 arch/sparc/include/uapi/asm/poll.h    | 20 ++++++++++++++++++++
 arch/xtensa/include/uapi/asm/poll.h   | 17 +++++++++++++++++
 fs/fcntl.c                            |  2 +-
 fs/fuse/file.c                        |  4 ++--
 fs/select.c                           |  4 ++--
 include/uapi/asm-generic/poll.h       | 14 ++++++++++++++
 10 files changed, 125 insertions(+), 8 deletions(-)

diff --git a/arch/blackfin/include/uapi/asm/poll.h b/arch/blackfin/include/uapi/asm/poll.h
index 961e49056b0a..3b162f2d2970 100644
--- a/arch/blackfin/include/uapi/asm/poll.h
+++ b/arch/blackfin/include/uapi/asm/poll.h
@@ -9,8 +9,25 @@
 #ifndef _UAPI__BFIN_POLL_H
 #define _UAPI__BFIN_POLL_H
 
-#define POLLWRNORM	(__force __poll_t)4 /* POLLOUT */
+#ifndef __KERNEL__
+#define POLLWRNORM	POLLOUT
 #define POLLWRBAND	(__force __poll_t)256
+#else
+#define __ARCH_HAS_MANGLED_POLL
+static inline __u16 mangle_poll(__poll_t val)
+{
+	__u16 v = (__force __u16)val;
+	/* bit 9 -> bit 8, bit 8 -> bit 2 */
+	return (v & ~0x300) | ((v & 0x200) >> 1) | ((v & 0x100) >> 6);
+}
+
+static inline __poll_t demangle_poll(__u16 v)
+{
+        /* bit 8 -> bit 9, bit 2 -> bits 2 and 8 */
+	return (__force __poll_t)((v & ~0x100) | ((v & 0x100) << 1) |
+				((v & 4) << 6));
+}
+#endif
 
 #include <asm-generic/poll.h>
 
diff --git a/arch/frv/include/uapi/asm/poll.h b/arch/frv/include/uapi/asm/poll.h
index d7053ada7c69..a44c8f0ebee7 100644
--- a/arch/frv/include/uapi/asm/poll.h
+++ b/arch/frv/include/uapi/asm/poll.h
@@ -2,12 +2,27 @@
 #ifndef _ASM_POLL_H
 #define _ASM_POLL_H
 
+#ifndef __KERNEL__
 #define POLLWRNORM	POLLOUT
 #define POLLWRBAND	(__force __poll_t)256
+#else
+#define __ARCH_HAS_MANGLED_POLL
+static inline __u16 mangle_poll(__poll_t val)
+{
+	__u16 v = (__force __u16)val;
+	/* bit 9 -> bit 8, bit 8 -> bit 2 */
+	return (v & ~0x300) | ((v & 0x200) >> 1) | ((v & 0x100) >> 6);
+}
+
+static inline __poll_t demangle_poll(__u16 v)
+{
+        /* bit 8 -> bit 9, bit 2 -> bits 2 and 8 */
+	return (__force __poll_t)((v & ~0x100) | ((v & 0x100) << 1) |
+				((v & 4) << 6));
+}
+#endif
 
 #include <asm-generic/poll.h>
-
 #undef POLLREMOVE
 
 #endif
-
diff --git a/arch/m68k/include/uapi/asm/poll.h b/arch/m68k/include/uapi/asm/poll.h
index 99314937fe5c..d8be239e8141 100644
--- a/arch/m68k/include/uapi/asm/poll.h
+++ b/arch/m68k/include/uapi/asm/poll.h
@@ -2,8 +2,25 @@
 #ifndef __m68k_POLL_H
 #define __m68k_POLL_H
 
+#ifndef __KERNEL__
 #define POLLWRNORM	POLLOUT
 #define POLLWRBAND	(__force __poll_t)256
+#else
+#define __ARCH_HAS_MANGLED_POLL
+static inline __u16 mangle_poll(__poll_t val)
+{
+	__u16 v = (__force __u16)val;
+	/* bit 9 -> bit 8, bit 8 -> bit 2 */
+	return (v & ~0x300) | ((v & 0x200) >> 1) | ((v & 0x100) >> 6);
+}
+
+static inline __poll_t demangle_poll(__u16 v)
+{
+        /* bit 8 -> bit 9, bit 2 -> bits 2 and 8 */
+	return (__force __poll_t)((v & ~0x100) | ((v & 0x100) << 1) |
+				((v & 4) << 6));
+}
+#endif
 
 #include <asm-generic/poll.h>
 
diff --git a/arch/mips/include/uapi/asm/poll.h b/arch/mips/include/uapi/asm/poll.h
index e937f8b1b007..3173f8917128 100644
--- a/arch/mips/include/uapi/asm/poll.h
+++ b/arch/mips/include/uapi/asm/poll.h
@@ -2,8 +2,25 @@
 #ifndef __ASM_POLL_H
 #define __ASM_POLL_H
 
+#ifndef __KERNEL__
 #define POLLWRNORM	POLLOUT
 #define POLLWRBAND	(__force __poll_t)0x0100
+#else
+#define __ARCH_HAS_MANGLED_POLL
+static inline __u16 mangle_poll(__poll_t val)
+{
+	__u16 v = (__force __u16)val;
+	/* bit 9 -> bit 8, bit 8 -> bit 2 */
+	return (v & ~0x300) | ((v & 0x200) >> 1) | ((v & 0x100) >> 6);
+}
+
+static inline __poll_t demangle_poll(__u16 v)
+{
+        /* bit 8 -> bit 9, bit 2 -> bits 2 and 8 */
+	return (__force __poll_t)((v & ~0x100) | ((v & 0x100) << 1) |
+				((v & 4) << 6));
+}
+#endif
 
 #include <asm-generic/poll.h>
 
diff --git a/arch/sparc/include/uapi/asm/poll.h b/arch/sparc/include/uapi/asm/poll.h
index 595cb12df1f1..2a81e79aa3ea 100644
--- a/arch/sparc/include/uapi/asm/poll.h
+++ b/arch/sparc/include/uapi/asm/poll.h
@@ -2,11 +2,31 @@
 #ifndef __SPARC_POLL_H
 #define __SPARC_POLL_H
 
+#ifndef __KERNEL__
 #define POLLWRNORM	POLLOUT
 #define POLLWRBAND	(__force __poll_t)256
 #define POLLMSG		(__force __poll_t)512
 #define POLLREMOVE	(__force __poll_t)1024
 #define POLLRDHUP       (__force __poll_t)2048
+#else
+#define __ARCH_HAS_MANGLED_POLL
+static inline __u16 mangle_poll(__poll_t val)
+{
+	__u16 v = (__force __u16)val;
+        /* bit 9 -> bit 8, bit 8 -> bit 2, bit 13 -> bit 11 */
+	return (v & ~0x300) | ((v & 0x200) >> 1) | ((v & 0x100) >> 6) |
+				((v & 0x2000) >> 2);
+
+
+}
+
+static inline __poll_t demangle_poll(__u16 v)
+{
+        /* bit 8 -> bit 9, bit 2 -> bits 2 and 8 */
+	return (__force __poll_t)((v & ~0x100) | ((v & 0x100) << 1) |
+				((v & 4) << 6) | ((v & 0x800) << 2));
+}
+#endif
 
 #include <asm-generic/poll.h>
 
diff --git a/arch/xtensa/include/uapi/asm/poll.h b/arch/xtensa/include/uapi/asm/poll.h
index 22bbc48b9f85..e3246d41182c 100644
--- a/arch/xtensa/include/uapi/asm/poll.h
+++ b/arch/xtensa/include/uapi/asm/poll.h
@@ -12,9 +12,26 @@
 #ifndef _XTENSA_POLL_H
 #define _XTENSA_POLL_H
 
+#ifndef __KERNEL__
 #define POLLWRNORM	POLLOUT
 #define POLLWRBAND	(__force __poll_t)0x0100
 #define POLLREMOVE	(__force __poll_t)0x0800
+#else
+#define __ARCH_HAS_MANGLED_POLL
+static inline __u16 mangle_poll(__poll_t val)
+{
+	__u16 v = (__force __u16)val;
+	/* bit 9 -> bit 8, bit 8 -> bit 2 */
+	return (v & ~0x300) | ((v & 0x200) >> 1) | ((v & 0x100) >> 6);
+}
+
+static inline __poll_t demangle_poll(__u16 v)
+{
+        /* bit 8 -> bit 9, bit 2 -> bits 2 and 8 */
+	return (__force __poll_t)((v & ~0x100) | ((v & 0x100) << 1) |
+				((v & 4) << 6));
+}
+#endif
 
 #include <asm-generic/poll.h>
 
diff --git a/fs/fcntl.c b/fs/fcntl.c
index afe731c7a5a8..84bab55b4712 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -758,7 +758,7 @@ static void send_sigio_to_task(struct task_struct *p,
 			if (reason - POLL_IN >= NSIGPOLL)
 				si.si_band  = ~0L;
 			else
-				si.si_band = (__force long)band_table[reason - POLL_IN];
+				si.si_band = mangle_poll(band_table[reason - POLL_IN]);
 			si.si_fd    = fd;
 			if (!do_send_sig_info(signum, &si, p, group))
 				break;
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index fa4ca6bd2c96..e85e974dd211 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -2764,7 +2764,7 @@ __poll_t fuse_file_poll(struct file *file, poll_table *wait)
 		return DEFAULT_POLLMASK;
 
 	poll_wait(file, &ff->poll_wait, wait);
-	inarg.events = (__u32)poll_requested_events(wait);
+	inarg.events = mangle_poll(poll_requested_events(wait));
 
 	/*
 	 * Ask for notification iff there's someone waiting for it.
@@ -2786,7 +2786,7 @@ __poll_t fuse_file_poll(struct file *file, poll_table *wait)
 	err = fuse_simple_request(fc, &args);
 
 	if (!err)
-		return outarg.revents;
+		return demangle_poll(outarg.revents);
 	if (err == -ENOSYS) {
 		fc->no_poll = 1;
 		return DEFAULT_POLLMASK;
diff --git a/fs/select.c b/fs/select.c
index b2deeb215dbe..ec14171dd78a 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -817,7 +817,7 @@ static inline __poll_t do_pollfd(struct pollfd *pollfd, poll_table *pwait,
 		mask = POLLNVAL;
 		if (f.file) {
 			/* userland u16 ->events contains POLL... bitmap */
-			__poll_t filter = (__force __poll_t)pollfd->events |
+			__poll_t filter = demangle_poll(pollfd->events) |
 						POLLERR | POLLHUP;
 			mask = DEFAULT_POLLMASK;
 			if (f.file->f_op->poll) {
@@ -833,7 +833,7 @@ static inline __poll_t do_pollfd(struct pollfd *pollfd, poll_table *pwait,
 		}
 	}
 	/* ... and so does ->revents */
-	pollfd->revents = (__force u16)mask;
+	pollfd->revents = mangle_poll(mask);
 
 	return mask;
 }
diff --git a/include/uapi/asm-generic/poll.h b/include/uapi/asm-generic/poll.h
index 8c0e9dd384b6..639fade14b23 100644
--- a/include/uapi/asm-generic/poll.h
+++ b/include/uapi/asm-generic/poll.h
@@ -33,6 +33,20 @@
 
 #define POLL_BUSY_LOOP	(__force __poll_t)0x8000
 
+#ifdef __KERNEL__
+#ifndef __ARCH_HAS_MANGLED_POLL
+static inline __u16 mangle_poll(__poll_t val)
+{
+	return (__force __u16)val;
+}
+
+static inline __poll_t demangle_poll(__u16 v)
+{
+	return (__force __poll_t)v;
+}
+#endif
+#endif
+
 struct pollfd {
 	int fd;
 	short events;