From 5750b7e3f971e02e1d5c676484eb10c779c6ac13 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Fri, 2 Jun 2017 18:31:16 -0700
Subject: [PATCH] Use LO_HI_LONG_FLAGS for p{readv,writev}{64}v2

The kernel interface for p{readv,writev}{64}v is

(unsigned long fd, {const }struct iovec *iov, unsigned long vlen,
 unsigned long pos_l, unsigned long pos_h)

The LO_HI_LONG macro is used to pass offset to the pos_l and pos_h pair.
Since pos_h is ignored when size of offset == sizeof of pos_l, x86-64
has

 #define LO_HI_LONG(val) (val)

But the kernel interface for p{readv,writev}{64}v2 is

(unsigned long fd, {const }struct iovec *iov, unsigned long vlen,
 unsigned long pos_l, unsigned long pos_h, int flags)

Except for targets which define __ARCH_WANT_COMPAT_SYS_PREADV64V2 and
__ARCH_WANT_COMPAT_SYS_PWRITEV64V2,

(unsigned long fd, {const }struct iovec *iov, unsigned long vlen,
 unsigned long pos, int flags)

will be used for p{readv,writev}{64}v2.  X32 is the only such target.
The x86-64 LO_HI_LONG can't be used for p{readv,writev}{64}v2.  Add a
new macro, LO_HI_LONG_FLAGS, to pass the off{64}_t and flags arguments.

Tested on i686, x32 and x86-64.

	* sysdeps/unix/sysv/linux/preadv2.c (preadv2): Replace LO_HI_LONG
	with LO_HI_LONG_FLAGS.
	* sysdeps/unix/sysv/linux/preadv64v2.c (preadv64v2): Likewise.
	* sysdeps/unix/sysv/linux/pwritev2.c (pwritev2): Likewise.
	* sysdeps/unix/sysv/linux/pwritev64v2.c (pwritev64v2): Likewise.
	* sysdeps/unix/sysv/linux/sysdep.h (LO_HI_LONG_FLAGS): New.
	* sysdeps/unix/sysv/linux/x86_64/sysdep.h (LO_HI_LONG_FLAGS):
	Likewise.
	* sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h (LO_HI_LONG_FLAGS):
	Likewise.
---
 sysdeps/unix/sysv/linux/preadv2.c           | 2 +-
 sysdeps/unix/sysv/linux/preadv64v2.c        | 2 +-
 sysdeps/unix/sysv/linux/pwritev2.c          | 2 +-
 sysdeps/unix/sysv/linux/pwritev64v2.c       | 2 +-
 sysdeps/unix/sysv/linux/sysdep.h            | 7 +++++++
 sysdeps/unix/sysv/linux/x86_64/sysdep.h     | 5 +++++
 sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h | 5 +++++
 7 files changed, 21 insertions(+), 4 deletions(-)

