[v2] sysv: linux: Add 64-bit time_t variant for msgctl

Message ID 20200708153216.3148801-1-adhemerval.zanella@linaro.org
State Committed
Headers
Series [v2] sysv: linux: Add 64-bit time_t variant for msgctl |

Commit Message

Adhemerval Zanella July 8, 2020, 3:32 p.m. UTC
  This is a small updated version that basically does:

  git mv include/sys/msg.h sysdeps/unix/sysv/linux/include/sys/msg.h

It moves the sysvipc to be Linux specific, since the generic version
does implement _libc_msgsnd or __libc_msgrcv; and avoid a build failure
on Hurd (since it does not provide struct_msqid64_ds.h).

---

To provide a y2038 safe interface a new symbol __msgctl64 is added
and __msgctl is change to call it instead (it adds some extra buffer
coping for the 32 bit time_t implementation).

Two new structures are added:

  1. kernel_msqid64_ds: used internally only on 32-bit architectures
     to issue the syscall.  A handful of architectures (hppa, i386, mips,
     powerpc32, and sparc32) require specific implementations due to
     their kernel ABI.

  2. msqid_ds64: this is only for __TIMESIZE != 64 to use along with
     the 64-bit semctl.  It is different than the kernel struct because
     the exported 64-bit time_t might require different alignment
     depending on the architecture ABI.

So the resulting implementation does:

  1. For 64-bit architectures it assumes msqid_ds already contains
     64-bit time_t fields and will result in just the __msgctl symbol
     using the __msgctl64 code.  The msgid_ds argument is passed as-is
     to the syscall.

  2. For 32-bit architectures with default 64-bit time_t (newer ABIs
     such riscv32 or arc), it will also result in only one exported
     symbol but with the required high/low time handling.

  3. Finally for 32-bit architecture with both 32-bit and 64-bit time_t
     support we follow the already set way to provide one symbol with
     64-bit time_t support and implement the 32-bit time_t support using
     the 64-bit time_t.

     The default 32-bit symbol will allocate and copy the msqid_ds
     over multiple buffers, but this should be deprecated in favor
     of the __msgctl64 anyway.

Checked on i686-linux-gnu and x86_64-linux-gnu.  I also did some sniff
tests on powerpc, powerpc64, mips, mips64, armhf, sparcv9, and
sparc64.

Tested-by: Carlos O'Donell <carlos@redhat.com>
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
---
 .../sysv/linux/bits/types/struct_msqid64_ds.h |  38 ++++
 .../sysv/linux/bits/types/struct_msqid_ds.h   |   6 +-
 .../linux/hppa/bits/types/struct_msqid_ds.h   |   6 +-
 .../linux/hppa/struct_kernel_msqid64_ds.h     |  18 ++
 .../linux/i386/struct_kernel_msqid64_ds.h     |  18 ++
 .../unix/sysv/linux/include}/sys/msg.h        |  10 +
 .../linux/mips/bits/types/struct_msqid_ds.h   |  12 +-
 .../linux/mips/struct_kernel_msqid64_ds.h     |  33 ++++
 sysdeps/unix/sysv/linux/msgctl.c              | 179 ++++++++++++++----
 .../powerpc/bits/types/struct_msqid_ds.h      |   6 +-
 .../powerpc32/struct_kernel_msqid64_ds.h      |  18 ++
 sysdeps/unix/sysv/linux/semctl.c              |  27 +--
 .../linux/sparc/bits/types/struct_msqid_ds.h  |   6 +-
 .../sparc/sparc32/struct_kernel_msqid64_ds.h  |  18 ++
 .../sysv/linux/struct_kernel_msqid64_ds.h     |  19 ++
 15 files changed, 350 insertions(+), 64 deletions(-)
 create mode 100644 sysdeps/unix/sysv/linux/bits/types/struct_msqid64_ds.h
 create mode 100644 sysdeps/unix/sysv/linux/hppa/struct_kernel_msqid64_ds.h
 create mode 100644 sysdeps/unix/sysv/linux/i386/struct_kernel_msqid64_ds.h
 rename {include => sysdeps/unix/sysv/linux/include}/sys/msg.h (55%)
 create mode 100644 sysdeps/unix/sysv/linux/mips/struct_kernel_msqid64_ds.h
 create mode 100644 sysdeps/unix/sysv/linux/powerpc/powerpc32/struct_kernel_msqid64_ds.h
 create mode 100644 sysdeps/unix/sysv/linux/sparc/sparc32/struct_kernel_msqid64_ds.h
 create mode 100644 sysdeps/unix/sysv/linux/struct_kernel_msqid64_ds.h
  

Comments

Carlos O'Donell July 8, 2020, 5:04 p.m. UTC | #1
On 7/8/20 11:32 AM, Adhemerval Zanella wrote:
> This is a small updated version that basically does:
> 
>   git mv include/sys/msg.h sysdeps/unix/sysv/linux/include/sys/msg.h
> 
> It moves the sysvipc to be Linux specific, since the generic version
> does implement _libc_msgsnd or __libc_msgrcv; and avoid a build failure
> on Hurd (since it does not provide struct_msqid64_ds.h).

OK for 2.32.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
 
