linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] Pass 64-bit off_t as one 64-bit argument on 64-bit platforms
@ 2016-07-15 15:13 H.J. Lu
  0 siblings, 0 replies; only message in thread
From: H.J. Lu @ 2016-07-15 15:13 UTC (permalink / raw)
  To: LKML

[-- Attachment #1: Type: text/plain, Size: 1061 bytes --]

Currently 64-bit off_t is passed in 2 64-bit arguments on 64-bit
platforms with the second argument ignored by

static inline loff_t pos_from_hilo(unsigned long high, unsigned long low)
{
return (((loff_t)high << HALF_LONG_BITS) << HALF_LONG_BITS) | low;
}

SYSCALL_DEFINE5(preadv, unsigned long, fd, const struct iovec __user *, vec,
       unsigned long, vlen, unsigned long, pos_l, unsigned long, pos_h)
{
loff_t pos = pos_from_hilo(pos_h, pos_l);
return do_preadv(fd, vec, vlen, pos, 0);
}

On x86-64, only 4 arguments are passed to preadv.  Since off_t is the
last argument, garbage in the 5th argument isn't used by kernel.

Since off_t isn't the last argument for preadv2 nor pwritev2, 64-bit
off_t has be be passed in 2 64-bit arguments.  This patch changes preadv,
pwritev, preadv2 and pwritev2 to pass 64-bit off_t in one 64-bit argument
on 64-bit platforms.  preadv and pwritev are compatible with passing
off_t in one or two arguments as the 2nd argument is ignored by kernel.
But preadv2 and pwritev2 are incompatible with the old ones.


-- 
H.J.

[-- Attachment #2: 0001-Pass-64-bit-off_t-as-one-64-bit-argument-on-64-bit-p.patch --]
[-- Type: text/x-patch, Size: 4895 bytes --]

From 8e00ed418e4c4a7d575ad5ac197dd03857bc9cad Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Fri, 15 Jul 2016 07:56:03 -0700
Subject: [PATCH] Pass 64-bit off_t as one 64-bit argument on 64-bit platforms

Currently 64-bit off_t is passed in 2 64-bit arguments on 64-bit
platforms with the second argument ignored by

static inline loff_t pos_from_hilo(unsigned long high, unsigned long low)
{
	return (((loff_t)high << HALF_LONG_BITS) << HALF_LONG_BITS) | low;
}

SYSCALL_DEFINE5(preadv, unsigned long, fd, const struct iovec __user *, vec,
	        unsigned long, vlen, unsigned long, pos_l, unsigned long, pos_h)
{
	loff_t pos = pos_from_hilo(pos_h, pos_l);
	return do_preadv(fd, vec, vlen, pos, 0);
}

On x86-64, only 4 arguments are passed to preadv.  Since off_t is the
last argument, garbage in the 5th argument isn't used by kernel.

Since off_t isn't the last argument for preadv2 nor pwritev2, 64-bit
off_t has be be passed in 2 64-bit arguments.  This patch changes preadv,
pwritev, preadv2 and pwritev2 to pass 64-bit off_t in one 64-bit argument
on 64-bit platforms.  preadv and pwritev are compatible with passing
off_t in one or two arguments as the 2nd argument is ignored by kernel.
But preadv2 and pwritev2 are incompatible with the old ones.

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
---
 fs/read_write.c          | 28 ++++++++++++++++++++++++++++
 include/linux/syscalls.h | 11 +++++++++++
 2 files changed, 39 insertions(+)

diff --git a/fs/read_write.c b/fs/read_write.c
index 66215a7..779461a 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -924,11 +924,13 @@ static ssize_t do_writev(unsigned long fd, const struct iovec __user *vec,
 	return ret;
 }
 
+#if BITS_PER_LONG == 32
 static inline loff_t pos_from_hilo(unsigned long high, unsigned long low)
 {
 #define HALF_LONG_BITS (BITS_PER_LONG / 2)
 	return (((loff_t)high << HALF_LONG_BITS) << HALF_LONG_BITS) | low;
 }
+#endif
 
 static ssize_t do_preadv(unsigned long fd, const struct iovec __user *vec,
 			 unsigned long vlen, loff_t pos, int flags)
@@ -988,6 +990,7 @@ SYSCALL_DEFINE3(writev, unsigned long, fd, const struct iovec __user *, vec,
 	return do_writev(fd, vec, vlen, 0);
 }
 
+#if BITS_PER_LONG == 32
 SYSCALL_DEFINE5(preadv, unsigned long, fd, const struct iovec __user *, vec,
 		unsigned long, vlen, unsigned long, pos_l, unsigned long, pos_h)
 {
@@ -1027,6 +1030,31 @@ SYSCALL_DEFINE6(pwritev2, unsigned long, fd, const struct iovec __user *, vec,
 
 	return do_pwritev(fd, vec, vlen, pos, flags);
 }
+#else
+SYSCALL_DEFINE4(preadv, unsigned long, fd, const struct iovec __user *, vec,
+		unsigned long, vlen, loff_t, pos)
+{
+	return do_preadv(fd, vec, vlen, pos, 0);
+}
+
+SYSCALL_DEFINE5(preadv2, unsigned long, fd, const struct iovec __user *, vec,
+		unsigned long, vlen, loff_t, pos, int, flags)
+{
+	return do_preadv(fd, vec, vlen, pos, flags);
+}
+
+SYSCALL_DEFINE4(pwritev, unsigned long, fd, const struct iovec __user *, vec,
+		unsigned long, vlen, loff_t, pos)
+{
+	return do_pwritev(fd, vec, vlen, pos, 0);
+}
+
+SYSCALL_DEFINE5(pwritev2, unsigned long, fd, const struct iovec __user *, vec,
+		unsigned long, vlen, loff_t, pos, int, flags)
+{
+	return do_pwritev(fd, vec, vlen, pos, flags);
+}
+#endif
 
 #ifdef CONFIG_COMPAT
 
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index d022390..e61066f 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -573,6 +573,7 @@ asmlinkage long sys_pread64(unsigned int fd, char __user *buf,
 			    size_t count, loff_t pos);
 asmlinkage long sys_pwrite64(unsigned int fd, const char __user *buf,
 			     size_t count, loff_t pos);
+#if BITS_PER_LONG == 32
 asmlinkage long sys_preadv(unsigned long fd, const struct iovec __user *vec,
 			   unsigned long vlen, unsigned long pos_l, unsigned long pos_h);
 asmlinkage long sys_preadv2(unsigned long fd, const struct iovec __user *vec,
@@ -583,6 +584,16 @@ asmlinkage long sys_pwritev(unsigned long fd, const struct iovec __user *vec,
 asmlinkage long sys_pwritev2(unsigned long fd, const struct iovec __user *vec,
 			    unsigned long vlen, unsigned long pos_l, unsigned long pos_h,
 			    int flags);
+#else
+asmlinkage long sys_preadv(unsigned long fd, const struct iovec __user *vec,
+			   unsigned long vlen, loff_t pos);
+asmlinkage long sys_preadv2(unsigned long fd, const struct iovec __user *vec,
+			    unsigned long vlen, loff_t pos, int flags);
+asmlinkage long sys_pwritev(unsigned long fd, const struct iovec __user *vec,
+			    unsigned long vlen, loff_t pos);
+asmlinkage long sys_pwritev2(unsigned long fd, const struct iovec __user *vec,
+			    unsigned long vlen, loff_t pos, int flags);
+#endif
 asmlinkage long sys_getcwd(char __user *buf, unsigned long size);
 asmlinkage long sys_mkdir(const char __user *pathname, umode_t mode);
 asmlinkage long sys_chdir(const char __user *filename);
-- 
2.7.4


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2016-07-15 15:13 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-07-15 15:13 [PATCH] Pass 64-bit off_t as one 64-bit argument on 64-bit platforms H.J. Lu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).