On 6 October 2016 at 16:49, Dejan Jovicevic <dejan.jovice...@rt-rk.com> wrote: > v1 -> v2: > - Using safe_preadv() instead of calling preadv() directly. > > This system call performs the same task as the readv system call, > with the exception of having the fourth argument, offset, which > specifes the file offset at which the input operation is to be performed. > > This implementation is based on the existing readv implementation. > > Signed-off-by: Dejan Jovicevic <dejan.jovice...@rt-rk.com> > --- > linux-user/syscall.c | 15 +++++++++++++++ > 1 file changed, 15 insertions(+) > > diff --git a/linux-user/syscall.c b/linux-user/syscall.c > index 0815f30..c7619f6 100644 > --- a/linux-user/syscall.c > +++ b/linux-user/syscall.c > @@ -908,6 +908,8 @@ safe_syscall2(int, tkill, int, tid, int, sig) > safe_syscall3(int, tgkill, int, tgid, int, pid, int, sig) > safe_syscall3(ssize_t, readv, int, fd, const struct iovec *, iov, int, > iovcnt) > safe_syscall3(ssize_t, writev, int, fd, const struct iovec *, iov, int, > iovcnt) > +safe_syscall4(ssize_t, preadv, int, fd, const struct iovec *, iov, int, > iovcnt, > + off_t, offset) > safe_syscall3(int, connect, int, fd, const struct sockaddr *, addr, > socklen_t, addrlen) > safe_syscall6(ssize_t, sendto, int, fd, const void *, buf, size_t, len, > @@ -9894,6 +9896,19 @@ abi_long do_syscall(void *cpu_env, int num, abi_long > arg1, > } > } > break; > +#if defined(TARGET_NR_preadv) > + case TARGET_NR_preadv: > + { > + struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0); > + if (vec != NULL) { > + ret = get_errno(safe_preadv(arg1, vec, arg3, arg4)); > + unlock_iovec(vec, arg2, arg3, 1); > + } else { > + ret = -host_to_target_errno(errno); > + } > + } > + break; > +#endif
Looking at the kernel implementation I think this is not quite right (sorry for not checking the first time around). preadv is a 5-argument syscall: SYSCALL_DEFINE5(preadv, unsigned long, fd, const struct iovec __user *, vec, unsigned long, vlen, unsigned long, pos_l, unsigned long, pos_h) and the 64-bit offset is obtained by combining the pos_l and pos_h arguments via pos_from_hilo(): http://lxr.free-electrons.com/source/fs/read_write.c#L927 So we need to handle 5 arguments in the inputs from the guest, and we need to pass 5 arguments to the host syscall. (Watch out for the case where guest and host have different ideas of the size of long, when converting the input pos_l/pos_h to the host pos_l/pos_h.) Similarly for pwritev. thanks -- PMM