diff mbox

linux-user: Implement sendmmsg syscall

Message ID 1378388242-13114-1-git-send-email-agraf@suse.de
State New
Headers show

Commit Message

Alexander Graf Sept. 5, 2013, 1:37 p.m. UTC
Glibc when built for newer kernels assumes that the sendmmsg syscall is available.
Without it, dns resolution simply fails to work.

Wrap the syscall with existing infrastructure so that we don't have a host dependency
on sendmmsg.

Signed-off-by: Alexander Graf <agraf@suse.de>
---
 linux-user/syscall.c      | 29 +++++++++++++++++++++++++++++
 linux-user/syscall_defs.h |  4 ++++
 2 files changed, 33 insertions(+)

Comments

Laurent Vivier Sept. 5, 2013, 2:21 p.m. UTC | #1
> Le 5 septembre 2013 à 15:37, Alexander Graf <agraf@suse.de> a écrit :
>
>
> Glibc when built for newer kernels assumes that the sendmmsg syscall is
> available.
> Without it, dns resolution simply fails to work.
>
> Wrap the syscall with existing infrastructure so that we don't have a host
> dependency
> on sendmmsg.

Why don't you write a "do_sendrecvmmsg()" in the same way it is done for
"do_sendrecvmsg()" to be able to manage also the "recvmmsg()" syscall ?

Regards,
Laurent

> Signed-off-by: Alexander Graf <agraf@suse.de>
> ---
> linux-user/syscall.c | 29 +++++++++++++++++++++++++++++
> linux-user/syscall_defs.h | 4 ++++
> 2 files changed, 33 insertions(+)
>
> diff --git a/linux-user/syscall.c b/linux-user/syscall.c
> index 0272990..59cfdf4 100644
> --- a/linux-user/syscall.c
> +++ b/linux-user/syscall.c
> @@ -1863,6 +1863,30 @@ out2:
> return ret;
> }
>
> +#ifdef TARGET_NR_sendmmsg
> +static abi_long do_sendmmsg(int fd, abi_ulong target_msgvec,
> + unsigned int vlen, unsigned int flags)
> +{
> + struct target_mmsghdr *mmsgp;
> + abi_ulong arg2 = target_msgvec;
> + int i;
> +
> + if (!(mmsgp = lock_user(VERIFY_WRITE, target_msgvec,
> + sizeof(*mmsgp) * vlen, 1))) {
> + return -TARGET_EFAULT;
> + }
> +
> + for (i = 0; i < vlen; i++) {
> + mmsgp[i].msg_len = tswap32(do_sendrecvmsg(fd, arg2, flags, 1));
> + arg2 += sizeof(struct target_mmsghdr);
> + }
> +
> + unlock_user(mmsgp, target_msgvec, 0);
> + /* XXX need to handle nonblocking case too */
> + return vlen;
> +}
> +#endif
> +
> /* If we don't have a system accept4() then just call accept.
> * The callsites to do_accept4() will ensure that they don't
> * pass a non-zero flags argument in this config.
> @@ -6973,6 +6997,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_ulong
> arg1,
> ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
> break;
> #endif
> +#ifdef TARGET_NR_sendmmsg
> + case TARGET_NR_sendmmsg:
> + ret = do_sendmmsg(arg1, arg2, arg3, arg4);
> + break;
> +#endif
> #ifdef TARGET_NR_sendto
> case TARGET_NR_sendto:
> ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
> diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
> index e51ef31..37645de 100644
> --- a/linux-user/syscall_defs.h
> +++ b/linux-user/syscall_defs.h
> @@ -222,6 +222,10 @@ __target_cmsg_nxthdr (struct target_msghdr *__mhdr,
> struct target_cmsghdr *__cms
> return __cmsg;
> }
>
> +struct target_mmsghdr {
> + struct target_msghdr msg_hdr; /* Message header */
> + unsigned int msg_len; /* Number of bytes transmitted */
> +};
>
> struct target_rusage {
> struct target_timeval ru_utime; /* user time used */
> --
> 1.8.1.4
>
>
Peter Maydell Sept. 5, 2013, 2:31 p.m. UTC | #2
On 5 September 2013 14:37, Alexander Graf <agraf@suse.de> wrote:
> Glibc when built for newer kernels assumes that the sendmmsg syscall is available.
> Without it, dns resolution simply fails to work.
>
> Wrap the syscall with existing infrastructure so that we don't have a host dependency
> on sendmmsg.
>
> Signed-off-by: Alexander Graf <agraf@suse.de>
> ---
>  linux-user/syscall.c      | 29 +++++++++++++++++++++++++++++
>  linux-user/syscall_defs.h |  4 ++++
>  2 files changed, 33 insertions(+)
>
> diff --git a/linux-user/syscall.c b/linux-user/syscall.c
> index 0272990..59cfdf4 100644
> --- a/linux-user/syscall.c
> +++ b/linux-user/syscall.c
> @@ -1863,6 +1863,30 @@ out2:
>      return ret;
>  }
>
> +#ifdef TARGET_NR_sendmmsg
> +static abi_long do_sendmmsg(int fd, abi_ulong target_msgvec,
> +                            unsigned int vlen, unsigned int flags)
> +{
> +    struct target_mmsghdr *mmsgp;
> +    abi_ulong arg2 = target_msgvec;
> +    int i;

If we're doing this in terms of sendmsg, we need to
implement the kernel's "if CMSG_COMPAT fail EINVAL"
logic ourselves. Compare
 http://lxr.linux.no/#linux+v3.11/net/socket.c#L2175

> +
> +    if (!(mmsgp = lock_user(VERIFY_WRITE, target_msgvec,
> +                            sizeof(*mmsgp) * vlen, 1))) {
> +        return -TARGET_EFAULT;
> +    }
> +
> +    for (i = 0; i < vlen; i++) {
> +        mmsgp[i].msg_len = tswap32(do_sendrecvmsg(fd, arg2, flags, 1));

If do_sendrecvmsg reports an errno we should stop
processing the array and return it, not just
stuff it into msg_len. Compare:
  http://lxr.linux.no/#linux+v3.11/net/socket.c#L2155

> +        arg2 += sizeof(struct target_mmsghdr);
> +    }
> +
> +    unlock_user(mmsgp, target_msgvec, 0);
> +    /* XXX need to handle nonblocking case too */
> +    return vlen;
> +}
> +#endif