> ---
> 
> To provide a y2038 safe interface a new symbol __msgctl64 is added
> and __msgctl is change to call it instead (it adds some extra buffer
> coping for the 32 bit time_t implementation).
> 
> Two new structures are added:
> 
>   1. kernel_msqid64_ds: used internally only on 32-bit architectures
>      to issue the syscall.  A handful of architectures (hppa, i386, mips,
>      powerpc32, and sparc32) require specific implementations due to
>      their kernel ABI.
> 
>   2. msqid_ds64: this is only for __TIMESIZE != 64 to use along with
>      the 64-bit semctl.  It is different than the kernel struct because
>      the exported 64-bit time_t might require different alignment
>      depending on the architecture ABI.
> 
> So the resulting implementation does:
> 
>   1. For 64-bit architectures it assumes msqid_ds already contains
>      64-bit time_t fields and will result in just the __msgctl symbol
>      using the __msgctl64 code.  The msgid_ds argument is passed as-is
>      to the syscall.
> 
>   2. For 32-bit architectures with default 64-bit time_t (newer ABIs
>      such riscv32 or arc), it will also result in only one exported
>      symbol but with the required high/low time handling.
> 
>   3. Finally for 32-bit architecture with both 32-bit and 64-bit time_t
>      support we follow the already set way to provide one symbol with
>      64-bit time_t support and implement the 32-bit time_t support using
>      the 64-bit time_t.
> 
>      The default 32-bit symbol will allocate and copy the msqid_ds
>      over multiple buffers, but this should be deprecated in favor
>      of the __msgctl64 anyway.
> 
> Checked on i686-linux-gnu and x86_64-linux-gnu.  I also did some sniff
> tests on powerpc, powerpc64, mips, mips64, armhf, sparcv9, and
> sparc64.
> 
> Tested-by: Carlos O'Donell <carlos@redhat.com>
> Reviewed-by: Carlos O'Donell <carlos@redhat.com>
> ---
>  .../sysv/linux/bits/types/struct_msqid64_ds.h |  38 ++++
>  .../sysv/linux/bits/types/struct_msqid_ds.h   |   6 +-
>  .../linux/hppa/bits/types/struct_msqid_ds.h   |   6 +-
>  .../linux/hppa/struct_kernel_msqid64_ds.h     |  18 ++
>  .../linux/i386/struct_kernel_msqid64_ds.h     |  18 ++
>  .../unix/sysv/linux/include}/sys/msg.h        |  10 +
>  .../linux/mips/bits/types/struct_msqid_ds.h   |  12 +-
>  .../linux/mips/struct_kernel_msqid64_ds.h     |  33 ++++
>  sysdeps/unix/sysv/linux/msgctl.c              | 179 ++++++++++++++----
>  .../powerpc/bits/types/struct_msqid_ds.h      |   6 +-
>  .../powerpc32/struct_kernel_msqid64_ds.h      |  18 ++
>  sysdeps/unix/sysv/linux/semctl.c              |  27 +--
>  .../linux/sparc/bits/types/struct_msqid_ds.h  |   6 +-
>  .../sparc/sparc32/struct_kernel_msqid64_ds.h  |  18 ++
>  .../sysv/linux/struct_kernel_msqid64_ds.h     |  19 ++
>  15 files changed, 350 insertions(+), 64 deletions(-)
>  create mode 100644 sysdeps/unix/sysv/linux/bits/types/struct_msqid64_ds.h
>  create mode 100644 sysdeps/unix/sysv/linux/hppa/struct_kernel_msqid64_ds.h
>  create mode 100644 sysdeps/unix/sysv/linux/i386/struct_kernel_msqid64_ds.h
>  rename {include => sysdeps/unix/sysv/linux/include}/sys/msg.h (55%)
>  create mode 100644 sysdeps/unix/sysv/linux/mips/struct_kernel_msqid64_ds.h
>  create mode 100644 sysdeps/unix/sysv/linux/powerpc/powerpc32/struct_kernel_msqid64_ds.h
>  create mode 100644 sysdeps/unix/sysv/linux/sparc/sparc32/struct_kernel_msqid64_ds.h
>  create mode 100644 sysdeps/unix/sysv/linux/struct_kernel_msqid64_ds.h
> 
> diff --git a/sysdeps/unix/sysv/linux/bits/types/struct_msqid64_ds.h b/sysdeps/unix/sysv/linux/bits/types/struct_msqid64_ds.h
> new file mode 100644
> index 0000000000..3536c8ea62
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/bits/types/struct_msqid64_ds.h
> @@ -0,0 +1,38 @@
> +/* Generic implementation of the SysV message struct msqid64_ds.
> +   Copyright (C) 2020 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#ifndef _SYS_MSG_H
> +# error "Never use <bits/msq.h> directly; include <sys/msg.h> instead."
> +#endif
> +
> +#if __TIMESIZE == 64
> +# define __msqid64_ds msqid_ds
> +#else
> +struct __msqid64_ds
> +{
> +  struct ipc_perm msg_perm;	/* structure describing operation permission */
> +  __time64_t msg_stime;		/* time of last msgsnd command */
> +  __time64_t msg_rtime;		/* time of last msgsnd command */
> +  __time64_t msg_ctime;		/* time of last change */
> +  __syscall_ulong_t __msg_cbytes; /* current number of bytes on queue */
> +  msgqnum_t msg_qnum;		/* number of messages currently on queue */
> +  msglen_t msg_qbytes;		/* max number of bytes allowed on queue */
> +  __pid_t msg_lspid;		/* pid of last msgsnd() */
> +  __pid_t msg_lrpid;		/* pid of last msgrcv() */
> +};
> +#endif
> diff --git a/sysdeps/unix/sysv/linux/bits/types/struct_msqid_ds.h b/sysdeps/unix/sysv/linux/bits/types/struct_msqid_ds.h
> index 32173a7b60..43b38175ad 100644
> --- a/sysdeps/unix/sysv/linux/bits/types/struct_msqid_ds.h
> +++ b/sysdeps/unix/sysv/linux/bits/types/struct_msqid_ds.h
> @@ -27,11 +27,11 @@ struct msqid_ds
>    struct ipc_perm msg_perm;	/* structure describing operation permission */
>  #if __TIMESIZE == 32
>    __time_t msg_stime;		/* time of last msgsnd command */
> -  unsigned long int __glibc_reserved1;
> +  unsigned long int __msg_stime_high;
>    __time_t msg_rtime;		/* time of last msgsnd command */
> -  unsigned long int __glibc_reserved2;
> +  unsigned long int __msg_rtime_high;
>    __time_t msg_ctime;		/* time of last change */
> -  unsigned long int __glibc_reserved3;
> +  unsigned long int __msg_ctime_high;
>  #else
>    __time_t msg_stime;		/* time of last msgsnd command */
>    __time_t msg_rtime;		/* time of last msgsnd command */
> diff --git a/sysdeps/unix/sysv/linux/hppa/bits/types/struct_msqid_ds.h b/sysdeps/unix/sysv/linux/hppa/bits/types/struct_msqid_ds.h
> index 3cf70e36c4..16eac46941 100644
> --- a/sysdeps/unix/sysv/linux/hppa/bits/types/struct_msqid_ds.h
> +++ b/sysdeps/unix/sysv/linux/hppa/bits/types/struct_msqid_ds.h
> @@ -26,11 +26,11 @@ struct msqid_ds
>  {
>    struct ipc_perm msg_perm;	/* structure describing operation permission */
>  #if __TIMESIZE == 32
> -  unsigned long int __glibc_reserved1;
> +  unsigned long int __msg_stime_high;
>    __time_t msg_stime;		/* time of last msgsnd command */
> -  unsigned long int __glibc_reserved2;
> +  unsigned long int __msg_rtime_high;
>    __time_t msg_rtime;		/* time of last msgsnd command */
> -  unsigned long int __glibc_reserved3;
> +  unsigned long int __msg_ctime_high;
>    __time_t msg_ctime;		/* time of last change */
>  #else
>    __time_t msg_stime;		/* time of last msgsnd command */
> diff --git a/sysdeps/unix/sysv/linux/hppa/struct_kernel_msqid64_ds.h b/sysdeps/unix/sysv/linux/hppa/struct_kernel_msqid64_ds.h
> new file mode 100644
> index 0000000000..69a63ee27a
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/hppa/struct_kernel_msqid64_ds.h
> @@ -0,0 +1,18 @@
> +/* Analogous to kernel struct msqid64_ds used on msgctl.  */
> +struct kernel_msqid64_ds
> +{
> +  struct ipc_perm msg_perm;
> +  unsigned long msg_stime_high;
> +  unsigned long msg_stime;
> +  unsigned long msg_rtime_high;
> +  unsigned long msg_rtime;
> +  unsigned long msg_ctime_high;
> +  unsigned long msg_ctime;
> +  unsigned long msg_cbytes;
> +  unsigned long msg_qnum;
> +  unsigned long msg_qbytes;
> +  __pid_t msg_lspid;
> +  __pid_t msg_lrpid;
> +  unsigned long __unused1;
> +  unsigned long __unused2;
> +};
> diff --git a/sysdeps/unix/sysv/linux/i386/struct_kernel_msqid64_ds.h b/sysdeps/unix/sysv/linux/i386/struct_kernel_msqid64_ds.h
> new file mode 100644
> index 0000000000..65b940567b
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/i386/struct_kernel_msqid64_ds.h
> @@ -0,0 +1,18 @@
> +/* Analogous to kernel struct compat_msqid64_ds used on msgctl.  */
> +struct kernel_msqid64_ds
> +{
> +  struct ipc_perm msg_perm;
> +  unsigned long msg_stime;
> +  unsigned long msg_stime_high;
> +  unsigned long msg_rtime;
> +  unsigned long msg_rtime_high;
> +  unsigned long msg_ctime;
> +  unsigned long msg_ctime_high;
> +  unsigned long msg_cbytes;
> +  unsigned long msg_qnum;
> +  unsigned long msg_qbytes;
> +  __pid_t msg_lspid;
> +  __pid_t msg_lrpid;
> +  unsigned long __unused1;
> +  unsigned long __unused2;
> +};
> diff --git a/include/sys/msg.h b/sysdeps/unix/sysv/linux/include/sys/msg.h
> similarity index 55%
> rename from include/sys/msg.h
> rename to sysdeps/unix/sysv/linux/include/sys/msg.h
> index 43ec5b9472..522903f818 100644
> --- a/include/sys/msg.h
> +++ b/sysdeps/unix/sysv/linux/include/sys/msg.h
> @@ -6,6 +6,16 @@ extern ssize_t __libc_msgrcv (int msqid, void *msgp, size_t msgsz,
>  			      long int msgtyp, int msgflg);
>  extern int __libc_msgsnd (int msqid, const void *msgp, size_t msgsz,
>  			  int msgflg);
> +
> +# include <bits/types/struct_msqid64_ds.h>
> +
> +# if __TIMESIZE == 64
> +#  define __msgctl64 __msgctl
> +# else
> +extern int __msgctl64 (int msqid, int cmd, struct __msqid64_ds *buf);
> +libc_hidden_proto (__msgctl64);
> +# endif
> +
>  #endif
>  
>  #endif
> diff --git a/sysdeps/unix/sysv/linux/mips/bits/types/struct_msqid_ds.h b/sysdeps/unix/sysv/linux/mips/bits/types/struct_msqid_ds.h
> index 85fdeef274..9ff010c763 100644
> --- a/sysdeps/unix/sysv/linux/mips/bits/types/struct_msqid_ds.h
> +++ b/sysdeps/unix/sysv/linux/mips/bits/types/struct_msqid_ds.h
> @@ -28,17 +28,17 @@ struct msqid_ds
>  #if __TIMESIZE == 32
>  # ifdef __MIPSEL__
>    __time_t msg_stime;		/* time of last msgsnd command */
> -  unsigned long int __glibc_reserved1;
> +  unsigned long int __msg_stime_high;
>    __time_t msg_rtime;		/* time of last msgsnd command */
> -  unsigned long int __glibc_reserved2;
> +  unsigned long int __msg_rtime_high;
>    __time_t msg_ctime;		/* time of last change */
> -  unsigned long int __glibc_reserved3;
> +  unsigned long int __msg_ctime_high;
>  # else
> -  unsigned long int __glibc_reserved1;
> +  unsigned long int __msg_stime_high;
>    __time_t msg_stime;		/* time of last msgsnd command */
> -  unsigned long int __glibc_reserved2;
> +  unsigned long int __msg_rtime_high;
>    __time_t msg_rtime;		/* time of last msgsnd command */
> -  unsigned long int __glibc_reserved3;
> +  unsigned long int __msg_ctime_high;
>    __time_t msg_ctime;		/* time of last change */
>  # endif
>  #else
> diff --git a/sysdeps/unix/sysv/linux/mips/struct_kernel_msqid64_ds.h b/sysdeps/unix/sysv/linux/mips/struct_kernel_msqid64_ds.h
> new file mode 100644
> index 0000000000..9cfd5a0dfe
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/mips/struct_kernel_msqid64_ds.h
> @@ -0,0 +1,33 @@
> +/* Analogous to kernel struct msqid64_ds used on msgctl.  */
> +struct kernel_msqid64_ds
> +{
> +  struct ipc_perm msg_perm;
> +#if __TIMESIZE == 32
> +# ifdef __MIPSEL__
> +  unsigned long int msg_stime;
> +  unsigned long int msg_stime_high;
> +  unsigned long int msg_rtime;
> +  unsigned long int msg_rtime_high;
> +  unsigned long int msg_ctime;
> +  unsigned long int msg_ctime_high;
> +# else
> +  unsigned long int msg_stime_high;
> +  unsigned long int msg_stime;
> +  unsigned long int msg_rtime_high;
> +  unsigned long int msg_rtime;
> +  unsigned long int msg_ctime_high;
> +  unsigned long int msg_ctime;
> +# endif
> +#else
> +  unsigned long int msg_stime;
> +  unsigned long int msg_rtime;
> +  unsigned long int msg_ctime;
> +#endif
> +  unsigned long int msg_cbytes;
> +  unsigned long int msg_qnum;
> +  unsigned long int msg_qbytes;
> +  __pid_t msg_lspid;
> +  __pid_t msg_lrpid;
> +  unsigned long int __unused1;
> +  unsigned long int __unused2;
> +};
> diff --git a/sysdeps/unix/sysv/linux/msgctl.c b/sysdeps/unix/sysv/linux/msgctl.c
> index fd46aec1a0..a7f7651280 100644
> --- a/sysdeps/unix/sysv/linux/msgctl.c
> +++ b/sysdeps/unix/sysv/linux/msgctl.c
> @@ -23,16 +23,55 @@
>  #include <errno.h>
>  #include <linux/posix_types.h>  /* For __kernel_mode_t.  */
>  
> -#ifndef DEFAULT_VERSION
> -# ifndef __ASSUME_SYSVIPC_BROKEN_MODE_T
> -#  define DEFAULT_VERSION GLIBC_2_2
> -# else
> -#  define DEFAULT_VERSION GLIBC_2_31
> -# endif
> +/* POSIX states ipc_perm mode should have type of mode_t.  */
> +_Static_assert (sizeof ((struct msqid_ds){0}.msg_perm.mode)
> +		== sizeof (mode_t),
> +		"sizeof (msqid_ds.msg_perm.mode) != sizeof (mode_t)");
> +
> +#if __IPC_TIME64 == 0
> +typedef struct msqid_ds msgctl_arg_t;
> +#else
> +# include <struct_kernel_msqid64_ds.h>
> +
> +static void
> +msqid64_to_kmsqid64 (const struct __msqid64_ds *msqid64,
> +		     struct kernel_msqid64_ds *kmsqid)
> +{
> +  kmsqid->msg_perm       = msqid64->msg_perm;
> +  kmsqid->msg_stime      = msqid64->msg_stime;
> +  kmsqid->msg_stime_high = msqid64->msg_stime >> 32;
> +  kmsqid->msg_rtime      = msqid64->msg_rtime;
> +  kmsqid->msg_rtime_high = msqid64->msg_rtime >> 32;
> +  kmsqid->msg_ctime      = msqid64->msg_ctime;
> +  kmsqid->msg_ctime_high = msqid64->msg_ctime >> 32;
> +  kmsqid->msg_qnum       = msqid64->msg_qnum;
> +  kmsqid->msg_qbytes     = msqid64->msg_qbytes;
> +  kmsqid->msg_lspid      = msqid64->msg_lspid;
> +  kmsqid->msg_lrpid      = msqid64->msg_lrpid;
> +}
> +
> +static void
> +kmsqid64_to_msqid64 (const struct kernel_msqid64_ds *kmsqid,
> +		     struct __msqid64_ds *msqid64)
> +{
> +  msqid64->msg_perm   = kmsqid->msg_perm;
> +  msqid64->msg_stime  = kmsqid->msg_stime
> +		        | ((__time64_t) kmsqid->msg_stime_high << 32);
> +  msqid64->msg_rtime  = kmsqid->msg_rtime
> +		        | ((__time64_t) kmsqid->msg_rtime_high << 32);
> +  msqid64->msg_ctime  = kmsqid->msg_ctime
> +		        | ((__time64_t) kmsqid->msg_ctime_high << 32);
> +  msqid64->msg_qnum   = kmsqid->msg_qnum;
> +  msqid64->msg_qbytes = kmsqid->msg_qbytes;
> +  msqid64->msg_lspid  = kmsqid->msg_lspid;
> +  msqid64->msg_lrpid  = kmsqid->msg_lrpid;
> +}
> +
> +typedef struct kernel_msqid64_ds msgctl_arg_t;
>  #endif
>  
>  static int
> -msgctl_syscall (int msqid, int cmd, struct msqid_ds *buf)
> +msgctl_syscall (int msqid, int cmd, msgctl_arg_t *buf)
>  {
>  #ifdef __ASSUME_DIRECT_SYSVIPC_SYSCALLS
>    return INLINE_SYSCALL_CALL (msgctl, msqid, cmd | __IPC_64, buf);
> @@ -43,46 +82,118 @@ msgctl_syscall (int msqid, int cmd, struct msqid_ds *buf)
>  }
>  
>  int
> -__new_msgctl (int msqid, int cmd, struct msqid_ds *buf)
> +__msgctl64 (int msqid, int cmd, struct __msqid64_ds *buf)
>  {
> -  /* POSIX states ipc_perm mode should have type of mode_t.  */
> -  _Static_assert (sizeof ((struct msqid_ds){0}.msg_perm.mode)
> -		  == sizeof (mode_t),
> -		  "sizeof (msqid_ds.msg_perm.mode) != sizeof (mode_t)");
> -
> -#ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
> -  struct msqid_ds tmpds;
> -  if (cmd == IPC_SET)
> +#if __IPC_TIME64
> +  struct kernel_msqid64_ds ksemid, *arg = NULL;
> +  if (buf != NULL)
>      {
> -      tmpds = *buf;
> -      tmpds.msg_perm.mode *= 0x10000U;
> -      buf = &tmpds;
> +      msqid64_to_kmsqid64 (buf, &ksemid);
> +      arg = &ksemid;
>      }
> +# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
> +  if (cmd == IPC_SET)
> +    arg->msg_perm.mode *= 0x10000U;
> +# endif
> +#else
> +  msgctl_arg_t *arg = buf;
>  #endif
>  
> -  int ret = msgctl_syscall (msqid, cmd, buf);
> +  int ret = msgctl_syscall (msqid, cmd, arg);
> +  if (ret < 0)
> +    return ret;
>  
> -  if (ret >= 0)
> +  switch (cmd)
>      {
> -      switch (cmd)
> -	{
> -	case IPC_STAT:
> -	case MSG_STAT:
> -	case MSG_STAT_ANY:
> +    case IPC_STAT:
> +    case MSG_STAT:
> +    case MSG_STAT_ANY:
>  #ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
> -	  buf->msg_perm.mode >>= 16;
> +      arg->msg_perm.mode >>= 16;
>  #else
> -	  /* Old Linux kernel versions might not clear the mode padding.  */
> -	  if (sizeof ((struct msqid_ds){0}.msg_perm.mode)
> -	      != sizeof (__kernel_mode_t))
> -	    buf->msg_perm.mode &= 0xFFFF;
> +      /* Old Linux kernel versions might not clear the mode padding.  */
> +      if (sizeof ((struct msqid_ds){0}.msg_perm.mode)
> +          != sizeof (__kernel_mode_t))
> +	arg->msg_perm.mode &= 0xFFFF;
> +#endif
> +
> +#if __IPC_TIME64
> +      kmsqid64_to_msqid64 (arg, buf);
>  #endif
> -	}
>      }
>  
>    return ret;
>  }
> -versioned_symbol (libc, __new_msgctl, msgctl, DEFAULT_VERSION);
> +#if __TIMESIZE != 64
> +libc_hidden_def (__msgctl64)
> +
> +static void
> +msqid_to_msqid64 (struct __msqid64_ds *mq64, const struct msqid_ds *mq)
> +{
> +  mq64->msg_perm   = mq->msg_perm;
> +  mq64->msg_stime  = mq->msg_stime
> +		     | ((__time64_t) mq->__msg_stime_high << 32);
> +  mq64->msg_rtime  = mq->msg_rtime
> +		     | ((__time64_t) mq->__msg_rtime_high << 32);
> +  mq64->msg_ctime  = mq->msg_ctime
> +		     | ((__time64_t) mq->__msg_ctime_high << 32);
> +  mq64->msg_qnum   = mq->msg_qnum;
> +  mq64->msg_qbytes = mq->msg_qbytes;
> +  mq64->msg_lspid  = mq->msg_lspid;
> +  mq64->msg_lrpid  = mq->msg_lrpid;
> +}
> +
> +static void
> +msqid64_to_msqid (struct msqid_ds *mq, const struct __msqid64_ds *mq64)
> +{
> +  mq->msg_perm         = mq64->msg_perm;
> +  mq->msg_stime        = mq64->msg_stime;
> +  mq->__msg_stime_high = 0;
> +  mq->msg_rtime        = mq64->msg_rtime;
> +  mq->__msg_rtime_high = 0;
> +  mq->msg_ctime        = mq64->msg_ctime;
> +  mq->__msg_ctime_high = 0;
> +  mq->msg_qnum         = mq64->msg_qnum;
> +  mq->msg_qbytes       = mq64->msg_qbytes;
> +  mq->msg_lspid        = mq64->msg_lspid;
> +  mq->msg_lrpid        = mq64->msg_lrpid;
> +}
> +
> +int
> +__msgctl (int msqid, int cmd, struct msqid_ds *buf)
> +{
> +  struct __msqid64_ds msqid64, *buf64 = NULL;
> +  if (buf != NULL)
> +    {
> +      msqid_to_msqid64 (&msqid64, buf);
> +      buf64 = &msqid64;
> +    }
> +
> +  int ret = __msgctl64 (msqid, cmd, buf64);
> +  if (ret < 0)
> +    return ret;
> +
> +  switch (cmd)
> +    {
> +    case IPC_STAT:
> +    case MSG_STAT:
> +    case MSG_STAT_ANY:
> +      if (buf64 != NULL)
> +        msqid64_to_msqid (buf, buf64);
> +    }
> +
> +  return ret;
> +}
> +#endif
> +
> +#ifndef DEFAULT_VERSION
> +# ifndef __ASSUME_SYSVIPC_BROKEN_MODE_T
> +#  define DEFAULT_VERSION GLIBC_2_2
> +# else
> +#  define DEFAULT_VERSION GLIBC_2_31
> +# endif
> +#endif
> +versioned_symbol (libc, __msgctl, msgctl, DEFAULT_VERSION);
>  
>  #if defined __ASSUME_SYSVIPC_BROKEN_MODE_T \
>      && SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_31)
> @@ -90,7 +201,7 @@ int
>  attribute_compat_text_section
>  __msgctl_mode16 (int msqid, int cmd, struct msqid_ds *buf)
>  {
> -  return msgctl_syscall (msqid, cmd, buf);
> +  return msgctl_syscall (msqid, cmd, (msgctl_arg_t *) buf);
>  }
>  compat_symbol (libc, __msgctl_mode16, msgctl, GLIBC_2_2);
>  #endif
> diff --git a/sysdeps/unix/sysv/linux/powerpc/bits/types/struct_msqid_ds.h b/sysdeps/unix/sysv/linux/powerpc/bits/types/struct_msqid_ds.h
> index 4ae2fbcbdc..35cc51f733 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/bits/types/struct_msqid_ds.h
> +++ b/sysdeps/unix/sysv/linux/powerpc/bits/types/struct_msqid_ds.h
> @@ -26,11 +26,11 @@ struct msqid_ds
>  {
>    struct ipc_perm msg_perm;	/* structure describing operation permission */
>  #if __TIMESIZE == 32
> -  unsigned long int __glibc_reserved1;
> +  unsigned long int __msg_stime_high;
>    __time_t msg_stime;		/* time of last msgsnd command */
> -  unsigned long int __glibc_reserved2;
> +  unsigned long int __msg_rtime_high;
>    __time_t msg_rtime;		/* time of last msgsnd command */
> -  unsigned long int __glibc_reserved3;
> +  unsigned long int __msg_ctime_high;
>    __time_t msg_ctime;		/* time of last change */
>  #else
>    __time_t msg_stime;		/* time of last msgsnd command */
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/struct_kernel_msqid64_ds.h b/sysdeps/unix/sysv/linux/powerpc/powerpc32/struct_kernel_msqid64_ds.h
> new file mode 100644
> index 0000000000..69a63ee27a
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/struct_kernel_msqid64_ds.h
> @@ -0,0 +1,18 @@
> +/* Analogous to kernel struct msqid64_ds used on msgctl.  */
> +struct kernel_msqid64_ds
> +{
> +  struct ipc_perm msg_perm;
> +  unsigned long msg_stime_high;
> +  unsigned long msg_stime;
> +  unsigned long msg_rtime_high;
> +  unsigned long msg_rtime;
> +  unsigned long msg_ctime_high;
> +  unsigned long msg_ctime;
> +  unsigned long msg_cbytes;
> +  unsigned long msg_qnum;
> +  unsigned long msg_qbytes;
> +  __pid_t msg_lspid;
> +  __pid_t msg_lrpid;
> +  unsigned long __unused1;
> +  unsigned long __unused2;
> +};
> diff --git a/sysdeps/unix/sysv/linux/semctl.c b/sysdeps/unix/sysv/linux/semctl.c
> index 90460e6310..005c00ea75 100644
> --- a/sysdeps/unix/sysv/linux/semctl.c
> +++ b/sysdeps/unix/sysv/linux/semctl.c
> @@ -196,19 +196,11 @@ libc_hidden_def (__semctl64)
>  
>  /* The 64-bit time_t semid_ds version might have a different layout and
>     internal field alignment.  */
> -static void
> -semid64_ds_to_semid_ds (struct semid_ds *ds, const struct __semid64_ds *ds64)
> -{
> -  ds->sem_perm = ds64->sem_perm;
> -  ds->sem_otime = ds64->sem_otime;
> -  ds->sem_ctime = ds64->sem_ctime;
> -  ds->sem_nsems = ds64->sem_nsems;
> -}
>  
>  static void
> -semid_ds_to_semid64_ds (struct __semid64_ds *ds64, const struct semid_ds *ds)
> +semid_to_semid64 (struct __semid64_ds *ds64, const struct semid_ds *ds)
>  {
> -  ds64->sem_perm = ds->sem_perm;
> +  ds64->sem_perm  = ds->sem_perm;
>    ds64->sem_otime = ds->sem_otime
>  		    | ((__time64_t) ds->__sem_otime_high << 32);
>    ds64->sem_ctime = ds->sem_ctime
> @@ -216,6 +208,17 @@ semid_ds_to_semid64_ds (struct __semid64_ds *ds64, const struct semid_ds *ds)
>    ds64->sem_nsems = ds->sem_nsems;
>  }
>  
> +static void
> +semid64_to_semid (struct semid_ds *ds, const struct __semid64_ds *ds64)
> +{
> +  ds->sem_perm         = ds64->sem_perm;
> +  ds->sem_otime        = ds64->sem_otime;
> +  ds->__sem_otime_high = 0;
> +  ds->sem_ctime        = ds64->sem_ctime;
> +  ds->__sem_ctime_high = 0;
> +  ds->sem_nsems        = ds64->sem_nsems;
> +}
> +
>  static union semun64
>  semun_to_semun64 (int cmd, union semun semun, struct __semid64_ds *semid64)
>  {
> @@ -232,7 +235,7 @@ semun_to_semun64 (int cmd, union semun semun, struct __semid64_ds *semid64)
>      case IPC_STAT:
>      case IPC_SET:
>        r.buf = semid64;
> -      semid_ds_to_semid64_ds (r.buf, semun.buf);
> +      semid_to_semid64 (r.buf, semun.buf);
>  # ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
>        if (cmd == IPC_SET)
>  	r.buf->sem_perm.mode *= 0x10000U;
> @@ -282,7 +285,7 @@ __semctl (int semid, int semnum, int cmd, ...)
>      case IPC_STAT:
>      case SEM_STAT:
>      case SEM_STAT_ANY:
> -      semid64_ds_to_semid_ds (arg.buf, arg64.buf);
> +      semid64_to_semid (arg.buf, arg64.buf);
>      }
>  
>    return ret;
> diff --git a/sysdeps/unix/sysv/linux/sparc/bits/types/struct_msqid_ds.h b/sysdeps/unix/sysv/linux/sparc/bits/types/struct_msqid_ds.h
> index 71980839c7..502c23d91e 100644
> --- a/sysdeps/unix/sysv/linux/sparc/bits/types/struct_msqid_ds.h
> +++ b/sysdeps/unix/sysv/linux/sparc/bits/types/struct_msqid_ds.h
> @@ -26,11 +26,11 @@ struct msqid_ds
>  {
>    struct ipc_perm msg_perm;	/* structure describing operation permission */
>  #if __TIMESIZE == 32
> -  unsigned long int __glibc_reserved1;
> +  unsigned long int __msg_stime_high;
>    __time_t msg_stime;		/* time of last msgsnd command */
> -  unsigned long int __glibc_reserved2;
> +  unsigned long int __msg_rtime_high;
>    __time_t msg_rtime;		/* time of last msgsnd command */
> -  unsigned long int __glibc_reserved3;
> +  unsigned long int __msg_ctime_high;
>    __time_t msg_ctime;		/* time of last change */
>  #else
>    __time_t msg_stime;		/* time of last msgsnd command */
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/struct_kernel_msqid64_ds.h b/sysdeps/unix/sysv/linux/sparc/sparc32/struct_kernel_msqid64_ds.h
> new file mode 100644
> index 0000000000..69a63ee27a
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/struct_kernel_msqid64_ds.h
> @@ -0,0 +1,18 @@
> +/* Analogous to kernel struct msqid64_ds used on msgctl.  */
> +struct kernel_msqid64_ds
> +{
> +  struct ipc_perm msg_perm;
> +  unsigned long msg_stime_high;
> +  unsigned long msg_stime;
> +  unsigned long msg_rtime_high;
> +  unsigned long msg_rtime;
> +  unsigned long msg_ctime_high;
> +  unsigned long msg_ctime;
> +  unsigned long msg_cbytes;
> +  unsigned long msg_qnum;
> +  unsigned long msg_qbytes;
> +  __pid_t msg_lspid;
> +  __pid_t msg_lrpid;
> +  unsigned long __unused1;
> +  unsigned long __unused2;
> +};
> diff --git a/sysdeps/unix/sysv/linux/struct_kernel_msqid64_ds.h b/sysdeps/unix/sysv/linux/struct_kernel_msqid64_ds.h
> new file mode 100644
> index 0000000000..b88d910adc
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/struct_kernel_msqid64_ds.h
> @@ -0,0 +1,19 @@
> +/* Analogous to kernel struct msqid64_ds used on msgctl.  It is only used
> +   for 32-bit architectures on 64-bit time_t msgctl64 implementation.  */
> +struct kernel_msqid64_ds
> +{
> +  struct ipc_perm msg_perm;
> +  unsigned long int msg_stime;
> +  unsigned long int msg_stime_high;
> +  unsigned long int msg_rtime;
> +  unsigned long int msg_rtime_high;
> +  unsigned long int msg_ctime;
> +  unsigned long int msg_ctime_high;
> +  unsigned long int msg_cbytes;
> +  unsigned long int msg_qnum;
> +  unsigned long int msg_qbytes;
> +  __pid_t msg_lspid;
> +  __pid_t msg_lrpid;
> +  unsigned long int __unused4;
> +  unsigned long int __unused5;
> +};
>
  
Alistair Francis July 8, 2020, 5:56 p.m. UTC | #2
On Wed, Jul 8, 2020 at 8:33 AM Adhemerval Zanella via Libc-alpha
<libc-alpha@sourceware.org> wrote:
>
> This is a small updated version that basically does:
>
>   git mv include/sys/msg.h sysdeps/unix/sysv/linux/include/sys/msg.h
>
> It moves the sysvipc to be Linux specific, since the generic version
> does implement _libc_msgsnd or __libc_msgrcv; and avoid a build failure
> on Hurd (since it does not provide struct_msqid64_ds.h).
>
> ---
>
> To provide a y2038 safe interface a new symbol __msgctl64 is added
> and __msgctl is change to call it instead (it adds some extra buffer
> coping for the 32 bit time_t implementation).
>
> Two new structures are added:
>
>   1. kernel_msqid64_ds: used internally only on 32-bit architectures
>      to issue the syscall.  A handful of architectures (hppa, i386, mips,
>      powerpc32, and sparc32) require specific implementations due to
>      their kernel ABI.
>
>   2. msqid_ds64: this is only for __TIMESIZE != 64 to use along with
>      the 64-bit semctl.  It is different than the kernel struct because
>      the exported 64-bit time_t might require different alignment
>      depending on the architecture ABI.
>
> So the resulting implementation does:
>
>   1. For 64-bit architectures it assumes msqid_ds already contains
>      64-bit time_t fields and will result in just the __msgctl symbol
>      using the __msgctl64 code.  The msgid_ds argument is passed as-is
>      to the syscall.
>
>   2. For 32-bit architectures with default 64-bit time_t (newer ABIs
>      such riscv32 or arc), it will also result in only one exported
>      symbol but with the required high/low time handling.
>
>   3. Finally for 32-bit architecture with both 32-bit and 64-bit time_t
>      support we follow the already set way to provide one symbol with
>      64-bit time_t support and implement the 32-bit time_t support using
>      the 64-bit time_t.
>
>      The default 32-bit symbol will allocate and copy the msqid_ds
>      over multiple buffers, but this should be deprecated in favor
>      of the __msgctl64 anyway.
>
> Checked on i686-linux-gnu and x86_64-linux-gnu.  I also did some sniff
> tests on powerpc, powerpc64, mips, mips64, armhf, sparcv9, and
> sparc64.
>
> Tested-by: Carlos O'Donell <carlos@redhat.com>
> Reviewed-by: Carlos O'Donell <carlos@redhat.com>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  .../sysv/linux/bits/types/struct_msqid64_ds.h |  38 ++++
>  .../sysv/linux/bits/types/struct_msqid_ds.h   |   6 +-
>  .../linux/hppa/bits/types/struct_msqid_ds.h   |   6 +-
>  .../linux/hppa/struct_kernel_msqid64_ds.h     |  18 ++
>  .../linux/i386/struct_kernel_msqid64_ds.h     |  18 ++
>  .../unix/sysv/linux/include}/sys/msg.h        |  10 +
>  .../linux/mips/bits/types/struct_msqid_ds.h   |  12 +-
>  .../linux/mips/struct_kernel_msqid64_ds.h     |  33 ++++
>  sysdeps/unix/sysv/linux/msgctl.c              | 179 ++++++++++++++----
>  .../powerpc/bits/types/struct_msqid_ds.h      |   6 +-
>  .../powerpc32/struct_kernel_msqid64_ds.h      |  18 ++
>  sysdeps/unix/sysv/linux/semctl.c              |  27 +--
>  .../linux/sparc/bits/types/struct_msqid_ds.h  |   6 +-
>  .../sparc/sparc32/struct_kernel_msqid64_ds.h  |  18 ++
>  .../sysv/linux/struct_kernel_msqid64_ds.h     |  19 ++
>  15 files changed, 350 insertions(+), 64 deletions(-)
>  create mode 100644 sysdeps/unix/sysv/linux/bits/types/struct_msqid64_ds.h
>  create mode 100644 sysdeps/unix/sysv/linux/hppa/struct_kernel_msqid64_ds.h
>  create mode 100644 sysdeps/unix/sysv/linux/i386/struct_kernel_msqid64_ds.h
>  rename {include => sysdeps/unix/sysv/linux/include}/sys/msg.h (55%)
>  create mode 100644 sysdeps/unix/sysv/linux/mips/struct_kernel_msqid64_ds.h
>  create mode 100644 sysdeps/unix/sysv/linux/powerpc/powerpc32/struct_kernel_msqid64_ds.h
>  create mode 100644 sysdeps/unix/sysv/linux/sparc/sparc32/struct_kernel_msqid64_ds.h
>  create mode 100644 sysdeps/unix/sysv/linux/struct_kernel_msqid64_ds.h
>
> diff --git a/sysdeps/unix/sysv/linux/bits/types/struct_msqid64_ds.h b/sysdeps/unix/sysv/linux/bits/types/struct_msqid64_ds.h
> new file mode 100644
> index 0000000000..3536c8ea62
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/bits/types/struct_msqid64_ds.h
> @@ -0,0 +1,38 @@
> +/* Generic implementation of the SysV message struct msqid64_ds.
> +   Copyright (C) 2020 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#ifndef _SYS_MSG_H
> +# error "Never use <bits/msq.h> directly; include <sys/msg.h> instead."
> +#endif
> +
> +#if __TIMESIZE == 64
> +# define __msqid64_ds msqid_ds
> +#else
> +struct __msqid64_ds
> +{
> +  struct ipc_perm msg_perm;    /* structure describing operation permission */
> +  __time64_t msg_stime;                /* time of last msgsnd command */
> +  __time64_t msg_rtime;                /* time of last msgsnd command */
> +  __time64_t msg_ctime;                /* time of last change */
> +  __syscall_ulong_t __msg_cbytes; /* current number of bytes on queue */
> +  msgqnum_t msg_qnum;          /* number of messages currently on queue */
> +  msglen_t msg_qbytes;         /* max number of bytes allowed on queue */
> +  __pid_t msg_lspid;           /* pid of last msgsnd() */
> +  __pid_t msg_lrpid;           /* pid of last msgrcv() */
> +};
> +#endif
> diff --git a/sysdeps/unix/sysv/linux/bits/types/struct_msqid_ds.h b/sysdeps/unix/sysv/linux/bits/types/struct_msqid_ds.h
> index 32173a7b60..43b38175ad 100644
> --- a/sysdeps/unix/sysv/linux/bits/types/struct_msqid_ds.h
> +++ b/sysdeps/unix/sysv/linux/bits/types/struct_msqid_ds.h
> @@ -27,11 +27,11 @@ struct msqid_ds
>    struct ipc_perm msg_perm;    /* structure describing operation permission */
>  #if __TIMESIZE == 32
>    __time_t msg_stime;          /* time of last msgsnd command */
> -  unsigned long int __glibc_reserved1;
> +  unsigned long int __msg_stime_high;
>    __time_t msg_rtime;          /* time of last msgsnd command */
> -  unsigned long int __glibc_reserved2;
> +  unsigned long int __msg_rtime_high;
>    __time_t msg_ctime;          /* time of last change */
> -  unsigned long int __glibc_reserved3;
> +  unsigned long int __msg_ctime_high;
>  #else
>    __time_t msg_stime;          /* time of last msgsnd command */
>    __time_t msg_rtime;          /* time of last msgsnd command */
> diff --git a/sysdeps/unix/sysv/linux/hppa/bits/types/struct_msqid_ds.h b/sysdeps/unix/sysv/linux/hppa/bits/types/struct_msqid_ds.h
> index 3cf70e36c4..16eac46941 100644
> --- a/sysdeps/unix/sysv/linux/hppa/bits/types/struct_msqid_ds.h
> +++ b/sysdeps/unix/sysv/linux/hppa/bits/types/struct_msqid_ds.h
> @@ -26,11 +26,11 @@ struct msqid_ds
>  {
>    struct ipc_perm msg_perm;    /* structure describing operation permission */
>  #if __TIMESIZE == 32
> -  unsigned long int __glibc_reserved1;
> +  unsigned long int __msg_stime_high;
>    __time_t msg_stime;          /* time of last msgsnd command */
> -  unsigned long int __glibc_reserved2;
> +  unsigned long int __msg_rtime_high;
>    __time_t msg_rtime;          /* time of last msgsnd command */
> -  unsigned long int __glibc_reserved3;
> +  unsigned long int __msg_ctime_high;
>    __time_t msg_ctime;          /* time of last change */
>  #else
>    __time_t msg_stime;          /* time of last msgsnd command */
> diff --git a/sysdeps/unix/sysv/linux/hppa/struct_kernel_msqid64_ds.h b/sysdeps/unix/sysv/linux/hppa/struct_kernel_msqid64_ds.h
> new file mode 100644
> index 0000000000..69a63ee27a
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/hppa/struct_kernel_msqid64_ds.h
> @@ -0,0 +1,18 @@
> +/* Analogous to kernel struct msqid64_ds used on msgctl.  */
> +struct kernel_msqid64_ds
> +{
> +  struct ipc_perm msg_perm;
> +  unsigned long msg_stime_high;
> +  unsigned long msg_stime;
> +  unsigned long msg_rtime_high;
> +  unsigned long msg_rtime;
> +  unsigned long msg_ctime_high;
> +  unsigned long msg_ctime;
> +  unsigned long msg_cbytes;
> +  unsigned long msg_qnum;
> +  unsigned long msg_qbytes;
> +  __pid_t msg_lspid;
> +  __pid_t msg_lrpid;
> +  unsigned long __unused1;
> +  unsigned long __unused2;
> +};
> diff --git a/sysdeps/unix/sysv/linux/i386/struct_kernel_msqid64_ds.h b/sysdeps/unix/sysv/linux/i386/struct_kernel_msqid64_ds.h
> new file mode 100644
> index 0000000000..65b940567b
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/i386/struct_kernel_msqid64_ds.h
> @@ -0,0 +1,18 @@
> +/* Analogous to kernel struct compat_msqid64_ds used on msgctl.  */
> +struct kernel_msqid64_ds
> +{
> +  struct ipc_perm msg_perm;
> +  unsigned long msg_stime;
> +  unsigned long msg_stime_high;
> +  unsigned long msg_rtime;
> +  unsigned long msg_rtime_high;
> +  unsigned long msg_ctime;
> +  unsigned long msg_ctime_high;
> +  unsigned long msg_cbytes;
> +  unsigned long msg_qnum;
> +  unsigned long msg_qbytes;
> +  __pid_t msg_lspid;
> +  __pid_t msg_lrpid;
> +  unsigned long __unused1;
> +  unsigned long __unused2;
> +};
> diff --git a/include/sys/msg.h b/sysdeps/unix/sysv/linux/include/sys/msg.h
> similarity index 55%
> rename from include/sys/msg.h
> rename to sysdeps/unix/sysv/linux/include/sys/msg.h
> index 43ec5b9472..522903f818 100644
> --- a/include/sys/msg.h
> +++ b/sysdeps/unix/sysv/linux/include/sys/msg.h
> @@ -6,6 +6,16 @@ extern ssize_t __libc_msgrcv (int msqid, void *msgp, size_t msgsz,
>                               long int msgtyp, int msgflg);
>  extern int __libc_msgsnd (int msqid, const void *msgp, size_t msgsz,
>                           int msgflg);
> +
> +# include <bits/types/struct_msqid64_ds.h>
> +
> +# if __TIMESIZE == 64
> +#  define __msgctl64 __msgctl
> +# else
> +extern int __msgctl64 (int msqid, int cmd, struct __msqid64_ds *buf);
> +libc_hidden_proto (__msgctl64);
> +# endif
> +
>  #endif
>
>  #endif
> diff --git a/sysdeps/unix/sysv/linux/mips/bits/types/struct_msqid_ds.h b/sysdeps/unix/sysv/linux/mips/bits/types/struct_msqid_ds.h
> index 85fdeef274..9ff010c763 100644
> --- a/sysdeps/unix/sysv/linux/mips/bits/types/struct_msqid_ds.h
> +++ b/sysdeps/unix/sysv/linux/mips/bits/types/struct_msqid_ds.h
> @@ -28,17 +28,17 @@ struct msqid_ds
>  #if __TIMESIZE == 32
>  # ifdef __MIPSEL__
>    __time_t msg_stime;          /* time of last msgsnd command */
> -  unsigned long int __glibc_reserved1;
> +  unsigned long int __msg_stime_high;
>    __time_t msg_rtime;          /* time of last msgsnd command */
> -  unsigned long int __glibc_reserved2;
> +  unsigned long int __msg_rtime_high;
>    __time_t msg_ctime;          /* time of last change */
> -  unsigned long int __glibc_reserved3;
> +  unsigned long int __msg_ctime_high;
>  # else
> -  unsigned long int __glibc_reserved1;
> +  unsigned long int __msg_stime_high;
>    __time_t msg_stime;          /* time of last msgsnd command */
> -  unsigned long int __glibc_reserved2;
> +  unsigned long int __msg_rtime_high;
>    __time_t msg_rtime;          /* time of last msgsnd command */
> -  unsigned long int __glibc_reserved3;
> +  unsigned long int __msg_ctime_high;
>    __time_t msg_ctime;          /* time of last change */
>  # endif
>  #else
> diff --git a/sysdeps/unix/sysv/linux/mips/struct_kernel_msqid64_ds.h b/sysdeps/unix/sysv/linux/mips/struct_kernel_msqid64_ds.h
> new file mode 100644
> index 0000000000..9cfd5a0dfe
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/mips/struct_kernel_msqid64_ds.h
> @@ -0,0 +1,33 @@
> +/* Analogous to kernel struct msqid64_ds used on msgctl.  */
> +struct kernel_msqid64_ds
> +{
> +  struct ipc_perm msg_perm;
> +#if __TIMESIZE == 32
> +# ifdef __MIPSEL__
> +  unsigned long int msg_stime;
> +  unsigned long int msg_stime_high;
> +  unsigned long int msg_rtime;
> +  unsigned long int msg_rtime_high;
> +  unsigned long int msg_ctime;
> +  unsigned long int msg_ctime_high;
> +# else
> +  unsigned long int msg_stime_high;
> +  unsigned long int msg_stime;
> +  unsigned long int msg_rtime_high;
> +  unsigned long int msg_rtime;
> +  unsigned long int msg_ctime_high;
> +  unsigned long int msg_ctime;
> +# endif
> +#else
> +  unsigned long int msg_stime;
> +  unsigned long int msg_rtime;
> +  unsigned long int msg_ctime;
> +#endif
> +  unsigned long int msg_cbytes;
> +  unsigned long int msg_qnum;
> +  unsigned long int msg_qbytes;
> +  __pid_t msg_lspid;
> +  __pid_t msg_lrpid;
> +  unsigned long int __unused1;
> +  unsigned long int __unused2;
> +};
> diff --git a/sysdeps/unix/sysv/linux/msgctl.c b/sysdeps/unix/sysv/linux/msgctl.c
> index fd46aec1a0..a7f7651280 100644
> --- a/sysdeps/unix/sysv/linux/msgctl.c
> +++ b/sysdeps/unix/sysv/linux/msgctl.c
> @@ -23,16 +23,55 @@
>  #include <errno.h>
>  #include <linux/posix_types.h>  /* For __kernel_mode_t.  */
>
> -#ifndef DEFAULT_VERSION
> -# ifndef __ASSUME_SYSVIPC_BROKEN_MODE_T
> -#  define DEFAULT_VERSION GLIBC_2_2
> -# else
> -#  define DEFAULT_VERSION GLIBC_2_31
> -# endif
> +/* POSIX states ipc_perm mode should have type of mode_t.  */
> +_Static_assert (sizeof ((struct msqid_ds){0}.msg_perm.mode)
> +               == sizeof (mode_t),
> +               "sizeof (msqid_ds.msg_perm.mode) != sizeof (mode_t)");
> +
> +#if __IPC_TIME64 == 0
> +typedef struct msqid_ds msgctl_arg_t;
> +#else
> +# include <struct_kernel_msqid64_ds.h>
> +
> +static void
> +msqid64_to_kmsqid64 (const struct __msqid64_ds *msqid64,
> +                    struct kernel_msqid64_ds *kmsqid)
> +{
> +  kmsqid->msg_perm       = msqid64->msg_perm;
> +  kmsqid->msg_stime      = msqid64->msg_stime;
> +  kmsqid->msg_stime_high = msqid64->msg_stime >> 32;
> +  kmsqid->msg_rtime      = msqid64->msg_rtime;
> +  kmsqid->msg_rtime_high = msqid64->msg_rtime >> 32;
> +  kmsqid->msg_ctime      = msqid64->msg_ctime;
> +  kmsqid->msg_ctime_high = msqid64->msg_ctime >> 32;
> +  kmsqid->msg_qnum       = msqid64->msg_qnum;
> +  kmsqid->msg_qbytes     = msqid64->msg_qbytes;
> +  kmsqid->msg_lspid      = msqid64->msg_lspid;
> +  kmsqid->msg_lrpid      = msqid64->msg_lrpid;
> +}
> +
> +static void
> +kmsqid64_to_msqid64 (const struct kernel_msqid64_ds *kmsqid,
> +                    struct __msqid64_ds *msqid64)
> +{
> +  msqid64->msg_perm   = kmsqid->msg_perm;
> +  msqid64->msg_stime  = kmsqid->msg_stime
> +                       | ((__time64_t) kmsqid->msg_stime_high << 32);
> +  msqid64->msg_rtime  = kmsqid->msg_rtime
> +                       | ((__time64_t) kmsqid->msg_rtime_high << 32);
> +  msqid64->msg_ctime  = kmsqid->msg_ctime
> +                       | ((__time64_t) kmsqid->msg_ctime_high << 32);
> +  msqid64->msg_qnum   = kmsqid->msg_qnum;
> +  msqid64->msg_qbytes = kmsqid->msg_qbytes;
> +  msqid64->msg_lspid  = kmsqid->msg_lspid;
> +  msqid64->msg_lrpid  = kmsqid->msg_lrpid;
> +}
> +
> +typedef struct kernel_msqid64_ds msgctl_arg_t;
>  #endif
>
>  static int
> -msgctl_syscall (int msqid, int cmd, struct msqid_ds *buf)
> +msgctl_syscall (int msqid, int cmd, msgctl_arg_t *buf)
>  {
>  #ifdef __ASSUME_DIRECT_SYSVIPC_SYSCALLS
>    return INLINE_SYSCALL_CALL (msgctl, msqid, cmd | __IPC_64, buf);
> @@ -43,46 +82,118 @@ msgctl_syscall (int msqid, int cmd, struct msqid_ds *buf)
>  }
>
>  int
> -__new_msgctl (int msqid, int cmd, struct msqid_ds *buf)
> +__msgctl64 (int msqid, int cmd, struct __msqid64_ds *buf)
>  {
> -  /* POSIX states ipc_perm mode should have type of mode_t.  */
> -  _Static_assert (sizeof ((struct msqid_ds){0}.msg_perm.mode)
> -                 == sizeof (mode_t),
> -                 "sizeof (msqid_ds.msg_perm.mode) != sizeof (mode_t)");
> -
> -#ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
> -  struct msqid_ds tmpds;
> -  if (cmd == IPC_SET)
> +#if __IPC_TIME64
> +  struct kernel_msqid64_ds ksemid, *arg = NULL;
> +  if (buf != NULL)
>      {
> -      tmpds = *buf;
> -      tmpds.msg_perm.mode *= 0x10000U;
> -      buf = &tmpds;
> +      msqid64_to_kmsqid64 (buf, &ksemid);
> +      arg = &ksemid;
>      }
> +# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
> +  if (cmd == IPC_SET)
> +    arg->msg_perm.mode *= 0x10000U;
> +# endif
> +#else
> +  msgctl_arg_t *arg = buf;
>  #endif
>
> -  int ret = msgctl_syscall (msqid, cmd, buf);
> +  int ret = msgctl_syscall (msqid, cmd, arg);
> +  if (ret < 0)
> +    return ret;
>
> -  if (ret >= 0)
> +  switch (cmd)
>      {
> -      switch (cmd)
> -       {
> -       case IPC_STAT:
> -       case MSG_STAT:
> -       case MSG_STAT_ANY:
> +    case IPC_STAT:
> +    case MSG_STAT:
> +    case MSG_STAT_ANY:
>  #ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
> -         buf->msg_perm.mode >>= 16;
> +      arg->msg_perm.mode >>= 16;
>  #else
> -         /* Old Linux kernel versions might not clear the mode padding.  */
> -         if (sizeof ((struct msqid_ds){0}.msg_perm.mode)
> -             != sizeof (__kernel_mode_t))
> -           buf->msg_perm.mode &= 0xFFFF;
> +      /* Old Linux kernel versions might not clear the mode padding.  */
> +      if (sizeof ((struct msqid_ds){0}.msg_perm.mode)
> +          != sizeof (__kernel_mode_t))
> +       arg->msg_perm.mode &= 0xFFFF;
> +#endif
> +
> +#if __IPC_TIME64
> +      kmsqid64_to_msqid64 (arg, buf);
>  #endif
> -       }
>      }
>
>    return ret;
>  }
> -versioned_symbol (libc, __new_msgctl, msgctl, DEFAULT_VERSION);
> +#if __TIMESIZE != 64
> +libc_hidden_def (__msgctl64)
> +
> +static void
> +msqid_to_msqid64 (struct __msqid64_ds *mq64, const struct msqid_ds *mq)
> +{
> +  mq64->msg_perm   = mq->msg_perm;
> +  mq64->msg_stime  = mq->msg_stime
> +                    | ((__time64_t) mq->__msg_stime_high << 32);
> +  mq64->msg_rtime  = mq->msg_rtime
> +                    | ((__time64_t) mq->__msg_rtime_high << 32);
> +  mq64->msg_ctime  = mq->msg_ctime
> +                    | ((__time64_t) mq->__msg_ctime_high << 32);
> +  mq64->msg_qnum   = mq->msg_qnum;
> +  mq64->msg_qbytes = mq->msg_qbytes;
> +  mq64->msg_lspid  = mq->msg_lspid;
> +  mq64->msg_lrpid  = mq->msg_lrpid;
> +}
> +
> +static void
> +msqid64_to_msqid (struct msqid_ds *mq, const struct __msqid64_ds *mq64)
> +{
> +  mq->msg_perm         = mq64->msg_perm;
> +  mq->msg_stime        = mq64->msg_stime;
> +  mq->__msg_stime_high = 0;
> +  mq->msg_rtime        = mq64->msg_rtime;
> +  mq->__msg_rtime_high = 0;
> +  mq->msg_ctime        = mq64->msg_ctime;
> +  mq->__msg_ctime_high = 0;
> +  mq->msg_qnum         = mq64->msg_qnum;
> +  mq->msg_qbytes       = mq64->msg_qbytes;
> +  mq->msg_lspid        = mq64->msg_lspid;
> +  mq->msg_lrpid        = mq64->msg_lrpid;
> +}
> +
> +int
> +__msgctl (int msqid, int cmd, struct msqid_ds *buf)
> +{
> +  struct __msqid64_ds msqid64, *buf64 = NULL;
> +  if (buf != NULL)
> +    {
> +      msqid_to_msqid64 (&msqid64, buf);
> +      buf64 = &msqid64;
> +    }
> +
> +  int ret = __msgctl64 (msqid, cmd, buf64);
> +  if (ret < 0)
> +    return ret;
> +
> +  switch (cmd)
> +    {
> +    case IPC_STAT:
> +    case MSG_STAT:
> +    case MSG_STAT_ANY:
> +      if (buf64 != NULL)
> +        msqid64_to_msqid (buf, buf64);
> +    }
> +
> +  return ret;
> +}
> +#endif
> +
> +#ifndef DEFAULT_VERSION
> +# ifndef __ASSUME_SYSVIPC_BROKEN_MODE_T
> +#  define DEFAULT_VERSION GLIBC_2_2
> +# else
> +#  define DEFAULT_VERSION GLIBC_2_31
> +# endif
> +#endif
> +versioned_symbol (libc, __msgctl, msgctl, DEFAULT_VERSION);
>
>  #if defined __ASSUME_SYSVIPC_BROKEN_MODE_T \
>      && SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_31)
> @@ -90,7 +201,7 @@ int
>  attribute_compat_text_section
>  __msgctl_mode16 (int msqid, int cmd, struct msqid_ds *buf)
>  {
> -  return msgctl_syscall (msqid, cmd, buf);
> +  return msgctl_syscall (msqid, cmd, (msgctl_arg_t *) buf);
>  }
>  compat_symbol (libc, __msgctl_mode16, msgctl, GLIBC_2_2);
>  #endif
> diff --git a/sysdeps/unix/sysv/linux/powerpc/bits/types/struct_msqid_ds.h b/sysdeps/unix/sysv/linux/powerpc/bits/types/struct_msqid_ds.h
> index 4ae2fbcbdc..35cc51f733 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/bits/types/struct_msqid_ds.h
> +++ b/sysdeps/unix/sysv/linux/powerpc/bits/types/struct_msqid_ds.h
> @@ -26,11 +26,11 @@ struct msqid_ds
>  {
>    struct ipc_perm msg_perm;    /* structure describing operation permission */
>  #if __TIMESIZE == 32
> -  unsigned long int __glibc_reserved1;
> +  unsigned long int __msg_stime_high;
>    __time_t msg_stime;          /* time of last msgsnd command */
> -  unsigned long int __glibc_reserved2;
> +  unsigned long int __msg_rtime_high;
>    __time_t msg_rtime;          /* time of last msgsnd command */
> -  unsigned long int __glibc_reserved3;
> +  unsigned long int __msg_ctime_high;
>    __time_t msg_ctime;          /* time of last change */
>  #else
>    __time_t msg_stime;          /* time of last msgsnd command */
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/struct_kernel_msqid64_ds.h b/sysdeps/unix/sysv/linux/powerpc/powerpc32/struct_kernel_msqid64_ds.h
> new file mode 100644
> index 0000000000..69a63ee27a
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/struct_kernel_msqid64_ds.h
> @@ -0,0 +1,18 @@
> +/* Analogous to kernel struct msqid64_ds used on msgctl.  */
> +struct kernel_msqid64_ds
> +{
> +  struct ipc_perm msg_perm;
> +  unsigned long msg_stime_high;
> +  unsigned long msg_stime;
> +  unsigned long msg_rtime_high;
> +  unsigned long msg_rtime;
> +  unsigned long msg_ctime_high;
> +  unsigned long msg_ctime;
> +  unsigned long msg_cbytes;
> +  unsigned long msg_qnum;
> +  unsigned long msg_qbytes;
> +  __pid_t msg_lspid;
> +  __pid_t msg_lrpid;
> +  unsigned long __unused1;
> +  unsigned long __unused2;
> +};
> diff --git a/sysdeps/unix/sysv/linux/semctl.c b/sysdeps/unix/sysv/linux/semctl.c
> index 90460e6310..005c00ea75 100644
> --- a/sysdeps/unix/sysv/linux/semctl.c
> +++ b/sysdeps/unix/sysv/linux/semctl.c
> @@ -196,19 +196,11 @@ libc_hidden_def (__semctl64)
>
>  /* The 64-bit time_t semid_ds version might have a different layout and
>     internal field alignment.  */
> -static void
> -semid64_ds_to_semid_ds (struct semid_ds *ds, const struct __semid64_ds *ds64)
> -{
> -  ds->sem_perm = ds64->sem_perm;
> -  ds->sem_otime = ds64->sem_otime;
> -  ds->sem_ctime = ds64->sem_ctime;
> -  ds->sem_nsems = ds64->sem_nsems;
> -}
>
>  static void
> -semid_ds_to_semid64_ds (struct __semid64_ds *ds64, const struct semid_ds *ds)
> +semid_to_semid64 (struct __semid64_ds *ds64, const struct semid_ds *ds)
>  {
> -  ds64->sem_perm = ds->sem_perm;
> +  ds64->sem_perm  = ds->sem_perm;
>    ds64->sem_otime = ds->sem_otime
>                     | ((__time64_t) ds->__sem_otime_high << 32);
>    ds64->sem_ctime = ds->sem_ctime
> @@ -216,6 +208,17 @@ semid_ds_to_semid64_ds (struct __semid64_ds *ds64, const struct semid_ds *ds)
>    ds64->sem_nsems = ds->sem_nsems;
>  }
>
> +static void
> +semid64_to_semid (struct semid_ds *ds, const struct __semid64_ds *ds64)
> +{
> +  ds->sem_perm         = ds64->sem_perm;
> +  ds->sem_otime        = ds64->sem_otime;
> +  ds->__sem_otime_high = 0;
> +  ds->sem_ctime        = ds64->sem_ctime;
> +  ds->__sem_ctime_high = 0;
> +  ds->sem_nsems        = ds64->sem_nsems;
> +}
> +
>  static union semun64
>  semun_to_semun64 (int cmd, union semun semun, struct __semid64_ds *semid64)
>  {
> @@ -232,7 +235,7 @@ semun_to_semun64 (int cmd, union semun semun, struct __semid64_ds *semid64)
>      case IPC_STAT:
>      case IPC_SET:
>        r.buf = semid64;
> -      semid_ds_to_semid64_ds (r.buf, semun.buf);
> +      semid_to_semid64 (r.buf, semun.buf);
>  # ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
>        if (cmd == IPC_SET)
>         r.buf->sem_perm.mode *= 0x10000U;
> @@ -282,7 +285,7 @@ __semctl (int semid, int semnum, int cmd, ...)
>      case IPC_STAT:
>      case SEM_STAT:
>      case SEM_STAT_ANY:
> -      semid64_ds_to_semid_ds (arg.buf, arg64.buf);
> +      semid64_to_semid (arg.buf, arg64.buf);
>      }
>
>    return ret;
> diff --git a/sysdeps/unix/sysv/linux/sparc/bits/types/struct_msqid_ds.h b/sysdeps/unix/sysv/linux/sparc/bits/types/struct_msqid_ds.h
> index 71980839c7..502c23d91e 100644
> --- a/sysdeps/unix/sysv/linux/sparc/bits/types/struct_msqid_ds.h
> +++ b/sysdeps/unix/sysv/linux/sparc/bits/types/struct_msqid_ds.h
> @@ -26,11 +26,11 @@ struct msqid_ds
>  {
>    struct ipc_perm msg_perm;    /* structure describing operation permission */
>  #if __TIMESIZE == 32
> -  unsigned long int __glibc_reserved1;
> +  unsigned long int __msg_stime_high;
>    __time_t msg_stime;          /* time of last msgsnd command */
> -  unsigned long int __glibc_reserved2;
> +  unsigned long int __msg_rtime_high;
>    __time_t msg_rtime;          /* time of last msgsnd command */
> -  unsigned long int __glibc_reserved3;
> +  unsigned long int __msg_ctime_high;
>    __time_t msg_ctime;          /* time of last change */
>  #else
>    __time_t msg_stime;          /* time of last msgsnd command */
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/struct_kernel_msqid64_ds.h b/sysdeps/unix/sysv/linux/sparc/sparc32/struct_kernel_msqid64_ds.h
> new file mode 100644
> index 0000000000..69a63ee27a
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/struct_kernel_msqid64_ds.h
> @@ -0,0 +1,18 @@
> +/* Analogous to kernel struct msqid64_ds used on msgctl.  */
> +struct kernel_msqid64_ds
> +{
> +  struct ipc_perm msg_perm;
> +  unsigned long msg_stime_high;
> +  unsigned long msg_stime;
> +  unsigned long msg_rtime_high;
> +  unsigned long msg_rtime;
> +  unsigned long msg_ctime_high;
> +  unsigned long msg_ctime;
> +  unsigned long msg_cbytes;
> +  unsigned long msg_qnum;
> +  unsigned long msg_qbytes;
> +  __pid_t msg_lspid;
> +  __pid_t msg_lrpid;
> +  unsigned long __unused1;
> +  unsigned long __unused2;
> +};
> diff --git a/sysdeps/unix/sysv/linux/struct_kernel_msqid64_ds.h b/sysdeps/unix/sysv/linux/struct_kernel_msqid64_ds.h
> new file mode 100644
> index 0000000000..b88d910adc
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/struct_kernel_msqid64_ds.h
> @@ -0,0 +1,19 @@
> +/* Analogous to kernel struct msqid64_ds used on msgctl.  It is only used
> +   for 32-bit architectures on 64-bit time_t msgctl64 implementation.  */
> +struct kernel_msqid64_ds
> +{
> +  struct ipc_perm msg_perm;
> +  unsigned long int msg_stime;
> +  unsigned long int msg_stime_high;
> +  unsigned long int msg_rtime;
> +  unsigned long int msg_rtime_high;
> +  unsigned long int msg_ctime;
> +  unsigned long int msg_ctime_high;
> +  unsigned long int msg_cbytes;
> +  unsigned long int msg_qnum;
> +  unsigned long int msg_qbytes;
> +  __pid_t msg_lspid;
> +  __pid_t msg_lrpid;
> +  unsigned long int __unused4;
> +  unsigned long int __unused5;
> +};
> --
> 2.25.1
>
  

Patch

diff --git a/sysdeps/unix/sysv/linux/bits/types/struct_msqid64_ds.h b/sysdeps/unix/sysv/linux/bits/types/struct_msqid64_ds.h
new file mode 100644
index 0000000000..3536c8ea62
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/bits/types/struct_msqid64_ds.h
@@ -0,0 +1,38 @@ 
+/* Generic implementation of the SysV message struct msqid64_ds.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _SYS_MSG_H
+# error "Never use <bits/msq.h> directly; include <sys/msg.h> instead."
+#endif
+
+#if __TIMESIZE == 64
+# define __msqid64_ds msqid_ds
+#else
+struct __msqid64_ds
+{
+  struct ipc_perm msg_perm;	/* structure describing operation permission */
+  __time64_t msg_stime;		/* time of last msgsnd command */
+  __time64_t msg_rtime;		/* time of last msgsnd command */
+  __time64_t msg_ctime;		/* time of last change */
+  __syscall_ulong_t __msg_cbytes; /* current number of bytes on queue */
+  msgqnum_t msg_qnum;		/* number of messages currently on queue */
+  msglen_t msg_qbytes;		/* max number of bytes allowed on queue */
+  __pid_t msg_lspid;		/* pid of last msgsnd() */
+  __pid_t msg_lrpid;		/* pid of last msgrcv() */
+};
+#endif
diff --git a/sysdeps/unix/sysv/linux/bits/types/struct_msqid_ds.h b/sysdeps/unix/sysv/linux/bits/types/struct_msqid_ds.h
index 32173a7b60..43b38175ad 100644
--- a/sysdeps/unix/sysv/linux/bits/types/struct_msqid_ds.h
+++ b/sysdeps/unix/sysv/linux/bits/types/struct_msqid_ds.h
@@ -27,11 +27,11 @@  struct msqid_ds
   struct ipc_perm msg_perm;	/* structure describing operation permission */
 #if __TIMESIZE == 32
   __time_t msg_stime;		/* time of last msgsnd command */
-  unsigned long int __glibc_reserved1;
+  unsigned long int __msg_stime_high;
   __time_t msg_rtime;		/* time of last msgsnd command */
-  unsigned long int __glibc_reserved2;
+  unsigned long int __msg_rtime_high;
   __time_t msg_ctime;		/* time of last change */
-  unsigned long int __glibc_reserved3;
+  unsigned long int __msg_ctime_high;
 #else
   __time_t msg_stime;		/* time of last msgsnd command */
   __time_t msg_rtime;		/* time of last msgsnd command */
diff --git a/sysdeps/unix/sysv/linux/hppa/bits/types/struct_msqid_ds.h b/sysdeps/unix/sysv/linux/hppa/bits/types/struct_msqid_ds.h
index 3cf70e36c4..16eac46941 100644
--- a/sysdeps/unix/sysv/linux/hppa/bits/types/struct_msqid_ds.h
+++ b/sysdeps/unix/sysv/linux/hppa/bits/types/struct_msqid_ds.h
@@ -26,11 +26,11 @@  struct msqid_ds
 {
   struct ipc_perm msg_perm;	/* structure describing operation permission */
 #if __TIMESIZE == 32
-  unsigned long int __glibc_reserved1;
+  unsigned long int __msg_stime_high;
   __time_t msg_stime;		/* time of last msgsnd command */
-  unsigned long int __glibc_reserved2;
+  unsigned long int __msg_rtime_high;
   __time_t msg_rtime;		/* time of last msgsnd command */
-  unsigned long int __glibc_reserved3;
+  unsigned long int __msg_ctime_high;
   __time_t msg_ctime;		/* time of last change */
 #else
   __time_t msg_stime;		/* time of last msgsnd command */
diff --git a/sysdeps/unix/sysv/linux/hppa/struct_kernel_msqid64_ds.h b/sysdeps/unix/sysv/linux/hppa/struct_kernel_msqid64_ds.h
new file mode 100644
index 0000000000..69a63ee27a
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/hppa/struct_kernel_msqid64_ds.h
@@ -0,0 +1,18 @@ 
+/* Analogous to kernel struct msqid64_ds used on msgctl.  */
+struct kernel_msqid64_ds
+{
+  struct ipc_perm msg_perm;
+  unsigned long msg_stime_high;
+  unsigned long msg_stime;
+  unsigned long msg_rtime_high;
+  unsigned long msg_rtime;
+  unsigned long msg_ctime_high;
+  unsigned long msg_ctime;
+  unsigned long msg_cbytes;
+  unsigned long msg_qnum;
+  unsigned long msg_qbytes;
+  __pid_t msg_lspid;
+  __pid_t msg_lrpid;
+  unsigned long __unused1;
+  unsigned long __unused2;
+};
diff --git a/sysdeps/unix/sysv/linux/i386/struct_kernel_msqid64_ds.h b/sysdeps/unix/sysv/linux/i386/struct_kernel_msqid64_ds.h
new file mode 100644
index 0000000000..65b940567b
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/i386/struct_kernel_msqid64_ds.h
@@ -0,0 +1,18 @@ 
+/* Analogous to kernel struct compat_msqid64_ds used on msgctl.  */
+struct kernel_msqid64_ds
+{
+  struct ipc_perm msg_perm;
+  unsigned long msg_stime;
+  unsigned long msg_stime_high;
+  unsigned long msg_rtime;
+  unsigned long msg_rtime_high;
+  unsigned long msg_ctime;
+  unsigned long msg_ctime_high;
+  unsigned long msg_cbytes;
+  unsigned long msg_qnum;
+  unsigned long msg_qbytes;
+  __pid_t msg_lspid;
+  __pid_t msg_lrpid;
+  unsigned long __unused1;
+  unsigned long __unused2;
+};
diff --git a/include/sys/msg.h b/sysdeps/unix/sysv/linux/include/sys/msg.h
similarity index 55%
rename from include/sys/msg.h
rename to sysdeps/unix/sysv/linux/include/sys/msg.h
index 43ec5b9472..522903f818 100644
--- a/include/sys/msg.h
+++ b/sysdeps/unix/sysv/linux/include/sys/msg.h
@@ -6,6 +6,16 @@  extern ssize_t __libc_msgrcv (int msqid, void *msgp, size_t msgsz,
 			      long int msgtyp, int msgflg);
 extern int __libc_msgsnd (int msqid, const void *msgp, size_t msgsz,
 			  int msgflg);
+
+# include <bits/types/struct_msqid64_ds.h>
+
+# if __TIMESIZE == 64
+#  define __msgctl64 __msgctl
+# else
+extern int __msgctl64 (int msqid, int cmd, struct __msqid64_ds *buf);
+libc_hidden_proto (__msgctl64);
+# endif
+
 #endif
 
 #endif
diff --git a/sysdeps/unix/sysv/linux/mips/bits/types/struct_msqid_ds.h b/sysdeps/unix/sysv/linux/mips/bits/types/struct_msqid_ds.h
index 85fdeef274..9ff010c763 100644
--- a/sysdeps/unix/sysv/linux/mips/bits/types/struct_msqid_ds.h
+++ b/sysdeps/unix/sysv/linux/mips/bits/types/struct_msqid_ds.h
@@ -28,17 +28,17 @@  struct msqid_ds
 #if __TIMESIZE == 32
 # ifdef __MIPSEL__
   __time_t msg_stime;		/* time of last msgsnd command */
-  unsigned long int __glibc_reserved1;
+  unsigned long int __msg_stime_high;
   __time_t msg_rtime;		/* time of last msgsnd command */
-  unsigned long int __glibc_reserved2;
+  unsigned long int __msg_rtime_high;
   __time_t msg_ctime;		/* time of last change */
-  unsigned long int __glibc_reserved3;
+  unsigned long int __msg_ctime_high;
 # else
-  unsigned long int __glibc_reserved1;
+  unsigned long int __msg_stime_high;
   __time_t msg_stime;		/* time of last msgsnd command */
-  unsigned long int __glibc_reserved2;
+  unsigned long int __msg_rtime_high;
   __time_t msg_rtime;		/* time of last msgsnd command */
-  unsigned long int __glibc_reserved3;
+  unsigned long int __msg_ctime_high;
   __time_t msg_ctime;		/* time of last change */
 # endif
 #else
diff --git a/sysdeps/unix/sysv/linux/mips/struct_kernel_msqid64_ds.h b/sysdeps/unix/sysv/linux/mips/struct_kernel_msqid64_ds.h
new file mode 100644
index 0000000000..9cfd5a0dfe
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/mips/struct_kernel_msqid64_ds.h
@@ -0,0 +1,33 @@ 
+/* Analogous to kernel struct msqid64_ds used on msgctl.  */
+struct kernel_msqid64_ds
+{
+  struct ipc_perm msg_perm;
+#if __TIMESIZE == 32
+# ifdef __MIPSEL__
+  unsigned long int msg_stime;
+  unsigned long int msg_stime_high;
+  unsigned long int msg_rtime;
+  unsigned long int msg_rtime_high;
+  unsigned long int msg_ctime;
+  unsigned long int msg_ctime_high;
+# else
+  unsigned long int msg_stime_high;
+  unsigned long int msg_stime;
+  unsigned long int msg_rtime_high;
+  unsigned long int msg_rtime;
+  unsigned long int msg_ctime_high;
+  unsigned long int msg_ctime;
+# endif
+#else
+  unsigned long int msg_stime;
+  unsigned long int msg_rtime;
+  unsigned long int msg_ctime;
+#endif
+  unsigned long int msg_cbytes;
+  unsigned long int msg_qnum;
+  unsigned long int msg_qbytes;
+  __pid_t msg_lspid;
+  __pid_t msg_lrpid;
+  unsigned long int __unused1;
+  unsigned long int __unused2;
+};
diff --git a/sysdeps/unix/sysv/linux/msgctl.c b/sysdeps/unix/sysv/linux/msgctl.c
index fd46aec1a0..a7f7651280 100644
--- a/sysdeps/unix/sysv/linux/msgctl.c
+++ b/sysdeps/unix/sysv/linux/msgctl.c
@@ -23,16 +23,55 @@ 
 #include <errno.h>
 #include <linux/posix_types.h>  /* For __kernel_mode_t.  */
 
-#ifndef DEFAULT_VERSION
-# ifndef __ASSUME_SYSVIPC_BROKEN_MODE_T
-#  define DEFAULT_VERSION GLIBC_2_2
-# else
-#  define DEFAULT_VERSION GLIBC_2_31
-# endif
+/* POSIX states ipc_perm mode should have type of mode_t.  */
+_Static_assert (sizeof ((struct msqid_ds){0}.msg_perm.mode)
+		== sizeof (mode_t),
+		"sizeof (msqid_ds.msg_perm.mode) != sizeof (mode_t)");
+
+#if __IPC_TIME64 == 0
+typedef struct msqid_ds msgctl_arg_t;
+#else
+# include <struct_kernel_msqid64_ds.h>
+
+static void
+msqid64_to_kmsqid64 (const struct __msqid64_ds *msqid64,
+		     struct kernel_msqid64_ds *kmsqid)
+{
+  kmsqid->msg_perm       = msqid64->msg_perm;
+  kmsqid->msg_stime      = msqid64->msg_stime;
+  kmsqid->msg_stime_high = msqid64->msg_stime >> 32;
+  kmsqid->msg_rtime      = msqid64->msg_rtime;
+  kmsqid->msg_rtime_high = msqid64->msg_rtime >> 32;
+  kmsqid->msg_ctime      = msqid64->msg_ctime;
+  kmsqid->msg_ctime_high = msqid64->msg_ctime >> 32;
+  kmsqid->msg_qnum       = msqid64->msg_qnum;
+  kmsqid->msg_qbytes     = msqid64->msg_qbytes;
+  kmsqid->msg_lspid      = msqid64->msg_lspid;
+  kmsqid->msg_lrpid      = msqid64->msg_lrpid;
+}
+
+static void
+kmsqid64_to_msqid64 (const struct kernel_msqid64_ds *kmsqid,
+		     struct __msqid64_ds *msqid64)
+{
+  msqid64->msg_perm   = kmsqid->msg_perm;
+  msqid64->msg_stime  = kmsqid->msg_stime
+		        | ((__time64_t) kmsqid->msg_stime_high << 32);
+  msqid64->msg_rtime  = kmsqid->msg_rtime
+		        | ((__time64_t) kmsqid->msg_rtime_high << 32);
+  msqid64->msg_ctime  = kmsqid->msg_ctime
+		        | ((__time64_t) kmsqid->msg_ctime_high << 32);
+  msqid64->msg_qnum   = kmsqid->msg_qnum;
+  msqid64->msg_qbytes = kmsqid->msg_qbytes;
+  msqid64->msg_lspid  = kmsqid->msg_lspid;
+  msqid64->msg_lrpid  = kmsqid->msg_lrpid;
+}
+
+typedef struct kernel_msqid64_ds msgctl_arg_t;
 #endif
 
 static int
-msgctl_syscall (int msqid, int cmd, struct msqid_ds *buf)
+msgctl_syscall (int msqid, int cmd, msgctl_arg_t *buf)
 {
 #ifdef __ASSUME_DIRECT_SYSVIPC_SYSCALLS
   return INLINE_SYSCALL_CALL (msgctl, msqid, cmd | __IPC_64, buf);
@@ -43,46 +82,118 @@  msgctl_syscall (int msqid, int cmd, struct msqid_ds *buf)
 }
 
 int
-__new_msgctl (int msqid, int cmd, struct msqid_ds *buf)
+__msgctl64 (int msqid, int cmd, struct __msqid64_ds *buf)
 {
-  /* POSIX states ipc_perm mode should have type of mode_t.  */
-  _Static_assert (sizeof ((struct msqid_ds){0}.msg_perm.mode)
-		  == sizeof (mode_t),
-		  "sizeof (msqid_ds.msg_perm.mode) != sizeof (mode_t)");
-
-#ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
-  struct msqid_ds tmpds;
-  if (cmd == IPC_SET)
+#if __IPC_TIME64
+  struct kernel_msqid64_ds ksemid, *arg = NULL;
+  if (buf != NULL)
     {
-      tmpds = *buf;
-      tmpds.msg_perm.mode *= 0x10000U;
-      buf = &tmpds;
+      msqid64_to_kmsqid64 (buf, &ksemid);
+      arg = &ksemid;
     }
+# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
+  if (cmd == IPC_SET)
+    arg->msg_perm.mode *= 0x10000U;
+# endif
+#else
+  msgctl_arg_t *arg = buf;
 #endif
 
-  int ret = msgctl_syscall (msqid, cmd, buf);
+  int ret = msgctl_syscall (msqid, cmd, arg);
+  if (ret < 0)
+    return ret;
 
-  if (ret >= 0)
+  switch (cmd)
     {
-      switch (cmd)
-	{
-	case IPC_STAT:
-	case MSG_STAT:
-	case MSG_STAT_ANY:
+    case IPC_STAT:
+    case MSG_STAT:
+    case MSG_STAT_ANY:
 #ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
-	  buf->msg_perm.mode >>= 16;
+      arg->msg_perm.mode >>= 16;
 #else
-	  /* Old Linux kernel versions might not clear the mode padding.  */
-	  if (sizeof ((struct msqid_ds){0}.msg_perm.mode)
-	      != sizeof (__kernel_mode_t))
-	    buf->msg_perm.mode &= 0xFFFF;
+      /* Old Linux kernel versions might not clear the mode padding.  */
+      if (sizeof ((struct msqid_ds){0}.msg_perm.mode)
+          != sizeof (__kernel_mode_t))
+	arg->msg_perm.mode &= 0xFFFF;
+#endif
+
+#if __IPC_TIME64
+      kmsqid64_to_msqid64 (arg, buf);
 #endif
-	}
     }
 
   return ret;
 }
-versioned_symbol (libc, __new_msgctl, msgctl, DEFAULT_VERSION);
+#if __TIMESIZE != 64
+libc_hidden_def (__msgctl64)
+
+static void
+msqid_to_msqid64 (struct __msqid64_ds *mq64, const struct msqid_ds *mq)
+{
+  mq64->msg_perm   = mq->msg_perm;
+  mq64->msg_stime  = mq->msg_stime
+		     | ((__time64_t) mq->__msg_stime_high << 32);
+  mq64->msg_rtime  = mq->msg_rtime
+		     | ((__time64_t) mq->__msg_rtime_high << 32);
+  mq64->msg_ctime  = mq->msg_ctime
+		     | ((__time64_t) mq->__msg_ctime_high << 32);
+  mq64->msg_qnum   = mq->msg_qnum;
+  mq64->msg_qbytes = mq->msg_qbytes;
+  mq64->msg_lspid  = mq->msg_lspid;
+  mq64->msg_lrpid  = mq->msg_lrpid;
+}
+
+static void
+msqid64_to_msqid (struct msqid_ds *mq, const struct __msqid64_ds *mq64)
+{
+  mq->msg_perm         = mq64->msg_perm;
+  mq->msg_stime        = mq64->msg_stime;
+  mq->__msg_stime_high = 0;
+  mq->msg_rtime        = mq64->msg_rtime;
+  mq->__msg_rtime_high = 0;
+  mq->msg_ctime        = mq64->msg_ctime;
+  mq->__msg_ctime_high = 0;
+  mq->msg_qnum         = mq64->msg_qnum;
+  mq->msg_qbytes       = mq64->msg_qbytes;
+  mq->msg_lspid        = mq64->msg_lspid;
+  mq->msg_lrpid        = mq64->msg_lrpid;
+}
+
+int
+__msgctl (int msqid, int cmd, struct msqid_ds *buf)
+{
+  struct __msqid64_ds msqid64, *buf64 = NULL;
+  if (buf != NULL)
+    {
+      msqid_to_msqid64 (&msqid64, buf);
+      buf64 = &msqid64;
+    }
+
+  int ret = __msgctl64 (msqid, cmd, buf64);
+  if (ret < 0)
+    return ret;
+
+  switch (cmd)
+    {
+    case IPC_STAT:
+    case MSG_STAT:
+    case MSG_STAT_ANY:
+      if (buf64 != NULL)
+        msqid64_to_msqid (buf, buf64);
+    }
+
+  return ret;
+}
+#endif
+
+#ifndef DEFAULT_VERSION
+# ifndef __ASSUME_SYSVIPC_BROKEN_MODE_T
+#  define DEFAULT_VERSION GLIBC_2_2
+# else
+#  define DEFAULT_VERSION GLIBC_2_31
+# endif
+#endif
+versioned_symbol (libc, __msgctl, msgctl, DEFAULT_VERSION);
 
 #if defined __ASSUME_SYSVIPC_BROKEN_MODE_T \
     && SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_31)
@@ -90,7 +201,7 @@  int
 attribute_compat_text_section
 __msgctl_mode16 (int msqid, int cmd, struct msqid_ds *buf)
 {
-  return msgctl_syscall (msqid, cmd, buf);
+  return msgctl_syscall (msqid, cmd, (msgctl_arg_t *) buf);
 }
 compat_symbol (libc, __msgctl_mode16, msgctl, GLIBC_2_2);
 #endif
diff --git a/sysdeps/unix/sysv/linux/powerpc/bits/types/struct_msqid_ds.h b/sysdeps/unix/sysv/linux/powerpc/bits/types/struct_msqid_ds.h
index 4ae2fbcbdc..35cc51f733 100644
--- a/sysdeps/unix/sysv/linux/powerpc/bits/types/struct_msqid_ds.h
+++ b/sysdeps/unix/sysv/linux/powerpc/bits/types/struct_msqid_ds.h
@@ -26,11 +26,11 @@  struct msqid_ds
 {
   struct ipc_perm msg_perm;	/* structure describing operation permission */
 #if __TIMESIZE == 32
-  unsigned long int __glibc_reserved1;
+  unsigned long int __msg_stime_high;
   __time_t msg_stime;		/* time of last msgsnd command */
-  unsigned long int __glibc_reserved2;
+  unsigned long int __msg_rtime_high;
   __time_t msg_rtime;		/* time of last msgsnd command */
-  unsigned long int __glibc_reserved3;
+  unsigned long int __msg_ctime_high;
   __time_t msg_ctime;		/* time of last change */
 #else
   __time_t msg_stime;		/* time of last msgsnd command */
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/struct_kernel_msqid64_ds.h b/sysdeps/unix/sysv/linux/powerpc/powerpc32/struct_kernel_msqid64_ds.h
new file mode 100644
index 0000000000..69a63ee27a
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/struct_kernel_msqid64_ds.h
@@ -0,0 +1,18 @@ 
+/* Analogous to kernel struct msqid64_ds used on msgctl.  */
+struct kernel_msqid64_ds
+{
+  struct ipc_perm msg_perm;
+  unsigned long msg_stime_high;
+  unsigned long msg_stime;
+  unsigned long msg_rtime_high;
+  unsigned long msg_rtime;
+  unsigned long msg_ctime_high;
+  unsigned long msg_ctime;
+  unsigned long msg_cbytes;
+  unsigned long msg_qnum;
+  unsigned long msg_qbytes;
+  __pid_t msg_lspid;
+  __pid_t msg_lrpid;
+  unsigned long __unused1;
+  unsigned long __unused2;
+};
diff --git a/sysdeps/unix/sysv/linux/semctl.c b/sysdeps/unix/sysv/linux/semctl.c
index 90460e6310..005c00ea75 100644
--- a/sysdeps/unix/sysv/linux/semctl.c
+++ b/sysdeps/unix/sysv/linux/semctl.c
@@ -196,19 +196,11 @@  libc_hidden_def (__semctl64)
 
 /* The 64-bit time_t semid_ds version might have a different layout and
    internal field alignment.  */
-static void
-semid64_ds_to_semid_ds (struct semid_ds *ds, const struct __semid64_ds *ds64)
-{
-  ds->sem_perm = ds64->sem_perm;
-  ds->sem_otime = ds64->sem_otime;
-  ds->sem_ctime = ds64->sem_ctime;
-  ds->sem_nsems = ds64->sem_nsems;
-}
 
 static void
-semid_ds_to_semid64_ds (struct __semid64_ds *ds64, const struct semid_ds *ds)
+semid_to_semid64 (struct __semid64_ds *ds64, const struct semid_ds *ds)
 {
-  ds64->sem_perm = ds->sem_perm;
+  ds64->sem_perm  = ds->sem_perm;
   ds64->sem_otime = ds->sem_otime
 		    | ((__time64_t) ds->__sem_otime_high << 32);
   ds64->sem_ctime = ds->sem_ctime
@@ -216,6 +208,17 @@  semid_ds_to_semid64_ds (struct __semid64_ds *ds64, const struct semid_ds *ds)
   ds64->sem_nsems = ds->sem_nsems;
 }
 
+static void
+semid64_to_semid (struct semid_ds *ds, const struct __semid64_ds *ds64)
+{
+  ds->sem_perm         = ds64->sem_perm;
+  ds->sem_otime        = ds64->sem_otime;
+  ds->__sem_otime_high = 0;
+  ds->sem_ctime        = ds64->sem_ctime;
+  ds->__sem_ctime_high = 0;
+  ds->sem_nsems        = ds64->sem_nsems;
+}
+
 static union semun64
 semun_to_semun64 (int cmd, union semun semun, struct __semid64_ds *semid64)
 {
@@ -232,7 +235,7 @@  semun_to_semun64 (int cmd, union semun semun, struct __semid64_ds *semid64)
     case IPC_STAT:
     case IPC_SET:
       r.buf = semid64;
-      semid_ds_to_semid64_ds (r.buf, semun.buf);
+      semid_to_semid64 (r.buf, semun.buf);
 # ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
       if (cmd == IPC_SET)
 	r.buf->sem_perm.mode *= 0x10000U;
@@ -282,7 +285,7 @@  __semctl (int semid, int semnum, int cmd, ...)
     case IPC_STAT:
     case SEM_STAT:
     case SEM_STAT_ANY:
-      semid64_ds_to_semid_ds (arg.buf, arg64.buf);
+      semid64_to_semid (arg.buf, arg64.buf);
     }
 
   return ret;
diff --git a/sysdeps/unix/sysv/linux/sparc/bits/types/struct_msqid_ds.h b/sysdeps/unix/sysv/linux/sparc/bits/types/struct_msqid_ds.h
index 71980839c7..502c23d91e 100644
--- a/sysdeps/unix/sysv/linux/sparc/bits/types/struct_msqid_ds.h
+++ b/sysdeps/unix/sysv/linux/sparc/bits/types/struct_msqid_ds.h
@@ -26,11 +26,11 @@  struct msqid_ds
 {
   struct ipc_perm msg_perm;	/* structure describing operation permission */
 #if __TIMESIZE == 32
-  unsigned long int __glibc_reserved1;
+  unsigned long int __msg_stime_high;
   __time_t msg_stime;		/* time of last msgsnd command */
-  unsigned long int __glibc_reserved2;
+  unsigned long int __msg_rtime_high;
   __time_t msg_rtime;		/* time of last msgsnd command */
-  unsigned long int __glibc_reserved3;
+  unsigned long int __msg_ctime_high;
   __time_t msg_ctime;		/* time of last change */
 #else
   __time_t msg_stime;		/* time of last msgsnd command */
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/struct_kernel_msqid64_ds.h b/sysdeps/unix/sysv/linux/sparc/sparc32/struct_kernel_msqid64_ds.h
new file mode 100644
index 0000000000..69a63ee27a
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/struct_kernel_msqid64_ds.h
@@ -0,0 +1,18 @@ 
+/* Analogous to kernel struct msqid64_ds used on msgctl.  */
+struct kernel_msqid64_ds
+{
+  struct ipc_perm msg_perm;
+  unsigned long msg_stime_high;
+  unsigned long msg_stime;
+  unsigned long msg_rtime_high;
+  unsigned long msg_rtime;
+  unsigned long msg_ctime_high;
+  unsigned long msg_ctime;
+  unsigned long msg_cbytes;
+  unsigned long msg_qnum;
+  unsigned long msg_qbytes;
+  __pid_t msg_lspid;
+  __pid_t msg_lrpid;
+  unsigned long __unused1;
+  unsigned long __unused2;
+};
diff --git a/sysdeps/unix/sysv/linux/struct_kernel_msqid64_ds.h b/sysdeps/unix/sysv/linux/struct_kernel_msqid64_ds.h
new file mode 100644
index 0000000000..b88d910adc
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/struct_kernel_msqid64_ds.h
@@ -0,0 +1,19 @@ 
+/* Analogous to kernel struct msqid64_ds used on msgctl.  It is only used
+   for 32-bit architectures on 64-bit time_t msgctl64 implementation.  */
+struct kernel_msqid64_ds
+{
+  struct ipc_perm msg_perm;
+  unsigned long int msg_stime;
+  unsigned long int msg_stime_high;
+  unsigned long int msg_rtime;
+  unsigned long int msg_rtime_high;
+  unsigned long int msg_ctime;
+  unsigned long int msg_ctime_high;
+  unsigned long int msg_cbytes;
+  unsigned long int msg_qnum;
+  unsigned long int msg_qbytes;
+  __pid_t msg_lspid;
+  __pid_t msg_lrpid;
+  unsigned long int __unused4;
+  unsigned long int __unused5;
+};