Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f3554f4b authored by Gerd Hoffmann's avatar Gerd Hoffmann Committed by Linus Torvalds
Browse files

preadv/pwritev: Add preadv and pwritev system calls.

This patch adds preadv and pwritev system calls.  These syscalls are a
pretty straightforward combination of pread and readv (same for write).
They are quite useful for doing vectored I/O in threaded applications.
Using lseek+readv instead opens race windows you'll have to plug with
locking.

Other systems have such system calls too, for example NetBSD, check
here: http://www.daemon-systems.org/man/preadv.2.html



The application-visible interface provided by glibc should look like
this to be compatible to the existing implementations in the *BSD family:

  ssize_t preadv(int d, const struct iovec *iov, int iovcnt, off_t offset);
  ssize_t pwritev(int d, const struct iovec *iov, int iovcnt, off_t offset);

This prototype has one problem though: On 32bit archs is the (64bit)
offset argument unaligned, which the syscall ABI of several archs doesn't
allow to do.  At least s390 needs a wrapper in glibc to handle this.  As
we'll need a wrappers in glibc anyway I've decided to push problem to
glibc entriely and use a syscall prototype which works without
arch-specific wrappers inside the kernel: The offset argument is
explicitly splitted into two 32bit values.

The patch sports the actual system call implementation and the windup in
the x86 system call tables.  Other archs follow as separate patches.

Signed-off-by: default avatarGerd Hoffmann <kraxel@redhat.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: <linux-api@vger.kernel.org>
Cc: <linux-arch@vger.kernel.org>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 6949a631
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -828,4 +828,6 @@ ia32_sys_call_table:
	.quad sys_dup3			/* 330 */
	.quad sys_pipe2
	.quad sys_inotify_init1
	.quad compat_sys_preadv
	.quad compat_sys_pwritev
ia32_syscall_end:
+2 −0
Original line number Diff line number Diff line
@@ -338,6 +338,8 @@
#define __NR_dup3		330
#define __NR_pipe2		331
#define __NR_inotify_init1	332
#define __NR_preadv		333
#define __NR_pwritev		334

#ifdef __KERNEL__

+4 −0
Original line number Diff line number Diff line
@@ -653,6 +653,10 @@ __SYSCALL(__NR_dup3, sys_dup3)
__SYSCALL(__NR_pipe2, sys_pipe2)
#define __NR_inotify_init1			294
__SYSCALL(__NR_inotify_init1, sys_inotify_init1)
#define __NR_preadv				295
__SYSCALL(__NR_preadv, sys_preadv)
#define __NR_pwritev				296
__SYSCALL(__NR_pwritev, sys_pwritev)


#ifndef __NO_STUBS
+2 −0
Original line number Diff line number Diff line
@@ -332,3 +332,5 @@ ENTRY(sys_call_table)
	.long sys_dup3			/* 330 */
	.long sys_pipe2
	.long sys_inotify_init1
	.long sys_preadv
	.long sys_pwritev
+36 −0
Original line number Diff line number Diff line
@@ -1232,6 +1232,24 @@ compat_sys_readv(unsigned long fd, const struct compat_iovec __user *vec,
	return ret;
}

asmlinkage ssize_t
compat_sys_preadv(unsigned long fd, const struct compat_iovec __user *vec,
		  unsigned long vlen, u32 pos_high, u32 pos_low)
{
	loff_t pos = ((loff_t)pos_high << 32) | pos_low;
	struct file *file;
	ssize_t ret;

	if (pos < 0)
		return -EINVAL;
	file = fget(fd);
	if (!file)
		return -EBADF;
	ret = compat_readv(file, vec, vlen, &pos);
	fput(file);
	return ret;
}

static size_t compat_writev(struct file *file,
			    const struct compat_iovec __user *vec,
			    unsigned long vlen, loff_t *pos)
@@ -1269,6 +1287,24 @@ compat_sys_writev(unsigned long fd, const struct compat_iovec __user *vec,
	return ret;
}

asmlinkage ssize_t
compat_sys_pwritev(unsigned long fd, const struct compat_iovec __user *vec,
		   unsigned long vlen, u32 pos_high, u32 pos_low)
{
	loff_t pos = ((loff_t)pos_high << 32) | pos_low;
	struct file *file;
	ssize_t ret;

	if (pos < 0)
		return -EINVAL;
	file = fget(fd);
	if (!file)
		return -EBADF;
	ret = compat_writev(file, vec, vlen, &pos);
	fput(file);
	return ret;
}

asmlinkage long
compat_sys_vmsplice(int fd, const struct compat_iovec __user *iov32,
		    unsigned int nr_segs, unsigned int flags)
Loading