thanks
-- PMM
diff mbox

Patch

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 0272990..59cfdf4 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -1863,6 +1863,30 @@  out2:
     return ret;
 }
 
+#ifdef TARGET_NR_sendmmsg
+static abi_long do_sendmmsg(int fd, abi_ulong target_msgvec,
+                            unsigned int vlen, unsigned int flags)
+{
+    struct target_mmsghdr *mmsgp;
+    abi_ulong arg2 = target_msgvec;
+    int i;
+
+    if (!(mmsgp = lock_user(VERIFY_WRITE, target_msgvec,
+                            sizeof(*mmsgp) * vlen, 1))) {
+        return -TARGET_EFAULT;
+    }
+
+    for (i = 0; i < vlen; i++) {
+        mmsgp[i].msg_len = tswap32(do_sendrecvmsg(fd, arg2, flags, 1));
+        arg2 += sizeof(struct target_mmsghdr);
+    }
+
+    unlock_user(mmsgp, target_msgvec, 0);
+    /* XXX need to handle nonblocking case too */
+    return vlen;
+}
+#endif
+
 /* If we don't have a system accept4() then just call accept.
  * The callsites to do_accept4() will ensure that they don't
  * pass a non-zero flags argument in this config.
@@ -6973,6 +6997,11 @@  abi_long do_syscall(void *cpu_env, int num, abi_ulong arg1,
         ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
         break;
 #endif
+#ifdef TARGET_NR_sendmmsg
+    case TARGET_NR_sendmmsg:
+        ret = do_sendmmsg(arg1, arg2, arg3, arg4);
+        break;
+#endif
 #ifdef TARGET_NR_sendto
     case TARGET_NR_sendto:
         ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index e51ef31..37645de 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -222,6 +222,10 @@  __target_cmsg_nxthdr (struct target_msghdr *__mhdr, struct target_cmsghdr *__cms
   return __cmsg;
 }
 
+struct target_mmsghdr {
+    struct target_msghdr msg_hdr;              /* Message header */
+    unsigned int         msg_len;              /* Number of bytes transmitted */
+};
 
 struct  target_rusage {
         struct target_timeval ru_utime;        /* user time used */