qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/2] linux-user: Introducing support for 'recvmmsg_time64()'
@ 2020-08-25 21:20 Filip Bozuta
  2020-08-25 21:20 ` [PATCH v2 1/2] linux-user: Modify 'recvmmsg()' implementation Filip Bozuta
  2020-08-25 21:20 ` [PATCH v2 2/2] linux-user: Add support for 'recvmmsg_time64()' Filip Bozuta
  0 siblings, 2 replies; 3+ messages in thread
From: Filip Bozuta @ 2020-08-25 21:20 UTC (permalink / raw)
  To: qemu-devel; +Cc: Riku Voipio, Laurent Vivier, Filip Bozuta

This patch introduces functionality for 'recvmmsg_time64()' which
is a year 2038 safe variant of 'recvmmsg()'. This new time64 syscall
is introduced in series of two patches rather than in one patch
because a little modification was needed before the syscall could
be introduced properly.

The first patch in the series introduces a little fix in
the implementation of 'recvmmsg()' that introduces the timeout
argument which is of type 'struct timespec' for which the
separate time64 variant is added.

The second patch in the series introduces the implementation
of 'recvmmsg_time64()'.

Testing method:

    The implementation was tested using existing tests from
    the LTP test suite which was build inside a chroot.

Filip Bozuta (2):
  linux-user: Modify 'recvmmsg()' implementation
  linux-user: Add support for 'recvmmsg_time64()'

 linux-user/syscall.c | 56 +++++++++++++++++++++++++++++++++++++-------
 1 file changed, 48 insertions(+), 8 deletions(-)

-- 
2.25.1



^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH v2 1/2] linux-user: Modify 'recvmmsg()' implementation
  2020-08-25 21:20 [PATCH v2 0/2] linux-user: Introducing support for 'recvmmsg_time64()' Filip Bozuta
@ 2020-08-25 21:20 ` Filip Bozuta
  2020-08-25 21:20 ` [PATCH v2 2/2] linux-user: Add support for 'recvmmsg_time64()' Filip Bozuta
  1 sibling, 0 replies; 3+ messages in thread
From: Filip Bozuta @ 2020-08-25 21:20 UTC (permalink / raw)
  To: qemu-devel; +Cc: Riku Voipio, Laurent Vivier, Filip Bozuta

Implementation of syscall 'recvmmsg()' in file 'syscall.c' uses
a loop over 'recvmsg()' to receive each individual message from
a socket. However, the implementation ignores the timeout argument.
This patch changes that by introducing a timeout check after
each received message.

Implementation notes:

   Function 'clock_gettime()' is used to check the time before
   messages start getting received. After each message is received,
   'clock_gettime()' is called and used to check whether the timeout
   is expired.

