y2038: linux: Provide __recvmmsg_time64 implementation
Commit Message
This patch provides new __recvmmsg_time64 explicit 64 bit function for
receiving messages from a socket with absolute timeout.
Moreover, a 32 bit version - __recvmmsg has been refactored to internally use
__recvmmsg_time64.
The __recvmmsg is now supposed to be used on systems still supporting 32 bit time
(__TIMESIZE != 64) - hence the necessary conversion to 64 bit struct
__timespec64 from struct timespec.
The new recvmmsg_time64 syscall available from Linux 5.1+ has been used, when
applicable.
Build tests:
- ./src/scripts/build-many-glibcs.py glibcs
Run-time tests:
- Run specific tests on ARM/x86 32bit systems (qemu):
https://github.com/lmajewski/meta-y2038 and run tests:
https://github.com/lmajewski/y2038-tests/commits/master
Linux kernel, headers and minimal kernel version for glibc build test matrix:
- Linux v5.1 (with recvmmsg_time64) and glibc built with v5.1 as
minimal kernel version (--enable-kernel="5.1.0")
The __ASSUME_TIME64_SYSCALLS flag defined.
- Linux v5.1 and default minimal kernel version
The __ASSUME_TIME64_SYSCALLS not defined, but kernel supports recvmmsg_time64
syscall.
- Linux v4.19 (no recvmmsg_time64 support) with default minimal kernel version for
contemporary glibc (3.2.0)
This kernel doesn't support recvmmsg_time64 syscall, so the fallback to recvmmsg
is tested.
Above tests were performed with Y2038 redirection applied as well as without
(so the __TIMESIZE != 64 execution path is checked as well).
---
include/sys/socket.h | 10 +++++++
sysdeps/unix/sysv/linux/recvmmsg.c | 48 ++++++++++++++++++++++++++++--
2 files changed, 55 insertions(+), 3 deletions(-)
Comments
On Apr 08 2020, Lukasz Majewski wrote:
> +int
> +__recvmmsg (int fd, struct mmsghdr *vmessages, unsigned int vlen, int flags,
> + struct timespec *tmo)
> +{
> + struct __timespec64 ts64;
> +
> + if (tmo != NULL)
> + ts64 = valid_timespec_to_timespec64 (*tmo);
> +
> + return __recvmmsg_time64 (fd, vmessages, vlen, flags,
> + tmo != NULL ? &ts64 : NULL);
The timeout is a r/w operand.
Andreas.
Hi Andreas,
> On Apr 08 2020, Lukasz Majewski wrote:
>
> > +int
> > +__recvmmsg (int fd, struct mmsghdr *vmessages, unsigned int vlen,
> > int flags,
> > + struct timespec *tmo)
> > +{
> > + struct __timespec64 ts64;
> > +
> > + if (tmo != NULL)
> > + ts64 = valid_timespec_to_timespec64 (*tmo);
> > +
> > + return __recvmmsg_time64 (fd, vmessages, vlen, flags,
> > + tmo != NULL ? &ts64 : NULL);
>
> The timeout is a r/w operand.
Maybe I've wrongly looked on the manual of recvmmsg:
https://linux.die.net/man/2/recvmmsg
In this description there is no information about returning the time
left until the timeout expires.
The above documentation entry only mentions about timeout pointer being
NULL.
What do I miss?
>
> Andreas.
>
Best regards,
Lukasz Majewski
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-59 Fax: (+49)-8142-66989-80 Email: lukma@denx.de
On Apr 08 2020, Lukasz Majewski wrote:
> What do I miss?
There is no const.
Andreas.
08.04.2020 в 13:51:15 +0200 Lukasz Majewski написал:
> This patch provides new __recvmmsg_time64 explicit 64 bit function for
> receiving messages from a socket with absolute timeout.
> Moreover, a 32 bit version - __recvmmsg has been refactored to internally use
> __recvmmsg_time64.
>
> The __recvmmsg is now supposed to be used on systems still supporting 32 bit time
> (__TIMESIZE != 64) - hence the necessary conversion to 64 bit struct
> __timespec64 from struct timespec.
>
> The new recvmmsg_time64 syscall available from Linux 5.1+ has been used, when
> applicable.
>
> Build tests:
> - ./src/scripts/build-many-glibcs.py glibcs
>
> Run-time tests:
> - Run specific tests on ARM/x86 32bit systems (qemu):
> https://github.com/lmajewski/meta-y2038 and run tests:
> https://github.com/lmajewski/y2038-tests/commits/master
>
> Linux kernel, headers and minimal kernel version for glibc build test matrix:
> - Linux v5.1 (with recvmmsg_time64) and glibc built with v5.1 as
> minimal kernel version (--enable-kernel="5.1.0")
> The __ASSUME_TIME64_SYSCALLS flag defined.
>
> - Linux v5.1 and default minimal kernel version
> The __ASSUME_TIME64_SYSCALLS not defined, but kernel supports recvmmsg_time64
> syscall.
>
> - Linux v4.19 (no recvmmsg_time64 support) with default minimal kernel version for
> contemporary glibc (3.2.0)
> This kernel doesn't support recvmmsg_time64 syscall, so the fallback to recvmmsg
> is tested.
>
> Above tests were performed with Y2038 redirection applied as well as without
> (so the __TIMESIZE != 64 execution path is checked as well).
Note that this patch is broken for m68k and s390. And future
revisions of the patch have potential to break s390x running on
kernels older than 4.3.
> int
> -recvmmsg (int fd, struct mmsghdr *vmessages, unsigned int vlen, int flags,
> - struct timespec *tmo)
> +__recvmmsg_time64 (int fd, struct mmsghdr *vmessages, unsigned int vlen,
> + int flags, struct __timespec64 *tmo)
> {
> #ifdef __ASSUME_RECVMMSG_SYSCALL
> - return SYSCALL_CANCEL (recvmmsg, fd, vmessages, vlen, flags, tmo);
> +# ifdef __ASSUME_TIME64_SYSCALLS
> +# ifndef __NR_recvmmsg_time64
> +# define __NR_recvmmsg_time64 __NR_recvmmsg
> +# endif
> + return SYSCALL_CANCEL (recvmmsg_time64, fd, vmessages, vlen, flags, tmo);
> +# else
> + int ret = SYSCALL_CANCEL (recvmmsg_time64, fd, vmessages, vlen, flags, tmo);
> + if (ret == 0 || errno != ENOSYS)
> + return ret;
> +
> + struct timespec ts32;
> + if (tmo != NULL)
> + {
> + if (! in_time_t_range (tmo->tv_sec))
> + {
> + __set_errno (EOVERFLOW);
> + return -1;
> + }
> +
> + ts32 = valid_timespec64_to_timespec (*tmo);
> + }
> +
> + return SYSCALL_CANCEL (recvmmsg, fd, vmessages, vlen, flags,
> + tmo != NULL ? &ts32 : NULL);
> +# endif
> #else
> return SOCKETCALL_CANCEL (recvmmsg, fd, vmessages, vlen, flags, tmo);
> #endif
> }
!defined __ASSUME_RECVMMSG_SYSCALL case is broken for 32-bit
architectures. It can be done like this:
#ifdef __ASSUME_TIME64_SYSCALLS
# ifdef __ASSUME_RECVMMSG_SYSCALL
# ifndef __NR_recvmmsg_time64
# define __NR_recvmmsg_time64 __NR_recvmmsg
# endif
SYSCALL_CANCEL (recvmmsg_time64, …
# else
SOCKETCALL_CANCEL (recvmmsg, …
# endif
#else
SYSCALL_CANCEL (recvmmsg_time64, …
convert input
# ifdef __ASSUME_RECVMMSG_SYSCALL
SYSCALL_CANCEL (recvmmsg, …
# else
SOCKETCALL_CANCEL (recvmmsg, …
# endif
convert output
#endif
but I think Joseph opposed to __ASSUME_TIME64_SYSCALLS being used
here (and comment near __ASSUME_TIME64_SYSCALLS does not mention
recvmmsg).
Note that there are 5 relevant cases:
1. recvmmsg syscall always exists and uses 64-bit time_t.
2. recvmmsg_time64 syscall always exists.
3. socketcall always exists and uses 64-bit time_t.
4. recvmmsg syscall with 32-bit time_t and recvmmsg_time64 exist but
one of them may be unavailable at runtime (due to old or
!COMPAT_32BIT_TIME kernel).
5. socketcall with 32-bit time_t and recvmmsg_time64 exist but one of
them may be unavailable at runtime (due to old or !COMPAT_32BIT_TIME
kernel).
Hi Andreas,
> On Apr 08 2020, Lukasz Majewski wrote:
>
> > What do I miss?
>
> There is no const.
Ach... right.
Just informative - in the current glibc
(./sysdeps/unix/sysv/linux/recvmmsg.c) there is no const in *tmo
pointer type qualifier (only struct timespec *tmo).
>
> Andreas.
>
Best regards,
Lukasz Majewski
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-59 Fax: (+49)-8142-66989-80 Email: lukma@denx.de
Hi Stepan,
> 08.04.2020 в 13:51:15 +0200 Lukasz Majewski написал:
> > This patch provides new __recvmmsg_time64 explicit 64 bit function
> > for receiving messages from a socket with absolute timeout.
> > Moreover, a 32 bit version - __recvmmsg has been refactored to
> > internally use __recvmmsg_time64.
> >
> > The __recvmmsg is now supposed to be used on systems still
> > supporting 32 bit time (__TIMESIZE != 64) - hence the necessary
> > conversion to 64 bit struct __timespec64 from struct timespec.
> >
> > The new recvmmsg_time64 syscall available from Linux 5.1+ has been
> > used, when applicable.
> >
> > Build tests:
> > - ./src/scripts/build-many-glibcs.py glibcs
> >
> > Run-time tests:
> > - Run specific tests on ARM/x86 32bit systems (qemu):
> > https://github.com/lmajewski/meta-y2038 and run tests:
> > https://github.com/lmajewski/y2038-tests/commits/master
> >
> > Linux kernel, headers and minimal kernel version for glibc build
> > test matrix:
> > - Linux v5.1 (with recvmmsg_time64) and glibc built with v5.1 as
> > minimal kernel version (--enable-kernel="5.1.0")
> > The __ASSUME_TIME64_SYSCALLS flag defined.
> >
> > - Linux v5.1 and default minimal kernel version
> > The __ASSUME_TIME64_SYSCALLS not defined, but kernel supports
> > recvmmsg_time64 syscall.
> >
> > - Linux v4.19 (no recvmmsg_time64 support) with default minimal
> > kernel version for contemporary glibc (3.2.0)
> > This kernel doesn't support recvmmsg_time64 syscall, so the
> > fallback to recvmmsg is tested.
> >
> > Above tests were performed with Y2038 redirection applied as well
> > as without (so the __TIMESIZE != 64 execution path is checked as
> > well).
>
> Note that this patch is broken for m68k and s390. And future
> revisions of the patch have potential to break s390x running on
> kernels older than 4.3.
>
> > int
> > -recvmmsg (int fd, struct mmsghdr *vmessages, unsigned int vlen,
> > int flags,
> > - struct timespec *tmo)
> > +__recvmmsg_time64 (int fd, struct mmsghdr *vmessages, unsigned int
> > vlen,
> > + int flags, struct __timespec64 *tmo)
> > {
> > #ifdef __ASSUME_RECVMMSG_SYSCALL
> > - return SYSCALL_CANCEL (recvmmsg, fd, vmessages, vlen, flags,
> > tmo); +# ifdef __ASSUME_TIME64_SYSCALLS
> > +# ifndef __NR_recvmmsg_time64
> > +# define __NR_recvmmsg_time64 __NR_recvmmsg
> > +# endif
> > + return SYSCALL_CANCEL (recvmmsg_time64, fd, vmessages, vlen,
> > flags, tmo); +# else
> > + int ret = SYSCALL_CANCEL (recvmmsg_time64, fd, vmessages, vlen,
> > flags, tmo);
> > + if (ret == 0 || errno != ENOSYS)
> > + return ret;
> > +
> > + struct timespec ts32;
> > + if (tmo != NULL)
> > + {
> > + if (! in_time_t_range (tmo->tv_sec))
> > + {
> > + __set_errno (EOVERFLOW);
> > + return -1;
> > + }
> > +
> > + ts32 = valid_timespec64_to_timespec (*tmo);
> > + }
> > +
> > + return SYSCALL_CANCEL (recvmmsg, fd, vmessages, vlen, flags,
> > + tmo != NULL ? &ts32 : NULL);
> > +# endif
> > #else
> > return SOCKETCALL_CANCEL (recvmmsg, fd, vmessages, vlen, flags,
> > tmo); #endif
> > }
>
> !defined __ASSUME_RECVMMSG_SYSCALL case is broken for 32-bit
> architectures. It can be done like this:
>
> #ifdef __ASSUME_TIME64_SYSCALLS
> # ifdef __ASSUME_RECVMMSG_SYSCALL
> # ifndef __NR_recvmmsg_time64
> # define __NR_recvmmsg_time64 __NR_recvmmsg
> # endif
> SYSCALL_CANCEL (recvmmsg_time64, …
> # else
> SOCKETCALL_CANCEL (recvmmsg, …
> # endif
> #else
> SYSCALL_CANCEL (recvmmsg_time64, …
> convert input
> # ifdef __ASSUME_RECVMMSG_SYSCALL
> SYSCALL_CANCEL (recvmmsg, …
> # else
> SOCKETCALL_CANCEL (recvmmsg, …
> # endif
> convert output
> #endif
>
> but I think Joseph opposed to __ASSUME_TIME64_SYSCALLS being used
> here (and comment near __ASSUME_TIME64_SYSCALLS does not mention
> recvmmsg).
>
> Note that there are 5 relevant cases:
>
> 1. recvmmsg syscall always exists and uses 64-bit time_t.
> 2. recvmmsg_time64 syscall always exists.
> 3. socketcall always exists and uses 64-bit time_t.
> 4. recvmmsg syscall with 32-bit time_t and recvmmsg_time64 exist but
> one of them may be unavailable at runtime (due to old or
> !COMPAT_32BIT_TIME kernel).
> 5. socketcall with 32-bit time_t and recvmmsg_time64 exist but one of
> them may be unavailable at runtime (due to old or !COMPAT_32BIT_TIME
> kernel).
I've grepped the sources and it seems like the
__ASSUME_RECVMMSG_SYSCALL is undefined only for m68k and s390 when the
kernel is less than 4.3 (as you pointed out above).
IMHO, there is no hurry to accept this patch and I think that it would
be better to wait for glibc minimal supported kernel is bumped above
4.3 and apply this patch then.
The same situation is with statx being always available (for all
supported archs) after 4.13 Linux.
Best regards,
Lukasz Majewski
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-59 Fax: (+49)-8142-66989-80 Email: lukma@denx.de
Best regards,
Lukasz Majewski
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-59 Fax: (+49)-8142-66989-80 Email: lukma@denx.de
@@ -96,6 +96,16 @@ extern ssize_t __sendmsg (int __fd, const struct msghdr *__message,
extern int __sendmmsg (int __fd, struct mmsghdr *__vmessages,
unsigned int __vlen, int __flags);
libc_hidden_proto (__sendmmsg)
+
+# include <struct___timespec64.h>
+# if __TIMESIZE == 64
+# define __recvmmsg_time64 __recvmmsg
+# else
+extern int __recvmmsg_time64 (int fd, struct mmsghdr *vmessages,
+ unsigned int vlen, int flags,
+ struct __timespec64 *tmo);
+libc_hidden_proto (__recvmmsg_time64)
+# endif
#endif
/* Receive a message as described by MESSAGE from socket FD.
@@ -25,12 +25,54 @@
#include <kernel-features.h>
int
-recvmmsg (int fd, struct mmsghdr *vmessages, unsigned int vlen, int flags,
- struct timespec *tmo)
+__recvmmsg_time64 (int fd, struct mmsghdr *vmessages, unsigned int vlen,
+ int flags, struct __timespec64 *tmo)
{
#ifdef __ASSUME_RECVMMSG_SYSCALL
- return SYSCALL_CANCEL (recvmmsg, fd, vmessages, vlen, flags, tmo);
+# ifdef __ASSUME_TIME64_SYSCALLS
+# ifndef __NR_recvmmsg_time64
+# define __NR_recvmmsg_time64 __NR_recvmmsg
+# endif
+ return SYSCALL_CANCEL (recvmmsg_time64, fd, vmessages, vlen, flags, tmo);
+# else
+ int ret = SYSCALL_CANCEL (recvmmsg_time64, fd, vmessages, vlen, flags, tmo);
+ if (ret == 0 || errno != ENOSYS)
+ return ret;
+
+ struct timespec ts32;
+ if (tmo != NULL)
+ {
+ if (! in_time_t_range (tmo->tv_sec))
+ {
+ __set_errno (EOVERFLOW);
+ return -1;
+ }
+
+ ts32 = valid_timespec64_to_timespec (*tmo);
+ }
+
+ return SYSCALL_CANCEL (recvmmsg, fd, vmessages, vlen, flags,
+ tmo != NULL ? &ts32 : NULL);
+# endif
#else
return SOCKETCALL_CANCEL (recvmmsg, fd, vmessages, vlen, flags, tmo);
#endif
}
+
+#if __TIMESIZE != 64
+libc_hidden_def (__recvmmsg_time64)
+
+int
+__recvmmsg (int fd, struct mmsghdr *vmessages, unsigned int vlen, int flags,
+ struct timespec *tmo)
+{
+ struct __timespec64 ts64;
+
+ if (tmo != NULL)
+ ts64 = valid_timespec_to_timespec64 (*tmo);
+
+ return __recvmmsg_time64 (fd, vmessages, vlen, flags,
+ tmo != NULL ? &ts64 : NULL);
+}
+#endif
+strong_alias (__recvmmsg, recvmmsg)