diff --git a/sysdeps/unix/sysv/linux/preadv2.c b/sysdeps/unix/sysv/linux/preadv2.c
index 11fe85e..51f7d2c 100644
--- a/sysdeps/unix/sysv/linux/preadv2.c
+++ b/sysdeps/unix/sysv/linux/preadv2.c
@@ -31,7 +31,7 @@ preadv2 (int fd, const struct iovec *vector, int count, off_t offset,
 {
 # ifdef __NR_preadv2
   ssize_t result = SYSCALL_CANCEL (preadv2, fd, vector, count,
-				   LO_HI_LONG (offset), flags);
+				   LO_HI_LONG_FLAGS (offset, flags));
   if (result >= 0 || errno != ENOSYS)
     return result;
 # endif
diff --git a/sysdeps/unix/sysv/linux/preadv64v2.c b/sysdeps/unix/sysv/linux/preadv64v2.c
index 9d7f8c9..c1960de 100644
--- a/sysdeps/unix/sysv/linux/preadv64v2.c
+++ b/sysdeps/unix/sysv/linux/preadv64v2.c
@@ -29,7 +29,7 @@ preadv64v2 (int fd, const struct iovec *vector, int count, off64_t offset,
 {
 #ifdef __NR_preadv64v2
   ssize_t result = SYSCALL_CANCEL (preadv64v2, fd, vector, count,
-				   LO_HI_LONG (offset), flags);
+				   LO_HI_LONG_FLAGS (offset, flags));
   if (result >= 0 || errno != ENOSYS)
     return result;
 #endif
diff --git a/sysdeps/unix/sysv/linux/pwritev2.c b/sysdeps/unix/sysv/linux/pwritev2.c
index 72f0471..82685a4 100644
--- a/sysdeps/unix/sysv/linux/pwritev2.c
+++ b/sysdeps/unix/sysv/linux/pwritev2.c
@@ -27,7 +27,7 @@ pwritev2 (int fd, const struct iovec *vector, int count, off_t offset,
 {
 # ifdef __NR_pwritev2
   ssize_t result = SYSCALL_CANCEL (pwritev2, fd, vector, count,
-				   LO_HI_LONG (offset), flags);
+				   LO_HI_LONG_FLAGS (offset, flags));
   if (result >= 0 || errno != ENOSYS)
     return result;
 # endif
diff --git a/sysdeps/unix/sysv/linux/pwritev64v2.c b/sysdeps/unix/sysv/linux/pwritev64v2.c
index def9a0b..18336cc 100644
--- a/sysdeps/unix/sysv/linux/pwritev64v2.c
+++ b/sysdeps/unix/sysv/linux/pwritev64v2.c
@@ -29,7 +29,7 @@ pwritev64v2 (int fd, const struct iovec *vector, int count, off64_t offset,
 {
 #ifdef __NR_pwritev64v2
   ssize_t result = SYSCALL_CANCEL (pwritev64v2, fd, vector, count,
-				   LO_HI_LONG (offset), flags);
+				   LO_HI_LONG_FLAGS (offset, flags));
   if (result >= 0 || errno != ENOSYS)
     return result;
 #endif
diff --git a/sysdeps/unix/sysv/linux/sysdep.h b/sysdeps/unix/sysv/linux/sysdep.h
index 1c24766..1b9ad3a 100644
--- a/sysdeps/unix/sysv/linux/sysdep.h
+++ b/sysdeps/unix/sysv/linux/sysdep.h
@@ -63,6 +63,13 @@
  (long) (val), \
  (long) (((uint64_t) (val)) >> 32)
 
+/* Provide a macro to pass the off{64}_t and flags arguments on
+   p{readv,writev}{64}v2.  */
+#define LO_HI_LONG_FLAGS(val, flags) \
+ (long) (val), \
+ (long) (((uint64_t) (val)) >> 32), \
+ (int) (flags)
+
 /* Exports the __send symbol on send.c linux implementation (some ABI have
    it missing due the usage of a old generic version without it).  */
 #define HAVE_INTERNAL_SEND_SYMBOL	1
diff --git a/sysdeps/unix/sysv/linux/x86_64/sysdep.h b/sysdeps/unix/sysv/linux/x86_64/sysdep.h
index 7b8bd79..a3fe2fa 100644
--- a/sysdeps/unix/sysv/linux/x86_64/sysdep.h
+++ b/sysdeps/unix/sysv/linux/x86_64/sysdep.h
@@ -389,4 +389,9 @@
 #undef LO_HI_LONG
 #define LO_HI_LONG(val) (val)
 
+/* Provide a macro to pass the off{64}_t and flags arguments on
+   p{readv,writev}{64}v2.  */
+#undef LO_HI_LONG_FLAGS
+#define LO_HI_LONG_FLAGS(val, flags) (val), 0, (flags)
+
 #endif /* linux/x86_64/sysdep.h */
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h b/sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h
index f90fcfa..b694202 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h
@@ -22,4 +22,9 @@
 #include <sysdeps/unix/sysv/linux/x86_64/sysdep.h>
 #include <sysdeps/x86_64/x32/sysdep.h>
 
+/* Provide a macro to pass the off{64}_t and flags arguments on
+   p{readv,writev}{64}v2.  */
+#undef LO_HI_LONG_FLAGS
+#define LO_HI_LONG_FLAGS(val, flags) (val), (flags)
+
 #endif /* linux/x86_64/x32/sysdep.h */
-- 
2.9.4