Signed-off-by: Filip Bozuta <Filip.Bozuta@syrmia.com>
---
 linux-user/syscall.c | 45 ++++++++++++++++++++++++++++++++++++--------
 1 file changed, 37 insertions(+), 8 deletions(-)

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 05f03919ff..dc89bfacca 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -3197,21 +3197,36 @@ static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
 
 static abi_long do_sendrecvmmsg(int fd, abi_ulong target_msgvec,
                                 unsigned int vlen, unsigned int flags,
-                                int send)
+                                abi_ulong timeout, int send)
 {
     struct target_mmsghdr *mmsgp;
+    struct timespec ts, end_time, curr_time;
     abi_long ret = 0;
     int i;
 
     if (vlen > UIO_MAXIOV) {
         vlen = UIO_MAXIOV;
     }
-
     mmsgp = lock_user(VERIFY_WRITE, target_msgvec, sizeof(*mmsgp) * vlen, 1);
     if (!mmsgp) {
         return -TARGET_EFAULT;
     }
+    if (timeout) {
+        if (target_to_host_timespec(&ts, timeout)) {
+            return -TARGET_EFAULT;
+        }
+        if (ts.tv_sec < 0 || ts.tv_nsec < 0 || ts.tv_nsec > 1000000000) {
+            return -TARGET_EINVAL;
+        }
 
+        clock_gettime(CLOCK_REALTIME, &curr_time);
+        end_time.tv_sec = curr_time.tv_sec + ts.tv_sec;
+        end_time.tv_nsec = curr_time.tv_nsec + ts.tv_nsec;
+        if (end_time.tv_nsec > 1000000000) {
+            end_time.tv_nsec -= 1000000000;
+            end_time.tv_sec++;
+        }
+    }
     for (i = 0; i < vlen; i++) {
         ret = do_sendrecvmsg_locked(fd, &mmsgp[i].msg_hdr, flags, send);
         if (is_error(ret)) {
@@ -3222,6 +3237,20 @@ static abi_long do_sendrecvmmsg(int fd, abi_ulong target_msgvec,
         if (flags & MSG_WAITFORONE) {
             flags |= MSG_DONTWAIT;
         }
+        /*
+         * For recvmmsg() the timeout is checked only after a datagram is
+         * received.This is an existing bug in the kernel for this syscall:
+         * https://man7.org/linux/man-pages/man2/recvmmsg.2.html#BUGS
+         */
+        if (timeout) {
+            clock_gettime(CLOCK_REALTIME, &curr_time);
+            if (curr_time.tv_sec > end_time.tv_sec ||
+                (curr_time.tv_sec == end_time.tv_sec &&
+                curr_time.tv_nsec >= end_time.tv_nsec)) {
+                i++;
+                break;
+            }
+        }
     }
 
     unlock_user(mmsgp, target_msgvec, sizeof(*mmsgp) * i);
@@ -3477,7 +3506,7 @@ static abi_long do_socketcall(int num, abi_ulong vptr)
         [TARGET_SYS_SENDMSG] = 3,     /* fd, msg, flags */
         [TARGET_SYS_RECVMSG] = 3,     /* fd, msg, flags */
         [TARGET_SYS_ACCEPT4] = 4,     /* fd, addr, addrlen, flags */
-        [TARGET_SYS_RECVMMSG] = 4,    /* fd, msgvec, vlen, flags */
+        [TARGET_SYS_RECVMMSG] = 5,    /* fd, msgvec, vlen, flags, timeout */
         [TARGET_SYS_SENDMMSG] = 4,    /* fd, msgvec, vlen, flags */
     };
     abi_long a[6]; /* max 6 args */
@@ -3536,10 +3565,10 @@ static abi_long do_socketcall(int num, abi_ulong vptr)
         return do_sendrecvmsg(a[0], a[1], a[2], 0);
     case TARGET_SYS_ACCEPT4: /* sockfd, addr, addrlen, flags */
         return do_accept4(a[0], a[1], a[2], a[3]);
-    case TARGET_SYS_RECVMMSG: /* sockfd, msgvec, vlen, flags */
-        return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 0);
+    case TARGET_SYS_RECVMMSG: /* sockfd, msgvec, vlen, flags, timeout */
+        return do_sendrecvmmsg(a[0], a[1], a[2], a[3], a[4], 0);
     case TARGET_SYS_SENDMMSG: /* sockfd, msgvec, vlen, flags */
-        return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 1);
+        return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 0, 1);
     default:
         qemu_log_mask(LOG_UNIMP, "Unsupported socketcall: %d\n", num);
         return -TARGET_EINVAL;
@@ -9343,11 +9372,11 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
 #endif
 #ifdef TARGET_NR_sendmmsg
     case TARGET_NR_sendmmsg:
-        return do_sendrecvmmsg(arg1, arg2, arg3, arg4, 1);
+        return do_sendrecvmmsg(arg1, arg2, arg3, arg4, 0, 1);
 #endif
 #ifdef TARGET_NR_recvmmsg
     case TARGET_NR_recvmmsg:
-        return do_sendrecvmmsg(arg1, arg2, arg3, arg4, 0);
+        return do_sendrecvmmsg(arg1, arg2, arg3, arg4, arg5, 0);
 #endif
 #ifdef TARGET_NR_sendto
     case TARGET_NR_sendto:
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH v2 2/2] linux-user: Add support for 'recvmmsg_time64()'
  2020-08-25 21:20 [PATCH v2 0/2] linux-user: Introducing support for 'recvmmsg_time64()' Filip Bozuta
  2020-08-25 21:20 ` [PATCH v2 1/2] linux-user: Modify 'recvmmsg()' implementation Filip Bozuta
@ 2020-08-25 21:20 ` Filip Bozuta
  1 sibling, 0 replies; 3+ messages in thread
From: Filip Bozuta @ 2020-08-25 21:20 UTC (permalink / raw)
  To: qemu-devel; +Cc: Riku Voipio, Laurent Vivier, Filip Bozuta

   This patch introduces functionality for syscall:

*recvmmsg_time64

    This syscall is a 2038 safe variant for syscall:

    int recvmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen,
                 int flags, struct timespec *timeout)
    --receive multiple messages on a socket--
    man page: https://man7.org/linux/man-pages/man2/recvmmsg.2.html

Implementation notes:

    Function 'do_sendrecvmmsg()' in 'syscall.c' was changed with the
    addition of a new argument 'time64' which represents a flag by
    which the function knows what kind of 'struct timespec' converting
    function to call ('target_to_host_timespec() or
    'target_to_host_timespec64()'). It is false in case of
    'TARGET_NR_recvmmsg' and true in case of 'TARGET_NR_recvmmsg_time64'.

    In 'do_socketcall()', the 'TARGET_ABI_BITS' was checked to know
    what value for 'time64' argument to pass.

