[4/7] sysv: linux: Add 64-bit time_t variant for msgctl

Message ID 20200630192441.3299710-4-adhemerval.zanella@linaro.org
State Superseded
Headers show
Series
  • [1/7] sysv: linux: Add 64-bit time_t variant for semctl
Related show

Commit Message

Alistair Francis via Libc-alpha June 30, 2020, 7:24 p.m.
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
copy for the 32 bit time_t implementation).

Two two new structures are added:

  1. kernel_msqid64_ds: used internally only on 32-bit architectures
     to issue the syscall.  A handful architectures (hppa, i386, mips,
     powerpc32, and sparc32) requires specific implementation due its
     specific 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 one because
     the exported 64-bit time_t might require different alignment
     depending of the architecture ABI.

So the resulting implementation does:

  1. For 64-bit architectures it assumes msqid_ds already contains
     64-bit time_t fields it 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 on
     basis of the 64-bit one.

     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.
---
 include/sys/msg.h                             |  10 +
 .../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 ++
 .../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
 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

-- 
2.25.1

Comments

Alistair Francis via Libc-alpha July 2, 2020, 9:39 p.m. | #1
On Tue, Jun 30, 2020 at 12:27 PM Adhemerval Zanella via Libc-alpha
<libc-alpha@sourceware.org> wrote:
>

> 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

> copy for the 32 bit time_t implementation).

>

> Two two new structures are added:

>

>   1. kernel_msqid64_ds: used internally only on 32-bit architectures

>      to issue the syscall.  A handful architectures (hppa, i386, mips,

>      powerpc32, and sparc32) requires specific implementation due its

>      specific 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 one because

>      the exported 64-bit time_t might require different alignment

>      depending of the architecture ABI.

>

> So the resulting implementation does:

>

>   1. For 64-bit architectures it assumes msqid_ds already contains

>      64-bit time_t fields it 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 on

>      basis of the 64-bit one.

>

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

> ---

>  include/sys/msg.h                             |  10 +

>  .../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 ++

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

>  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/include/sys/msg.h b/include/sys/msg.h

> index 43ec5b9472..522903f818 100644

> --- a/include/sys/msg.h

> +++ b/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/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/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


Shouldn't everything below here be in a separate patch?

Alistair

> 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 3a06270242..7467d2566e 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..a676e34a5a

> --- /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

>
Alistair Francis via Libc-alpha July 7, 2020, 7:51 p.m. | #2
On 6/30/20 3:24 PM, Adhemerval Zanella via Libc-alpha wrote:

OK for master with textual changes.

Tested on x86_64 and i686.

Tested-by: Carlos O'Donell <carlos@redhat.com>

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

> copy for the 32 bit time_t implementation).


s/copy/copying/g

> 

> Two two new structures are added:


s/Two two/Two/g

> 

>   1. kernel_msqid64_ds: used internally only on 32-bit architectures

>      to issue the syscall.  A handful architectures (hppa, i386, mips,


s/handful/handful of/g

>      powerpc32, and sparc32) requires specific implementation due its

>      specific kernel ABI.

> 


Suggest:

require specific implementations due to their kernel ABI.

(get to reuse my text from 0/7 ;-))

>   2. msqid_ds64: this is only for __TIMESIZE != 64 to use along with

>      the 64-bit semctl.  It is different than the kernel one because


s/one/struct/g

>      the exported 64-bit time_t might require different alignment

>      depending of the architecture ABI.


s/of/on/g (fix in 0/7 also required)

> 

> So the resulting implementation does:

> 

>   1. For 64-bit architectures it assumes msqid_ds already contains

>      64-bit time_t fields it will result in just the __msgctl symbol


s/it/and/g

>      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 on

>      basis of the 64-bit one.


s/on basis of/using/g
s/one/time_t/g

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

> ---

>  include/sys/msg.h                             |  10 +

>  .../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 ++

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

>  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/include/sys/msg.h b/include/sys/msg.h

> index 43ec5b9472..522903f818 100644

> --- a/include/sys/msg.h

> +++ b/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);


OK.

> +# endif

> +

>  #endif

>  

>  #endif

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


OK.

> +   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 */


OK.

> +  __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;


OK.

>  #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;


OK

>    __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;


OK.

> +  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;


OK.

> +  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/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;


OK.

>    __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;


OK.

> +# 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)");


OK.

> +

> +#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;

> +}


OK.

> +

> +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;

> +}


OK.

> +

> +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;

>  }


OK.

> -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;


OK. No high values to transfer, but zero out the high values.

> +  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);


OK.

> +  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);


OK.

>  }

>  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 */


OK.

> 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;


OK.

> +  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 3a06270242..7467d2566e 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;

> +}


OK.

> +

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

> --- /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;

> +};

> 



-- 
Cheers,
Carlos.
Alistair Francis via Libc-alpha July 8, 2020, 6:07 p.m. | #3
On Thu, Jul 2, 2020 at 6:49 PM Alistair Francis <alistair23@gmail.com> wrote:
> >  #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

>

> Shouldn't everything below here be in a separate patch?


Sorry, I just saw you reply now. Yes, It has wrongly bled to this
patch. I will fix it.

Patch

diff --git a/include/sys/msg.h b/include/sys/msg.h
index 43ec5b9472..522903f818 100644
--- a/include/sys/msg.h
+++ b/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/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/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 3a06270242..7467d2566e 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..a676e34a5a
--- /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;
+};