Signed-off-by: Filip Bozuta <Filip.Bozuta@syrmia.com>
---
 linux-user/syscall.c | 27 +++++++++++++++++++--------
 1 file changed, 19 insertions(+), 8 deletions(-)

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index dc89bfacca..762eea0e5b 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -3197,7 +3197,7 @@ static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
 
 static abi_long do_sendrecvmmsg(int fd, abi_ulong target_msgvec,
                                 unsigned int vlen, unsigned int flags,
-                                abi_ulong timeout, int send)
+                                abi_ulong timeout, bool time64, int send)
 {
     struct target_mmsghdr *mmsgp;
     struct timespec ts, end_time, curr_time;
@@ -3212,8 +3212,14 @@ static abi_long do_sendrecvmmsg(int fd, abi_ulong target_msgvec,
         return -TARGET_EFAULT;
     }
     if (timeout) {
-        if (target_to_host_timespec(&ts, timeout)) {
-            return -TARGET_EFAULT;
+        if (time64) {
+            if (target_to_host_timespec64(&ts, timeout)) {
+                return -TARGET_EFAULT;
+            }
+        } else {
+            if (target_to_host_timespec(&ts, timeout)) {
+                return -TARGET_EFAULT;
+            }
         }
         if (ts.tv_sec < 0 || ts.tv_nsec < 0 || ts.tv_nsec > 1000000000) {
             return -TARGET_EINVAL;
@@ -3506,7 +3512,7 @@ static abi_long do_socketcall(int num, abi_ulong vptr)
         [TARGET_SYS_SENDMSG] = 3,     /* fd, msg, flags */
         [TARGET_SYS_RECVMSG] = 3,     /* fd, msg, flags */
         [TARGET_SYS_ACCEPT4] = 4,     /* fd, addr, addrlen, flags */
-        [TARGET_SYS_RECVMMSG] = 5,    /* fd, msgvec, vlen, flags, timeout */
+        [TARGET_SYS_RECVMMSG] = 6,    /* fd, msgvec, vlen, flags, timeout */
         [TARGET_SYS_SENDMMSG] = 4,    /* fd, msgvec, vlen, flags */
     };
     abi_long a[6]; /* max 6 args */
@@ -3566,9 +3572,10 @@ static abi_long do_socketcall(int num, abi_ulong vptr)
     case TARGET_SYS_ACCEPT4: /* sockfd, addr, addrlen, flags */
         return do_accept4(a[0], a[1], a[2], a[3]);
     case TARGET_SYS_RECVMMSG: /* sockfd, msgvec, vlen, flags, timeout */
-        return do_sendrecvmmsg(a[0], a[1], a[2], a[3], a[4], 0);
+        return do_sendrecvmmsg(a[0], a[1], a[2], a[3], a[4],
+                               TARGET_ABI_BITS == 64, 0);
     case TARGET_SYS_SENDMMSG: /* sockfd, msgvec, vlen, flags */
-        return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 0, 1);
+        return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 0, false, 1);
     default:
         qemu_log_mask(LOG_UNIMP, "Unsupported socketcall: %d\n", num);
         return -TARGET_EINVAL;
@@ -9372,11 +9379,15 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
 #endif
 #ifdef TARGET_NR_sendmmsg
     case TARGET_NR_sendmmsg:
-        return do_sendrecvmmsg(arg1, arg2, arg3, arg4, 0, 1);
+        return do_sendrecvmmsg(arg1, arg2, arg3, arg4, 0, false, 1);
 #endif
 #ifdef TARGET_NR_recvmmsg
     case TARGET_NR_recvmmsg:
-        return do_sendrecvmmsg(arg1, arg2, arg3, arg4, arg5, 0);
+        return do_sendrecvmmsg(arg1, arg2, arg3, arg4, arg5, false, 0);
+#endif
+#ifdef TARGET_NR_recvmmsg_time64
+    case TARGET_NR_recvmmsg_time64:
+        return do_sendrecvmmsg(arg1, arg2, arg3, arg4, arg5, true, 0);
 #endif
 #ifdef TARGET_NR_sendto
     case TARGET_NR_sendto:
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2020-08-25 21:34 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-08-25 21:20 [PATCH v2 0/2] linux-user: Introducing support for 'recvmmsg_time64()' Filip Bozuta
2020-08-25 21:20 ` [PATCH v2 1/2] linux-user: Modify 'recvmmsg()' implementation Filip Bozuta
2020-08-25 21:20 ` [PATCH v2 2/2] linux-user: Add support for 'recvmmsg_time64()' Filip Bozuta

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).