diff mbox series

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

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

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/shm.h sysdeps/unix/sysv/linux/include/sys/shm.h

It basically avoids a build failure on Hurd (since it does not provide
struct_shmid64_ds.h).

---

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

Two two new structures are added:

  1. kernel_shmid64_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. shmid_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 shmid_ds already contains
     64-bit time_t fields and will result in just the __shmctl symbol
     using the __shmctl64 code.  The shmid_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 of the 64-bit one.

     The default 32-bit symbol will allocate and copy the shmid_ds
     over multiple buffers, but this should be deprecated in favor
     of the __shmctl64 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>
---
 include/sys/shm.h                             |   1 -
 .../sysv/linux/bits/types/struct_shmid64_ds.h |  37 ++++
 .../sysv/linux/bits/types/struct_shmid_ds.h   |   6 +-
 .../linux/hppa/bits/types/struct_shmid_ds.h   |   6 +-
 .../linux/hppa/struct_kernel_shmid64_ds.h     |  18 ++
 .../linux/i386/struct_kernel_shmid64_ds.h     |  17 ++
 sysdeps/unix/sysv/linux/include/sys/shm.h     |  17 ++
 .../linux/mips/bits/types/struct_shmid_ds.h   |   6 +-
 .../linux/mips/struct_kernel_shmid64_ds.h     |  27 +++
 .../powerpc/bits/types/struct_shmid_ds.h      |   6 +-
 .../linux/powerpc/struct_kernel_shmid64_ds.h  |  18 ++
 sysdeps/unix/sysv/linux/shmctl.c              | 180 ++++++++++++++----
 .../linux/sparc/bits/types/struct_shmid_ds.h  |   6 +-
 .../linux/sparc/struct_kernel_shmid64_ds.h    |  17 ++
 .../sysv/linux/struct_kernel_shmid64_ds.h     |  17 ++
 15 files changed, 329 insertions(+), 50 deletions(-)
 delete mode 100644 include/sys/shm.h
 create mode 100644 sysdeps/unix/sysv/linux/bits/types/struct_shmid64_ds.h
 create mode 100644 sysdeps/unix/sysv/linux/hppa/struct_kernel_shmid64_ds.h
 create mode 100644 sysdeps/unix/sysv/linux/i386/struct_kernel_shmid64_ds.h
 create mode 100644 sysdeps/unix/sysv/linux/include/sys/shm.h
 create mode 100644 sysdeps/unix/sysv/linux/mips/struct_kernel_shmid64_ds.h
 create mode 100644 sysdeps/unix/sysv/linux/powerpc/struct_kernel_shmid64_ds.h
 create mode 100644 sysdeps/unix/sysv/linux/sparc/struct_kernel_shmid64_ds.h
 create mode 100644 sysdeps/unix/sysv/linux/struct_kernel_shmid64_ds.h

Comments

Carlos O'Donell July 8, 2020, 5:02 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/shm.h sysdeps/unix/sysv/linux/include/sys/shm.h
> 
> It basically avoids a build failure on Hurd (since it does not provide
> struct_shmid64_ds.h).

OK for master with all previous commit message and textual changes made.

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

> ---
> 
> To provide a y2038 safe interface a new symbol __shmctl64 is added
> and __shmctl is change to call it instead (it adds some extra buffer
> coping for the 32 bit time_t implementation).
> 
> Two two new structures are added:
> 
>   1. kernel_shmid64_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. shmid_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 shmid_ds already contains
>      64-bit time_t fields and will result in just the __shmctl symbol
>      using the __shmctl64 code.  The shmid_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 of the 64-bit one.
> 
>      The default 32-bit symbol will allocate and copy the shmid_ds
>      over multiple buffers, but this should be deprecated in favor
>      of the __shmctl64 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>
> ---
>  include/sys/shm.h                             |   1 -
>  .../sysv/linux/bits/types/struct_shmid64_ds.h |  37 ++++
>  .../sysv/linux/bits/types/struct_shmid_ds.h   |   6 +-
>  .../linux/hppa/bits/types/struct_shmid_ds.h   |   6 +-
>  .../linux/hppa/struct_kernel_shmid64_ds.h     |  18 ++
>  .../linux/i386/struct_kernel_shmid64_ds.h     |  17 ++
>  sysdeps/unix/sysv/linux/include/sys/shm.h     |  17 ++
>  .../linux/mips/bits/types/struct_shmid_ds.h   |   6 +-
>  .../linux/mips/struct_kernel_shmid64_ds.h     |  27 +++
>  .../powerpc/bits/types/struct_shmid_ds.h      |   6 +-
>  .../linux/powerpc/struct_kernel_shmid64_ds.h  |  18 ++
>  sysdeps/unix/sysv/linux/shmctl.c              | 180 ++++++++++++++----
>  .../linux/sparc/bits/types/struct_shmid_ds.h  |   6 +-
>  .../linux/sparc/struct_kernel_shmid64_ds.h    |  17 ++
>  .../sysv/linux/struct_kernel_shmid64_ds.h     |  17 ++
>  15 files changed, 329 insertions(+), 50 deletions(-)
>  delete mode 100644 include/sys/shm.h
>  create mode 100644 sysdeps/unix/sysv/linux/bits/types/struct_shmid64_ds.h
>  create mode 100644 sysdeps/unix/sysv/linux/hppa/struct_kernel_shmid64_ds.h
>  create mode 100644 sysdeps/unix/sysv/linux/i386/struct_kernel_shmid64_ds.h
>  create mode 100644 sysdeps/unix/sysv/linux/include/sys/shm.h
>  create mode 100644 sysdeps/unix/sysv/linux/mips/struct_kernel_shmid64_ds.h
>  create mode 100644 sysdeps/unix/sysv/linux/powerpc/struct_kernel_shmid64_ds.h
>  create mode 100644 sysdeps/unix/sysv/linux/sparc/struct_kernel_shmid64_ds.h
>  create mode 100644 sysdeps/unix/sysv/linux/struct_kernel_shmid64_ds.h
> 
> diff --git a/include/sys/shm.h b/include/sys/shm.h
> deleted file mode 100644
> index 1878fcc5be..0000000000
> --- a/include/sys/shm.h
> +++ /dev/null
> @@ -1 +0,0 @@
> -#include <sysvipc/sys/shm.h>
> diff --git a/sysdeps/unix/sysv/linux/bits/types/struct_shmid64_ds.h b/sysdeps/unix/sysv/linux/bits/types/struct_shmid64_ds.h
> new file mode 100644
> index 0000000000..f71e0d28ff
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/bits/types/struct_shmid64_ds.h
> @@ -0,0 +1,37 @@
> +/* Generic implementation of the shared memory struct shmid_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_SHM_H
> +# error "Never include <bits/types/struct_shmid_ds.h> directly; use <sys/shm.h> instead."
> +#endif
> +
> +#if __TIMESIZE == 64
> +# define __shmid64_ds shmid_ds
> +#else
> +struct __shmid64_ds
> +{
> +  struct ipc_perm shm_perm;	/* operation permission struct */
> +  size_t shm_segsz;		/* size of segment in bytes */
> +  __time64_t shm_atime;		/* time of last shmat() */
> +  __time64_t shm_dtime;		/* time of last shmdt() */
> +  __time64_t shm_ctime;		/* time of last change by shmctl() */
> +  __pid_t shm_cpid;		/* pid of creator */
> +  __pid_t shm_lpid;		/* pid of last shmop */
> +  shmatt_t shm_nattch;		/* number of current attaches */
> +};
> +#endif
> diff --git a/sysdeps/unix/sysv/linux/bits/types/struct_shmid_ds.h b/sysdeps/unix/sysv/linux/bits/types/struct_shmid_ds.h
> index 61ed4a08c3..836a7d50e9 100644
> --- a/sysdeps/unix/sysv/linux/bits/types/struct_shmid_ds.h
> +++ b/sysdeps/unix/sysv/linux/bits/types/struct_shmid_ds.h
> @@ -27,11 +27,11 @@ struct shmid_ds
>      size_t shm_segsz;			/* size of segment in bytes */
>  #if __TIMESIZE == 32
>      __time_t shm_atime;			/* time of last shmat() */
> -    unsigned long int __glibc_reserved1;
> +    unsigned long int __shm_atime_high;
>      __time_t shm_dtime;			/* time of last shmdt() */
> -    unsigned long int __glibc_reserved2;
> +    unsigned long int __shm_dtime_high;
>      __time_t shm_ctime;			/* time of last change by shmctl() */
> -    unsigned long int __glibc_reserved3;
> +    unsigned long int __shm_ctime_high;
>  #else
>      __time_t shm_atime;			/* time of last shmat() */
>      __time_t shm_dtime;			/* time of last shmdt() */
> diff --git a/sysdeps/unix/sysv/linux/hppa/bits/types/struct_shmid_ds.h b/sysdeps/unix/sysv/linux/hppa/bits/types/struct_shmid_ds.h
> index 1ebf222eac..1abed1e149 100644
> --- a/sysdeps/unix/sysv/linux/hppa/bits/types/struct_shmid_ds.h
> +++ b/sysdeps/unix/sysv/linux/hppa/bits/types/struct_shmid_ds.h
> @@ -25,11 +25,11 @@ struct shmid_ds
>    {
>      struct ipc_perm shm_perm;		/* operation permission struct */
>  #if __TIMESIZE == 32
> -    unsigned long int __glibc_reserved1;
> +    unsigned long int __shm_atime_high;
>      __time_t shm_atime;			/* time of last shmat() */
> -    unsigned long int __glibc_reserved2;
> +    unsigned long int __shm_dtime_high;
>      __time_t shm_dtime;			/* time of last shmdt() */
> -    unsigned long int __glibc_reserved3;
> +    unsigned long int __shm_ctime_high;
>      __time_t shm_ctime;			/* time of last change by shmctl() */
>      unsigned long int __glibc_reserved4;
>  #else
> diff --git a/sysdeps/unix/sysv/linux/hppa/struct_kernel_shmid64_ds.h b/sysdeps/unix/sysv/linux/hppa/struct_kernel_shmid64_ds.h
> new file mode 100644
> index 0000000000..4d09fc7f62
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/hppa/struct_kernel_shmid64_ds.h
> @@ -0,0 +1,18 @@
> +/* Analogous to kernel struct shmid64_ds used on shmctl.  */
> +struct kernel_shmid64_ds
> +{
> +  struct ipc_perm shm_perm;		/* operation permission struct */
> +  unsigned long int shm_atime_high;
> +  unsigned long int shm_atime;		/* time of last shmat() */
> +  unsigned long int shm_dtime_high;
> +  unsigned long int shm_dtime;		/* time of last shmdt() */
> +  unsigned long int shm_ctime_high;
> +  unsigned long int shm_ctime;		/* time of last change by shmctl() */
> +  unsigned long int __pad;
> +  size_t shm_segsz;			/* size of segment in bytes */
> +  __pid_t shm_cpid;			/* pid of creator */
> +  __pid_t shm_lpid;			/* pid of last shmop */
> +  shmatt_t shm_nattch;		/* number of current attaches */
> +  unsigned long int __unused1;
> +  unsigned long int __unused2;
> +};
> diff --git a/sysdeps/unix/sysv/linux/i386/struct_kernel_shmid64_ds.h b/sysdeps/unix/sysv/linux/i386/struct_kernel_shmid64_ds.h
> new file mode 100644
> index 0000000000..6a0a0d9c71
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/i386/struct_kernel_shmid64_ds.h
> @@ -0,0 +1,17 @@
> +/* Analogous to kernel struct compat_shmid64_ds used on shmctl.  */
> +struct kernel_shmid64_ds
> +{
> +  struct ipc_perm shm_perm;
> +  size_t shm_segsz;
> +  unsigned long int shm_atime;
> +  unsigned long int shm_atime_high;
> +  unsigned long int shm_dtime;
> +  unsigned long int shm_dtime_high;
> +  unsigned long int shm_ctime;
> +  unsigned long int shm_ctime_high;
> +  __pid_t shm_cpid;
> +  __pid_t shm_lpid;
> +  unsigned long int shm_nattch;
> +  unsigned long int __unused4;
> +  unsigned long int __unused5;
> +};
> diff --git a/sysdeps/unix/sysv/linux/include/sys/shm.h b/sysdeps/unix/sysv/linux/include/sys/shm.h
> new file mode 100644
> index 0000000000..530a1cdfc9
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/include/sys/shm.h
> @@ -0,0 +1,17 @@
> +#ifndef _SYS_SHM_H
> +#include <sysvipc/sys/shm.h>
> +
> +#ifndef _ISOMAC
> +
> +# include <bits/types/struct_shmid64_ds.h>
> +
> +# if __TIMESIZE == 64
> +#  define __shmctl64 __shmctl
> +# else
> +extern int __shmctl64 (int shmid, int cmd, struct __shmid64_ds *buf);
> +libc_hidden_proto (__shmctl64);
> +# endif
> +
> +#endif /* _ISOMAC  */
> +
> +#endif /* _SYS_SHM_H  */
> diff --git a/sysdeps/unix/sysv/linux/mips/bits/types/struct_shmid_ds.h b/sysdeps/unix/sysv/linux/mips/bits/types/struct_shmid_ds.h
> index 8e13928980..58090e2fcb 100644
> --- a/sysdeps/unix/sysv/linux/mips/bits/types/struct_shmid_ds.h
> +++ b/sysdeps/unix/sysv/linux/mips/bits/types/struct_shmid_ds.h
> @@ -38,9 +38,9 @@ struct shmid_ds
>      __pid_t shm_lpid;			/* pid of last shmop */
>      shmatt_t shm_nattch;		/* number of current attaches */
>  #if __TIMESIZE == 32
> -    unsigned short int __glibc_reserved1;
> -    unsigned short int __glibc_reserved2;
> -    unsigned short int __glibc_reserved3;
> +    unsigned short int __shm_atime_high;
> +    unsigned short int __shm_dtime_high;
> +    unsigned short int __shm_ctime_high;
>      unsigned short int __glibc_reserved4;
>  #else
>      __syscall_ulong_t __glibc_reserved5;
> diff --git a/sysdeps/unix/sysv/linux/mips/struct_kernel_shmid64_ds.h b/sysdeps/unix/sysv/linux/mips/struct_kernel_shmid64_ds.h
> new file mode 100644
> index 0000000000..a4baa5614f
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/mips/struct_kernel_shmid64_ds.h
> @@ -0,0 +1,27 @@
> +/* Analogous to kernel struct shmid64_ds used on shmctl.  */
> +struct kernel_shmid64_ds
> +{
> +  struct ipc_perm shm_perm;
> +  size_t shm_segsz;
> +#if __TIMESIZE == 64
> +  long int shm_atime;
> +  long int shm_dtime;
> +  long int shm_ctime;
> +#else
> +  unsigned long int shm_atime;
> +  unsigned long int shm_dtime;
> +  unsigned long int shm_ctime;
> +#endif
> +  __pid_t shm_cpid;
> +  __pid_t shm_lpid;
> +  unsigned long int shm_nattch;
> +#if __TIMESIZE == 64
> +  unsigned long int __unused1;
> +  unsigned long int __unused2;
> +#else
> +  unsigned short int shm_atime_high;
> +  unsigned short int shm_dtime_high;
> +  unsigned short int shm_ctime_high;
> +  unsigned short int __ununsed1;
> +#endif
> +};
> diff --git a/sysdeps/unix/sysv/linux/powerpc/bits/types/struct_shmid_ds.h b/sysdeps/unix/sysv/linux/powerpc/bits/types/struct_shmid_ds.h
> index b0816fb16a..39b3e5fd3e 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/bits/types/struct_shmid_ds.h
> +++ b/sysdeps/unix/sysv/linux/powerpc/bits/types/struct_shmid_ds.h
> @@ -25,11 +25,11 @@ struct shmid_ds
>    {
>      struct ipc_perm shm_perm;		/* operation permission struct */
>  #if __TIMESIZE == 32
> -    unsigned long int __glibc_reserved1;
> +    unsigned long int __shm_atime_high;
>      __time_t shm_atime;			/* time of last shmat() */
> -    unsigned long int __glibc_reserved2;
> +    unsigned long int __shm_dtime_high;
>      __time_t shm_dtime;			/* time of last shmdt() */
> -    unsigned long int __glibc_reserved3;
> +    unsigned long int __shm_ctime_high;
>      __time_t shm_ctime;			/* time of last change by shmctl() */
>      unsigned long int __glibc_reserved4;
>  #else
> diff --git a/sysdeps/unix/sysv/linux/powerpc/struct_kernel_shmid64_ds.h b/sysdeps/unix/sysv/linux/powerpc/struct_kernel_shmid64_ds.h
> new file mode 100644
> index 0000000000..ae3f3987ac
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/powerpc/struct_kernel_shmid64_ds.h
> @@ -0,0 +1,18 @@
> +/* Analogous to kernel struct shmid64_ds used on shmctl.  */
> +struct kernel_shmid64_ds
> +{
> +  struct ipc_perm shm_perm;
> +  unsigned long int shm_atime_high;
> +  unsigned long int shm_atime;
> +  unsigned long int shm_dtime_high;
> +  unsigned long int shm_dtime;
> +  unsigned long int shm_ctime_high;
> +  unsigned long int shm_ctime;
> +  unsigned long int __ununsed1;
> +  size_t shm_segsz;
> +  __pid_t shm_cpid;
> +  __pid_t shm_lpid;
> +  unsigned long int shm_nattch;
> +  unsigned long int __unused2;
> +  unsigned long int __unused3;
> +};
> diff --git a/sysdeps/unix/sysv/linux/shmctl.c b/sysdeps/unix/sysv/linux/shmctl.c
> index f41b359b8b..aaf3946054 100644
> --- a/sysdeps/unix/sysv/linux/shmctl.c
> +++ b/sysdeps/unix/sysv/linux/shmctl.c
> @@ -24,16 +24,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 shmid_ds){0}.shm_perm.mode)
> +		== sizeof (mode_t),
> +		"sizeof (shmid_ds.shm_perm.mode) != sizeof (mode_t)");
> +
> +#if __IPC_TIME64 == 0
> +typedef struct shmid_ds shmctl_arg_t;
> +#else
> +# include <struct_kernel_shmid64_ds.h>
> +
> +static void
> +shmid64_to_kshmid64 (const struct __shmid64_ds *shmid64,
> +		     struct kernel_shmid64_ds *kshmid)
> +{
> +  kshmid->shm_perm       = shmid64->shm_perm;
> +  kshmid->shm_segsz      = shmid64->shm_segsz;
> +  kshmid->shm_atime      = shmid64->shm_atime;
> +  kshmid->shm_atime_high = shmid64->shm_atime >> 32;
> +  kshmid->shm_dtime      = shmid64->shm_dtime;
> +  kshmid->shm_dtime_high = shmid64->shm_dtime >> 32;
> +  kshmid->shm_ctime      = shmid64->shm_ctime;
> +  kshmid->shm_ctime_high = shmid64->shm_ctime >> 32;
> +  kshmid->shm_cpid       = shmid64->shm_cpid;
> +  kshmid->shm_lpid       = shmid64->shm_lpid;
> +  kshmid->shm_nattch     = shmid64->shm_nattch;
> +}
> +
> +static void
> +kshmid64_to_shmid64 (const struct kernel_shmid64_ds *kshmid,
> +		     struct __shmid64_ds *shmid64)
> +{
> +  shmid64->shm_perm   = kshmid->shm_perm;
> +  shmid64->shm_segsz  = kshmid->shm_segsz;
> +  shmid64->shm_atime  = kshmid->shm_atime
> +		        | ((__time64_t) kshmid->shm_atime_high << 32);
> +  shmid64->shm_dtime  = kshmid->shm_dtime
> +		        | ((__time64_t) kshmid->shm_dtime_high << 32);
> +  shmid64->shm_ctime     = kshmid->shm_ctime
> +		        | ((__time64_t) kshmid->shm_ctime_high << 32);
> +  shmid64->shm_cpid   = kshmid->shm_cpid;
> +  shmid64->shm_lpid   = kshmid->shm_lpid;
> +  shmid64->shm_nattch = kshmid->shm_nattch;
> +}
> +
> +typedef struct kernel_shmid64_ds shmctl_arg_t;
>  #endif
>  
>  static int
> -shmctl_syscall (int shmid, int cmd, struct shmid_ds *buf)
> +shmctl_syscall (int shmid, int cmd, shmctl_arg_t *buf)
>  {
>  #ifdef __ASSUME_DIRECT_SYSVIPC_SYSCALLS
>    return INLINE_SYSCALL_CALL (shmctl, shmid, cmd | __IPC_64, buf);
> @@ -45,46 +84,119 @@ shmctl_syscall (int shmid, int cmd, struct shmid_ds *buf)
>  
>  /* Provide operations to control over shared memory segments.  */
>  int
> -__new_shmctl (int shmid, int cmd, struct shmid_ds *buf)
> +__shmctl64 (int shmid, int cmd, struct __shmid64_ds *buf)
>  {
> -  /* POSIX states ipc_perm mode should have type of mode_t.  */
> -  _Static_assert (sizeof ((struct shmid_ds){0}.shm_perm.mode)
> -		  == sizeof (mode_t),
> -		  "sizeof (msqid_ds.msg_perm.mode) != sizeof (mode_t)");
> -
> -#ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
> -  struct shmid_ds tmpds;
> -  if (cmd == IPC_SET)
> +#if __IPC_TIME64
> +  struct kernel_shmid64_ds kshmid, *arg = NULL;
> +  if (buf != NULL)
>      {
> -      tmpds = *buf;
> -      tmpds.shm_perm.mode *= 0x10000U;
> -      buf = &tmpds;
> +      shmid64_to_kshmid64 (buf, &kshmid);
> +      arg = &kshmid;
>      }
> +# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
> +  if (cmd == IPC_SET)
> +      arg->shm_perm.mode *= 0x10000U;
> +# endif
> +#else
> +  shmctl_arg_t *arg = buf;
>  #endif
>  
> -  int ret = shmctl_syscall (shmid, cmd, buf);
> +  int ret = shmctl_syscall (shmid, cmd, arg);
> +  if (ret < 0)
> +    return ret;
>  
> -  if (ret >= 0)
> +  switch (cmd)
>      {
> -      switch (cmd)
> -	{
> -        case IPC_STAT:
> -        case SHM_STAT:
> -        case SHM_STAT_ANY:
> +      case IPC_STAT:
> +      case SHM_STAT:
> +      case SHM_STAT_ANY:
>  #ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
> -          buf->shm_perm.mode >>= 16;
> +        arg->shm_perm.mode >>= 16;
>  #else
> -	  /* Old Linux kernel versions might not clear the mode padding.  */
> -	  if (sizeof ((struct shmid_ds){0}.shm_perm.mode)
> -	      != sizeof (__kernel_mode_t))
> -	    buf->shm_perm.mode &= 0xFFFF;
> +      /* Old Linux kernel versions might not clear the mode padding.  */
> +      if (sizeof ((struct shmid_ds){0}.shm_perm.mode)
> +	  != sizeof (__kernel_mode_t))
> +	arg->shm_perm.mode &= 0xFFFF;
> +#endif
> +
> +#if __IPC_TIME64
> +      kshmid64_to_shmid64 (arg, buf);
>  #endif
> -	}
>      }
>  
>    return ret;
>  }
> -versioned_symbol (libc, __new_shmctl, shmctl, DEFAULT_VERSION);
> +#if __TIMESIZE != 64
> +libc_hidden_def (__shmctl64)
> +
> +static void
> +shmid_to_shmid64 (struct __shmid64_ds *shm64, const struct shmid_ds *shm)
> +{
> +  shm64->shm_perm   = shm->shm_perm;
> +  shm64->shm_segsz  = shm->shm_segsz;
> +  shm64->shm_atime  = shm->shm_atime
> +		        | ((__time64_t) shm->__shm_atime_high << 32);
> +  shm64->shm_dtime  = shm->shm_dtime
> +		        | ((__time64_t) shm->__shm_dtime_high << 32);
> +  shm64->shm_ctime     = shm->shm_ctime
> +		        | ((__time64_t) shm->__shm_ctime_high << 32);
> +  shm64->shm_cpid   = shm->shm_cpid;
> +  shm64->shm_lpid   = shm->shm_lpid;
> +  shm64->shm_nattch = shm->shm_nattch;
> +}
> +
> +static void
> +shmid64_to_shmid (struct shmid_ds *shm, const struct __shmid64_ds *shm64)
> +{
> +  shm->shm_perm         = shm64->shm_perm;
> +  shm->shm_segsz        = shm64->shm_segsz;
> +  shm->shm_atime        = shm64->shm_atime;
> +  shm->__shm_atime_high = 0;
> +  shm->shm_dtime        = shm64->shm_dtime;
> +  shm->__shm_dtime_high = 0;
> +  shm->shm_ctime        = shm64->shm_ctime;
> +  shm->__shm_ctime_high = 0;
> +  shm->shm_cpid         = shm64->shm_cpid;
> +  shm->shm_lpid         = shm64->shm_lpid;
> +  shm->shm_nattch       = shm64->shm_nattch;
> +}
> +
> +int
> +__shmctl (int shmid, int cmd, struct shmid_ds *buf)
> +{
> +  struct __shmid64_ds shmid64, *buf64 = NULL;
> +  if (buf != NULL)
> +    {
> +      shmid_to_shmid64 (&shmid64, buf);
> +      buf64 = &shmid64;
> +    }
> +
> +  int ret = __shmctl64 (shmid, cmd, buf64);
> +  if (ret < 0)
> +    return ret;
> +
> +  switch (cmd)
> +    {
> +      case IPC_STAT:
> +      case SHM_STAT:
> +      case SHM_STAT_ANY:
> +	if (buf64 != NULL)
> +	  shmid64_to_shmid (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, __shmctl, shmctl, DEFAULT_VERSION);
>  
>  #if defined __ASSUME_SYSVIPC_BROKEN_MODE_T \
>      && SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_31)
> @@ -92,7 +204,7 @@ int
>  attribute_compat_text_section
>  __shmctl_mode16 (int shmid, int cmd, struct shmid_ds *buf)
>  {
> -  return shmctl_syscall (shmid, cmd, buf);
> +  return shmctl_syscall (shmid, cmd, (shmctl_arg_t *) buf);
>  }
>  compat_symbol (libc, __shmctl_mode16, shmctl, GLIBC_2_2);
>  #endif
> diff --git a/sysdeps/unix/sysv/linux/sparc/bits/types/struct_shmid_ds.h b/sysdeps/unix/sysv/linux/sparc/bits/types/struct_shmid_ds.h
> index d5fb61d374..cab3a2686f 100644
> --- a/sysdeps/unix/sysv/linux/sparc/bits/types/struct_shmid_ds.h
> +++ b/sysdeps/unix/sysv/linux/sparc/bits/types/struct_shmid_ds.h
> @@ -25,11 +25,11 @@ struct shmid_ds
>    {
>      struct ipc_perm shm_perm;		/* operation permission struct */
>  #if __TIMESIZE == 32
> -    unsigned long int __glibc_reserved1;
> +    unsigned long int __shm_atime_high;
>      __time_t shm_atime;			/* time of last shmat() */
> -    unsigned long int __glibc_reserved2;
> +    unsigned long int __shm_dtime_high;
>      __time_t shm_dtime;			/* time of last shmdt() */
> -    unsigned long int __glibc_reserved3;
> +    unsigned long int __shm_ctime_high;
>      __time_t shm_ctime;			/* time of last change by shmctl() */
>  #else
>      __time_t shm_atime;			/* time of last shmat() */
> diff --git a/sysdeps/unix/sysv/linux/sparc/struct_kernel_shmid64_ds.h b/sysdeps/unix/sysv/linux/sparc/struct_kernel_shmid64_ds.h
> new file mode 100644
> index 0000000000..333a410641
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/sparc/struct_kernel_shmid64_ds.h
> @@ -0,0 +1,17 @@
> +/* Analogous to kernel struct shmid64_ds used on shmctl.  */
> +struct kernel_shmid64_ds
> +{
> +  struct ipc_perm shm_perm;
> +  unsigned long int shm_atime_high;
> +  unsigned long int shm_atime;
> +  unsigned long int shm_dtime_high;
> +  unsigned long int shm_dtime;
> +  unsigned long int shm_ctime_high;
> +  unsigned long int shm_ctime;
> +  size_t shm_segsz;
> +  __pid_t shm_cpid;
> +  __pid_t shm_lpid;
> +  unsigned long int shm_nattch;
> +  unsigned long int __unused1;
> +  unsigned long int __unused2;
> +};
> diff --git a/sysdeps/unix/sysv/linux/struct_kernel_shmid64_ds.h b/sysdeps/unix/sysv/linux/struct_kernel_shmid64_ds.h
> new file mode 100644
> index 0000000000..6fe67afccb
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/struct_kernel_shmid64_ds.h
> @@ -0,0 +1,17 @@
> +/* Analogous to kernel struct shmid64_ds used on shmctl.  */
> +struct kernel_shmid64_ds
> +{
> +  struct ipc_perm shm_perm;
> +  size_t shm_segsz;
> +  unsigned long int shm_atime;
> +  unsigned long int shm_atime_high;
> +  unsigned long int shm_dtime;
> +  unsigned long int shm_dtime_high;
> +  unsigned long int shm_ctime;
> +  unsigned long int shm_ctime_high;
> +  __pid_t shm_cpid;
> +  __pid_t shm_lpid;
> +  unsigned long int shm_nattch;
> +  unsigned long int __unused1;
> +  unsigned long int __unused2;
> +};
>
Alistair Francis July 8, 2020, 6:01 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/shm.h sysdeps/unix/sysv/linux/include/sys/shm.h
>
> It basically avoids a build failure on Hurd (since it does not provide
> struct_shmid64_ds.h).
>
> ---
>
> To provide a y2038 safe interface a new symbol __shmctl64 is added
> and __shmctl is change to call it instead (it adds some extra buffer
> coping for the 32 bit time_t implementation).
>
> Two two new structures are added:
>
>   1. kernel_shmid64_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. shmid_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 shmid_ds already contains
>      64-bit time_t fields and will result in just the __shmctl symbol
>      using the __shmctl64 code.  The shmid_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 of the 64-bit one.
>
>      The default 32-bit symbol will allocate and copy the shmid_ds
>      over multiple buffers, but this should be deprecated in favor
>      of the __shmctl64 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>

For the whole series:

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

Alistair

> ---
>  include/sys/shm.h                             |   1 -
>  .../sysv/linux/bits/types/struct_shmid64_ds.h |  37 ++++
>  .../sysv/linux/bits/types/struct_shmid_ds.h   |   6 +-
>  .../linux/hppa/bits/types/struct_shmid_ds.h   |   6 +-
>  .../linux/hppa/struct_kernel_shmid64_ds.h     |  18 ++
>  .../linux/i386/struct_kernel_shmid64_ds.h     |  17 ++
>  sysdeps/unix/sysv/linux/include/sys/shm.h     |  17 ++
>  .../linux/mips/bits/types/struct_shmid_ds.h   |   6 +-
>  .../linux/mips/struct_kernel_shmid64_ds.h     |  27 +++
>  .../powerpc/bits/types/struct_shmid_ds.h      |   6 +-
>  .../linux/powerpc/struct_kernel_shmid64_ds.h  |  18 ++
>  sysdeps/unix/sysv/linux/shmctl.c              | 180 ++++++++++++++----
>  .../linux/sparc/bits/types/struct_shmid_ds.h  |   6 +-
>  .../linux/sparc/struct_kernel_shmid64_ds.h    |  17 ++
>  .../sysv/linux/struct_kernel_shmid64_ds.h     |  17 ++
>  15 files changed, 329 insertions(+), 50 deletions(-)
>  delete mode 100644 include/sys/shm.h
>  create mode 100644 sysdeps/unix/sysv/linux/bits/types/struct_shmid64_ds.h
>  create mode 100644 sysdeps/unix/sysv/linux/hppa/struct_kernel_shmid64_ds.h
>  create mode 100644 sysdeps/unix/sysv/linux/i386/struct_kernel_shmid64_ds.h
>  create mode 100644 sysdeps/unix/sysv/linux/include/sys/shm.h
>  create mode 100644 sysdeps/unix/sysv/linux/mips/struct_kernel_shmid64_ds.h
>  create mode 100644 sysdeps/unix/sysv/linux/powerpc/struct_kernel_shmid64_ds.h
>  create mode 100644 sysdeps/unix/sysv/linux/sparc/struct_kernel_shmid64_ds.h
>  create mode 100644 sysdeps/unix/sysv/linux/struct_kernel_shmid64_ds.h
>
> diff --git a/include/sys/shm.h b/include/sys/shm.h
> deleted file mode 100644
> index 1878fcc5be..0000000000
> --- a/include/sys/shm.h
> +++ /dev/null
> @@ -1 +0,0 @@
> -#include <sysvipc/sys/shm.h>
> diff --git a/sysdeps/unix/sysv/linux/bits/types/struct_shmid64_ds.h b/sysdeps/unix/sysv/linux/bits/types/struct_shmid64_ds.h
> new file mode 100644
> index 0000000000..f71e0d28ff
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/bits/types/struct_shmid64_ds.h
> @@ -0,0 +1,37 @@
> +/* Generic implementation of the shared memory struct shmid_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_SHM_H
> +# error "Never include <bits/types/struct_shmid_ds.h> directly; use <sys/shm.h> instead."
> +#endif
> +
> +#if __TIMESIZE == 64
> +# define __shmid64_ds shmid_ds
> +#else
> +struct __shmid64_ds
> +{
> +  struct ipc_perm shm_perm;    /* operation permission struct */
> +  size_t shm_segsz;            /* size of segment in bytes */
> +  __time64_t shm_atime;                /* time of last shmat() */
> +  __time64_t shm_dtime;                /* time of last shmdt() */
> +  __time64_t shm_ctime;                /* time of last change by shmctl() */
> +  __pid_t shm_cpid;            /* pid of creator */
> +  __pid_t shm_lpid;            /* pid of last shmop */
> +  shmatt_t shm_nattch;         /* number of current attaches */
> +};
> +#endif
> diff --git a/sysdeps/unix/sysv/linux/bits/types/struct_shmid_ds.h b/sysdeps/unix/sysv/linux/bits/types/struct_shmid_ds.h
> index 61ed4a08c3..836a7d50e9 100644
> --- a/sysdeps/unix/sysv/linux/bits/types/struct_shmid_ds.h
> +++ b/sysdeps/unix/sysv/linux/bits/types/struct_shmid_ds.h
> @@ -27,11 +27,11 @@ struct shmid_ds
>      size_t shm_segsz;                  /* size of segment in bytes */
>  #if __TIMESIZE == 32
>      __time_t shm_atime;                        /* time of last shmat() */
> -    unsigned long int __glibc_reserved1;
> +    unsigned long int __shm_atime_high;
>      __time_t shm_dtime;                        /* time of last shmdt() */
> -    unsigned long int __glibc_reserved2;
> +    unsigned long int __shm_dtime_high;
>      __time_t shm_ctime;                        /* time of last change by shmctl() */
> -    unsigned long int __glibc_reserved3;
> +    unsigned long int __shm_ctime_high;
>  #else
>      __time_t shm_atime;                        /* time of last shmat() */
>      __time_t shm_dtime;                        /* time of last shmdt() */
> diff --git a/sysdeps/unix/sysv/linux/hppa/bits/types/struct_shmid_ds.h b/sysdeps/unix/sysv/linux/hppa/bits/types/struct_shmid_ds.h
> index 1ebf222eac..1abed1e149 100644
> --- a/sysdeps/unix/sysv/linux/hppa/bits/types/struct_shmid_ds.h
> +++ b/sysdeps/unix/sysv/linux/hppa/bits/types/struct_shmid_ds.h
> @@ -25,11 +25,11 @@ struct shmid_ds
>    {
>      struct ipc_perm shm_perm;          /* operation permission struct */
>  #if __TIMESIZE == 32
> -    unsigned long int __glibc_reserved1;
> +    unsigned long int __shm_atime_high;
>      __time_t shm_atime;                        /* time of last shmat() */
> -    unsigned long int __glibc_reserved2;
> +    unsigned long int __shm_dtime_high;
>      __time_t shm_dtime;                        /* time of last shmdt() */
> -    unsigned long int __glibc_reserved3;
> +    unsigned long int __shm_ctime_high;
>      __time_t shm_ctime;                        /* time of last change by shmctl() */
>      unsigned long int __glibc_reserved4;
>  #else
> diff --git a/sysdeps/unix/sysv/linux/hppa/struct_kernel_shmid64_ds.h b/sysdeps/unix/sysv/linux/hppa/struct_kernel_shmid64_ds.h
> new file mode 100644
> index 0000000000..4d09fc7f62
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/hppa/struct_kernel_shmid64_ds.h
> @@ -0,0 +1,18 @@
> +/* Analogous to kernel struct shmid64_ds used on shmctl.  */
> +struct kernel_shmid64_ds
> +{
> +  struct ipc_perm shm_perm;            /* operation permission struct */
> +  unsigned long int shm_atime_high;
> +  unsigned long int shm_atime;         /* time of last shmat() */
> +  unsigned long int shm_dtime_high;
> +  unsigned long int shm_dtime;         /* time of last shmdt() */
> +  unsigned long int shm_ctime_high;
> +  unsigned long int shm_ctime;         /* time of last change by shmctl() */
> +  unsigned long int __pad;
> +  size_t shm_segsz;                    /* size of segment in bytes */
> +  __pid_t shm_cpid;                    /* pid of creator */
> +  __pid_t shm_lpid;                    /* pid of last shmop */
> +  shmatt_t shm_nattch;         /* number of current attaches */
> +  unsigned long int __unused1;
> +  unsigned long int __unused2;
> +};
> diff --git a/sysdeps/unix/sysv/linux/i386/struct_kernel_shmid64_ds.h b/sysdeps/unix/sysv/linux/i386/struct_kernel_shmid64_ds.h
> new file mode 100644
> index 0000000000..6a0a0d9c71
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/i386/struct_kernel_shmid64_ds.h
> @@ -0,0 +1,17 @@
> +/* Analogous to kernel struct compat_shmid64_ds used on shmctl.  */
> +struct kernel_shmid64_ds
> +{
> +  struct ipc_perm shm_perm;
> +  size_t shm_segsz;
> +  unsigned long int shm_atime;
> +  unsigned long int shm_atime_high;
> +  unsigned long int shm_dtime;
> +  unsigned long int shm_dtime_high;
> +  unsigned long int shm_ctime;
> +  unsigned long int shm_ctime_high;
> +  __pid_t shm_cpid;
> +  __pid_t shm_lpid;
> +  unsigned long int shm_nattch;
> +  unsigned long int __unused4;
> +  unsigned long int __unused5;
> +};
> diff --git a/sysdeps/unix/sysv/linux/include/sys/shm.h b/sysdeps/unix/sysv/linux/include/sys/shm.h
> new file mode 100644
> index 0000000000..530a1cdfc9
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/include/sys/shm.h
> @@ -0,0 +1,17 @@
> +#ifndef _SYS_SHM_H
> +#include <sysvipc/sys/shm.h>
> +
> +#ifndef _ISOMAC
> +
> +# include <bits/types/struct_shmid64_ds.h>
> +
> +# if __TIMESIZE == 64
> +#  define __shmctl64 __shmctl
> +# else
> +extern int __shmctl64 (int shmid, int cmd, struct __shmid64_ds *buf);
> +libc_hidden_proto (__shmctl64);
> +# endif
> +
> +#endif /* _ISOMAC  */
> +
> +#endif /* _SYS_SHM_H  */
> diff --git a/sysdeps/unix/sysv/linux/mips/bits/types/struct_shmid_ds.h b/sysdeps/unix/sysv/linux/mips/bits/types/struct_shmid_ds.h
> index 8e13928980..58090e2fcb 100644
> --- a/sysdeps/unix/sysv/linux/mips/bits/types/struct_shmid_ds.h
> +++ b/sysdeps/unix/sysv/linux/mips/bits/types/struct_shmid_ds.h
> @@ -38,9 +38,9 @@ struct shmid_ds
>      __pid_t shm_lpid;                  /* pid of last shmop */
>      shmatt_t shm_nattch;               /* number of current attaches */
>  #if __TIMESIZE == 32
> -    unsigned short int __glibc_reserved1;
> -    unsigned short int __glibc_reserved2;
> -    unsigned short int __glibc_reserved3;
> +    unsigned short int __shm_atime_high;
> +    unsigned short int __shm_dtime_high;
> +    unsigned short int __shm_ctime_high;
>      unsigned short int __glibc_reserved4;
>  #else
>      __syscall_ulong_t __glibc_reserved5;
> diff --git a/sysdeps/unix/sysv/linux/mips/struct_kernel_shmid64_ds.h b/sysdeps/unix/sysv/linux/mips/struct_kernel_shmid64_ds.h
> new file mode 100644
> index 0000000000..a4baa5614f
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/mips/struct_kernel_shmid64_ds.h
> @@ -0,0 +1,27 @@
> +/* Analogous to kernel struct shmid64_ds used on shmctl.  */
> +struct kernel_shmid64_ds
> +{
> +  struct ipc_perm shm_perm;
> +  size_t shm_segsz;
> +#if __TIMESIZE == 64
> +  long int shm_atime;
> +  long int shm_dtime;
> +  long int shm_ctime;
> +#else
> +  unsigned long int shm_atime;
> +  unsigned long int shm_dtime;
> +  unsigned long int shm_ctime;
> +#endif
> +  __pid_t shm_cpid;
> +  __pid_t shm_lpid;
> +  unsigned long int shm_nattch;
> +#if __TIMESIZE == 64
> +  unsigned long int __unused1;
> +  unsigned long int __unused2;
> +#else
> +  unsigned short int shm_atime_high;
> +  unsigned short int shm_dtime_high;
> +  unsigned short int shm_ctime_high;
> +  unsigned short int __ununsed1;
> +#endif
> +};
> diff --git a/sysdeps/unix/sysv/linux/powerpc/bits/types/struct_shmid_ds.h b/sysdeps/unix/sysv/linux/powerpc/bits/types/struct_shmid_ds.h
> index b0816fb16a..39b3e5fd3e 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/bits/types/struct_shmid_ds.h
> +++ b/sysdeps/unix/sysv/linux/powerpc/bits/types/struct_shmid_ds.h
> @@ -25,11 +25,11 @@ struct shmid_ds
>    {
>      struct ipc_perm shm_perm;          /* operation permission struct */
>  #if __TIMESIZE == 32
> -    unsigned long int __glibc_reserved1;
> +    unsigned long int __shm_atime_high;
>      __time_t shm_atime;                        /* time of last shmat() */
> -    unsigned long int __glibc_reserved2;
> +    unsigned long int __shm_dtime_high;
>      __time_t shm_dtime;                        /* time of last shmdt() */
> -    unsigned long int __glibc_reserved3;
> +    unsigned long int __shm_ctime_high;
>      __time_t shm_ctime;                        /* time of last change by shmctl() */
>      unsigned long int __glibc_reserved4;
>  #else
> diff --git a/sysdeps/unix/sysv/linux/powerpc/struct_kernel_shmid64_ds.h b/sysdeps/unix/sysv/linux/powerpc/struct_kernel_shmid64_ds.h
> new file mode 100644
> index 0000000000..ae3f3987ac
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/powerpc/struct_kernel_shmid64_ds.h
> @@ -0,0 +1,18 @@
> +/* Analogous to kernel struct shmid64_ds used on shmctl.  */
> +struct kernel_shmid64_ds
> +{
> +  struct ipc_perm shm_perm;
> +  unsigned long int shm_atime_high;
> +  unsigned long int shm_atime;
> +  unsigned long int shm_dtime_high;
> +  unsigned long int shm_dtime;
> +  unsigned long int shm_ctime_high;
> +  unsigned long int shm_ctime;
> +  unsigned long int __ununsed1;
> +  size_t shm_segsz;
> +  __pid_t shm_cpid;
> +  __pid_t shm_lpid;
> +  unsigned long int shm_nattch;
> +  unsigned long int __unused2;
> +  unsigned long int __unused3;
> +};
> diff --git a/sysdeps/unix/sysv/linux/shmctl.c b/sysdeps/unix/sysv/linux/shmctl.c
> index f41b359b8b..aaf3946054 100644
> --- a/sysdeps/unix/sysv/linux/shmctl.c
> +++ b/sysdeps/unix/sysv/linux/shmctl.c
> @@ -24,16 +24,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 shmid_ds){0}.shm_perm.mode)
> +               == sizeof (mode_t),
> +               "sizeof (shmid_ds.shm_perm.mode) != sizeof (mode_t)");
> +
> +#if __IPC_TIME64 == 0
> +typedef struct shmid_ds shmctl_arg_t;
> +#else
> +# include <struct_kernel_shmid64_ds.h>
> +
> +static void
> +shmid64_to_kshmid64 (const struct __shmid64_ds *shmid64,
> +                    struct kernel_shmid64_ds *kshmid)
> +{
> +  kshmid->shm_perm       = shmid64->shm_perm;
> +  kshmid->shm_segsz      = shmid64->shm_segsz;
> +  kshmid->shm_atime      = shmid64->shm_atime;
> +  kshmid->shm_atime_high = shmid64->shm_atime >> 32;
> +  kshmid->shm_dtime      = shmid64->shm_dtime;
> +  kshmid->shm_dtime_high = shmid64->shm_dtime >> 32;
> +  kshmid->shm_ctime      = shmid64->shm_ctime;
> +  kshmid->shm_ctime_high = shmid64->shm_ctime >> 32;
> +  kshmid->shm_cpid       = shmid64->shm_cpid;
> +  kshmid->shm_lpid       = shmid64->shm_lpid;
> +  kshmid->shm_nattch     = shmid64->shm_nattch;
> +}
> +
> +static void
> +kshmid64_to_shmid64 (const struct kernel_shmid64_ds *kshmid,
> +                    struct __shmid64_ds *shmid64)
> +{
> +  shmid64->shm_perm   = kshmid->shm_perm;
> +  shmid64->shm_segsz  = kshmid->shm_segsz;
> +  shmid64->shm_atime  = kshmid->shm_atime
> +                       | ((__time64_t) kshmid->shm_atime_high << 32);
> +  shmid64->shm_dtime  = kshmid->shm_dtime
> +                       | ((__time64_t) kshmid->shm_dtime_high << 32);
> +  shmid64->shm_ctime     = kshmid->shm_ctime
> +                       | ((__time64_t) kshmid->shm_ctime_high << 32);
> +  shmid64->shm_cpid   = kshmid->shm_cpid;
> +  shmid64->shm_lpid   = kshmid->shm_lpid;
> +  shmid64->shm_nattch = kshmid->shm_nattch;
> +}
> +
> +typedef struct kernel_shmid64_ds shmctl_arg_t;
>  #endif
>
>  static int
> -shmctl_syscall (int shmid, int cmd, struct shmid_ds *buf)
> +shmctl_syscall (int shmid, int cmd, shmctl_arg_t *buf)
>  {
>  #ifdef __ASSUME_DIRECT_SYSVIPC_SYSCALLS
>    return INLINE_SYSCALL_CALL (shmctl, shmid, cmd | __IPC_64, buf);
> @@ -45,46 +84,119 @@ shmctl_syscall (int shmid, int cmd, struct shmid_ds *buf)
>
>  /* Provide operations to control over shared memory segments.  */
>  int
> -__new_shmctl (int shmid, int cmd, struct shmid_ds *buf)
> +__shmctl64 (int shmid, int cmd, struct __shmid64_ds *buf)
>  {
> -  /* POSIX states ipc_perm mode should have type of mode_t.  */
> -  _Static_assert (sizeof ((struct shmid_ds){0}.shm_perm.mode)
> -                 == sizeof (mode_t),
> -                 "sizeof (msqid_ds.msg_perm.mode) != sizeof (mode_t)");
> -
> -#ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
> -  struct shmid_ds tmpds;
> -  if (cmd == IPC_SET)
> +#if __IPC_TIME64
> +  struct kernel_shmid64_ds kshmid, *arg = NULL;
> +  if (buf != NULL)
>      {
> -      tmpds = *buf;
> -      tmpds.shm_perm.mode *= 0x10000U;
> -      buf = &tmpds;
> +      shmid64_to_kshmid64 (buf, &kshmid);
> +      arg = &kshmid;
>      }
> +# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
> +  if (cmd == IPC_SET)
> +      arg->shm_perm.mode *= 0x10000U;
> +# endif
> +#else
> +  shmctl_arg_t *arg = buf;
>  #endif
>
> -  int ret = shmctl_syscall (shmid, cmd, buf);
> +  int ret = shmctl_syscall (shmid, cmd, arg);
> +  if (ret < 0)
> +    return ret;
>
> -  if (ret >= 0)
> +  switch (cmd)
>      {
> -      switch (cmd)
> -       {
> -        case IPC_STAT:
> -        case SHM_STAT:
> -        case SHM_STAT_ANY:
> +      case IPC_STAT:
> +      case SHM_STAT:
> +      case SHM_STAT_ANY:
>  #ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
> -          buf->shm_perm.mode >>= 16;
> +        arg->shm_perm.mode >>= 16;
>  #else
> -         /* Old Linux kernel versions might not clear the mode padding.  */
> -         if (sizeof ((struct shmid_ds){0}.shm_perm.mode)
> -             != sizeof (__kernel_mode_t))
> -           buf->shm_perm.mode &= 0xFFFF;
> +      /* Old Linux kernel versions might not clear the mode padding.  */
> +      if (sizeof ((struct shmid_ds){0}.shm_perm.mode)
> +         != sizeof (__kernel_mode_t))
> +       arg->shm_perm.mode &= 0xFFFF;
> +#endif
> +
> +#if __IPC_TIME64
> +      kshmid64_to_shmid64 (arg, buf);
>  #endif
> -       }
>      }
>
>    return ret;
>  }
> -versioned_symbol (libc, __new_shmctl, shmctl, DEFAULT_VERSION);
> +#if __TIMESIZE != 64
> +libc_hidden_def (__shmctl64)
> +
> +static void
> +shmid_to_shmid64 (struct __shmid64_ds *shm64, const struct shmid_ds *shm)
> +{
> +  shm64->shm_perm   = shm->shm_perm;
> +  shm64->shm_segsz  = shm->shm_segsz;
> +  shm64->shm_atime  = shm->shm_atime
> +                       | ((__time64_t) shm->__shm_atime_high << 32);
> +  shm64->shm_dtime  = shm->shm_dtime
> +                       | ((__time64_t) shm->__shm_dtime_high << 32);
> +  shm64->shm_ctime     = shm->shm_ctime
> +                       | ((__time64_t) shm->__shm_ctime_high << 32);
> +  shm64->shm_cpid   = shm->shm_cpid;
> +  shm64->shm_lpid   = shm->shm_lpid;
> +  shm64->shm_nattch = shm->shm_nattch;
> +}
> +
> +static void
> +shmid64_to_shmid (struct shmid_ds *shm, const struct __shmid64_ds *shm64)
> +{
> +  shm->shm_perm         = shm64->shm_perm;
> +  shm->shm_segsz        = shm64->shm_segsz;
> +  shm->shm_atime        = shm64->shm_atime;
> +  shm->__shm_atime_high = 0;
> +  shm->shm_dtime        = shm64->shm_dtime;
> +  shm->__shm_dtime_high = 0;
> +  shm->shm_ctime        = shm64->shm_ctime;
> +  shm->__shm_ctime_high = 0;
> +  shm->shm_cpid         = shm64->shm_cpid;
> +  shm->shm_lpid         = shm64->shm_lpid;
> +  shm->shm_nattch       = shm64->shm_nattch;
> +}
> +
> +int
> +__shmctl (int shmid, int cmd, struct shmid_ds *buf)
> +{
> +  struct __shmid64_ds shmid64, *buf64 = NULL;
> +  if (buf != NULL)
> +    {
> +      shmid_to_shmid64 (&shmid64, buf);
> +      buf64 = &shmid64;
> +    }
> +
> +  int ret = __shmctl64 (shmid, cmd, buf64);
> +  if (ret < 0)
> +    return ret;
> +
> +  switch (cmd)
> +    {
> +      case IPC_STAT:
> +      case SHM_STAT:
> +      case SHM_STAT_ANY:
> +       if (buf64 != NULL)
> +         shmid64_to_shmid (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, __shmctl, shmctl, DEFAULT_VERSION);
>
>  #if defined __ASSUME_SYSVIPC_BROKEN_MODE_T \
>      && SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_31)
> @@ -92,7 +204,7 @@ int
>  attribute_compat_text_section
>  __shmctl_mode16 (int shmid, int cmd, struct shmid_ds *buf)
>  {
> -  return shmctl_syscall (shmid, cmd, buf);
> +  return shmctl_syscall (shmid, cmd, (shmctl_arg_t *) buf);
>  }
>  compat_symbol (libc, __shmctl_mode16, shmctl, GLIBC_2_2);
>  #endif
> diff --git a/sysdeps/unix/sysv/linux/sparc/bits/types/struct_shmid_ds.h b/sysdeps/unix/sysv/linux/sparc/bits/types/struct_shmid_ds.h
> index d5fb61d374..cab3a2686f 100644
> --- a/sysdeps/unix/sysv/linux/sparc/bits/types/struct_shmid_ds.h
> +++ b/sysdeps/unix/sysv/linux/sparc/bits/types/struct_shmid_ds.h
> @@ -25,11 +25,11 @@ struct shmid_ds
>    {
>      struct ipc_perm shm_perm;          /* operation permission struct */
>  #if __TIMESIZE == 32
> -    unsigned long int __glibc_reserved1;
> +    unsigned long int __shm_atime_high;
>      __time_t shm_atime;                        /* time of last shmat() */
> -    unsigned long int __glibc_reserved2;
> +    unsigned long int __shm_dtime_high;
>      __time_t shm_dtime;                        /* time of last shmdt() */
> -    unsigned long int __glibc_reserved3;
> +    unsigned long int __shm_ctime_high;
>      __time_t shm_ctime;                        /* time of last change by shmctl() */
>  #else
>      __time_t shm_atime;                        /* time of last shmat() */
> diff --git a/sysdeps/unix/sysv/linux/sparc/struct_kernel_shmid64_ds.h b/sysdeps/unix/sysv/linux/sparc/struct_kernel_shmid64_ds.h
> new file mode 100644
> index 0000000000..333a410641
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/sparc/struct_kernel_shmid64_ds.h
> @@ -0,0 +1,17 @@
> +/* Analogous to kernel struct shmid64_ds used on shmctl.  */
> +struct kernel_shmid64_ds
> +{
> +  struct ipc_perm shm_perm;
> +  unsigned long int shm_atime_high;
> +  unsigned long int shm_atime;
> +  unsigned long int shm_dtime_high;
> +  unsigned long int shm_dtime;
> +  unsigned long int shm_ctime_high;
> +  unsigned long int shm_ctime;
> +  size_t shm_segsz;
> +  __pid_t shm_cpid;
> +  __pid_t shm_lpid;
> +  unsigned long int shm_nattch;
> +  unsigned long int __unused1;
> +  unsigned long int __unused2;
> +};
> diff --git a/sysdeps/unix/sysv/linux/struct_kernel_shmid64_ds.h b/sysdeps/unix/sysv/linux/struct_kernel_shmid64_ds.h
> new file mode 100644
> index 0000000000..6fe67afccb
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/struct_kernel_shmid64_ds.h
> @@ -0,0 +1,17 @@
> +/* Analogous to kernel struct shmid64_ds used on shmctl.  */
> +struct kernel_shmid64_ds
> +{
> +  struct ipc_perm shm_perm;
> +  size_t shm_segsz;
> +  unsigned long int shm_atime;
> +  unsigned long int shm_atime_high;
> +  unsigned long int shm_dtime;
> +  unsigned long int shm_dtime_high;
> +  unsigned long int shm_ctime;
> +  unsigned long int shm_ctime_high;
> +  __pid_t shm_cpid;
> +  __pid_t shm_lpid;
> +  unsigned long int shm_nattch;
> +  unsigned long int __unused1;
> +  unsigned long int __unused2;
> +};
> --
> 2.25.1
>
Joseph Myers July 10, 2020, 5:13 p.m. UTC | #3
On Wed, 8 Jul 2020, Adhemerval Zanella via Libc-alpha wrote:

> This is a small updated version that basically does:
> 
>   git mv include/sys/shm.h sysdeps/unix/sysv/linux/include/sys/shm.h
> 
> It basically avoids a build failure on Hurd (since it does not provide
> struct_shmid64_ds.h).

The build failure for Hurd is still present if there are no previously 
installed headers (so "compilers" build with build-many-glibcs.py).

https://sourceware.org/pipermail/libc-testresults/2020q3/006455.html

In file included from programs/locarchive.c:40:
../include/sys/shm.h:1:15: fatal error: sys/shm.h: No such file or 
directory
    1 | #include_next <sys/shm.h>
      |               ^~~~~~~~~~~

It's necessary to include the sysvipc/ path explicitly from include/, 
using #include_next won't work (or if it appears to work, will include a 
header from a previously installed glibc, not the one from the source 
tree).  I think you should have bits/types/struct_shmid64_ds.h for Hurd, 
even if initially nothing actually uses that type for Hurd.
Adhemerval Zanella July 10, 2020, 5:49 p.m. UTC | #4
On 10/07/2020 14:13, Joseph Myers wrote:
> On Wed, 8 Jul 2020, Adhemerval Zanella via Libc-alpha wrote:
> 
>> This is a small updated version that basically does:
>>
>>   git mv include/sys/shm.h sysdeps/unix/sysv/linux/include/sys/shm.h
>>
>> It basically avoids a build failure on Hurd (since it does not provide
>> struct_shmid64_ds.h).
> 
> The build failure for Hurd is still present if there are no previously 
> installed headers (so "compilers" build with build-many-glibcs.py).
> 
> https://sourceware.org/pipermail/libc-testresults/2020q3/006455.html
> 
> In file included from programs/locarchive.c:40:
> ../include/sys/shm.h:1:15: fatal error: sys/shm.h: No such file or 
> directory
>     1 | #include_next <sys/shm.h>
>       |               ^~~~~~~~~~~
> 
> It's necessary to include the sysvipc/ path explicitly from include/, 
> using #include_next won't work (or if it appears to work, will include a 
> header from a previously installed glibc, not the one from the source 
> tree).  I think you should have bits/types/struct_shmid64_ds.h for Hurd, 
> even if initially nothing actually uses that type for Hurd.
> 

Would be better to just add a Hurd specific sys/{msg,sem,shm.h}.h that
includes sysvipc/sys/{msg,sem,shm}.h? I has the advantage of not tying any
possible sysvipc support hurd might add to an specific internal ABI (such
as to provide the time64 support) and make the Linux specific localized in
Linux sysdeps folders.

Something like:

diff --git a/sysdeps/hurd/include/sys/msg.h b/sysdeps/hurd/include/sys/msg.h
new file mode 100644
index 0000000000..0f8026dda1
--- /dev/null
+++ b/sysdeps/hurd/include/sys/msg.h
@@ -0,0 +1 @@
+#include <sysvipc/sys/msg.h>
diff --git a/sysdeps/hurd/include/sys/sem.h b/sysdeps/hurd/include/sys/sem.h
new file mode 100644
index 0000000000..b0fb201bd0
--- /dev/null
+++ b/sysdeps/hurd/include/sys/sem.h
@@ -0,0 +1 @@
+#include <sysvipc/sys/sem.h>
diff --git a/sysdeps/hurd/include/sys/shm.h b/sysdeps/hurd/include/sys/shm.h
new file mode 100644
index 0000000000..1878fcc5be
--- /dev/null
+++ b/sysdeps/hurd/include/sys/shm.h
@@ -0,0 +1 @@
+#include <sysvipc/sys/shm.h>
Joseph Myers July 10, 2020, 5:57 p.m. UTC | #5
On Fri, 10 Jul 2020, Adhemerval Zanella wrote:

> Would be better to just add a Hurd specific sys/{msg,sem,shm.h}.h that
> includes sysvipc/sys/{msg,sem,shm}.h? I has the advantage of not tying any

I expect that would work as well.
Adhemerval Zanella July 10, 2020, 5:59 p.m. UTC | #6
On 10/07/2020 14:57, Joseph Myers wrote:
> On Fri, 10 Jul 2020, Adhemerval Zanella wrote:
> 
>> Would be better to just add a Hurd specific sys/{msg,sem,shm.h}.h that
>> includes sysvipc/sys/{msg,sem,shm}.h? I has the advantage of not tying any
> 
> I expect that would work as well.
> 

Ack, I will fire up a build-many-glibcs.py hurd build and send a patch.
diff mbox series

Patch

diff --git a/include/sys/shm.h b/include/sys/shm.h
deleted file mode 100644
index 1878fcc5be..0000000000
--- a/include/sys/shm.h
+++ /dev/null
@@ -1 +0,0 @@ 
-#include <sysvipc/sys/shm.h>
diff --git a/sysdeps/unix/sysv/linux/bits/types/struct_shmid64_ds.h b/sysdeps/unix/sysv/linux/bits/types/struct_shmid64_ds.h
new file mode 100644
index 0000000000..f71e0d28ff
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/bits/types/struct_shmid64_ds.h
@@ -0,0 +1,37 @@ 
+/* Generic implementation of the shared memory struct shmid_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_SHM_H
+# error "Never include <bits/types/struct_shmid_ds.h> directly; use <sys/shm.h> instead."
+#endif
+
+#if __TIMESIZE == 64
+# define __shmid64_ds shmid_ds
+#else
+struct __shmid64_ds
+{
+  struct ipc_perm shm_perm;	/* operation permission struct */
+  size_t shm_segsz;		/* size of segment in bytes */
+  __time64_t shm_atime;		/* time of last shmat() */
+  __time64_t shm_dtime;		/* time of last shmdt() */
+  __time64_t shm_ctime;		/* time of last change by shmctl() */
+  __pid_t shm_cpid;		/* pid of creator */
+  __pid_t shm_lpid;		/* pid of last shmop */
+  shmatt_t shm_nattch;		/* number of current attaches */
+};
+#endif
diff --git a/sysdeps/unix/sysv/linux/bits/types/struct_shmid_ds.h b/sysdeps/unix/sysv/linux/bits/types/struct_shmid_ds.h
index 61ed4a08c3..836a7d50e9 100644
--- a/sysdeps/unix/sysv/linux/bits/types/struct_shmid_ds.h
+++ b/sysdeps/unix/sysv/linux/bits/types/struct_shmid_ds.h
@@ -27,11 +27,11 @@  struct shmid_ds
     size_t shm_segsz;			/* size of segment in bytes */
 #if __TIMESIZE == 32
     __time_t shm_atime;			/* time of last shmat() */
-    unsigned long int __glibc_reserved1;
+    unsigned long int __shm_atime_high;
     __time_t shm_dtime;			/* time of last shmdt() */
-    unsigned long int __glibc_reserved2;
+    unsigned long int __shm_dtime_high;
     __time_t shm_ctime;			/* time of last change by shmctl() */
-    unsigned long int __glibc_reserved3;
+    unsigned long int __shm_ctime_high;
 #else
     __time_t shm_atime;			/* time of last shmat() */
     __time_t shm_dtime;			/* time of last shmdt() */
diff --git a/sysdeps/unix/sysv/linux/hppa/bits/types/struct_shmid_ds.h b/sysdeps/unix/sysv/linux/hppa/bits/types/struct_shmid_ds.h
index 1ebf222eac..1abed1e149 100644
--- a/sysdeps/unix/sysv/linux/hppa/bits/types/struct_shmid_ds.h
+++ b/sysdeps/unix/sysv/linux/hppa/bits/types/struct_shmid_ds.h
@@ -25,11 +25,11 @@  struct shmid_ds
   {
     struct ipc_perm shm_perm;		/* operation permission struct */
 #if __TIMESIZE == 32
-    unsigned long int __glibc_reserved1;
+    unsigned long int __shm_atime_high;
     __time_t shm_atime;			/* time of last shmat() */
-    unsigned long int __glibc_reserved2;
+    unsigned long int __shm_dtime_high;
     __time_t shm_dtime;			/* time of last shmdt() */
-    unsigned long int __glibc_reserved3;
+    unsigned long int __shm_ctime_high;
     __time_t shm_ctime;			/* time of last change by shmctl() */
     unsigned long int __glibc_reserved4;
 #else
diff --git a/sysdeps/unix/sysv/linux/hppa/struct_kernel_shmid64_ds.h b/sysdeps/unix/sysv/linux/hppa/struct_kernel_shmid64_ds.h
new file mode 100644
index 0000000000..4d09fc7f62
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/hppa/struct_kernel_shmid64_ds.h
@@ -0,0 +1,18 @@ 
+/* Analogous to kernel struct shmid64_ds used on shmctl.  */
+struct kernel_shmid64_ds
+{
+  struct ipc_perm shm_perm;		/* operation permission struct */
+  unsigned long int shm_atime_high;
+  unsigned long int shm_atime;		/* time of last shmat() */
+  unsigned long int shm_dtime_high;
+  unsigned long int shm_dtime;		/* time of last shmdt() */
+  unsigned long int shm_ctime_high;
+  unsigned long int shm_ctime;		/* time of last change by shmctl() */
+  unsigned long int __pad;
+  size_t shm_segsz;			/* size of segment in bytes */
+  __pid_t shm_cpid;			/* pid of creator */
+  __pid_t shm_lpid;			/* pid of last shmop */
+  shmatt_t shm_nattch;		/* number of current attaches */
+  unsigned long int __unused1;
+  unsigned long int __unused2;
+};
diff --git a/sysdeps/unix/sysv/linux/i386/struct_kernel_shmid64_ds.h b/sysdeps/unix/sysv/linux/i386/struct_kernel_shmid64_ds.h
new file mode 100644
index 0000000000..6a0a0d9c71
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/i386/struct_kernel_shmid64_ds.h
@@ -0,0 +1,17 @@ 
+/* Analogous to kernel struct compat_shmid64_ds used on shmctl.  */
+struct kernel_shmid64_ds
+{
+  struct ipc_perm shm_perm;
+  size_t shm_segsz;
+  unsigned long int shm_atime;
+  unsigned long int shm_atime_high;
+  unsigned long int shm_dtime;
+  unsigned long int shm_dtime_high;
+  unsigned long int shm_ctime;
+  unsigned long int shm_ctime_high;
+  __pid_t shm_cpid;
+  __pid_t shm_lpid;
+  unsigned long int shm_nattch;
+  unsigned long int __unused4;
+  unsigned long int __unused5;
+};
diff --git a/sysdeps/unix/sysv/linux/include/sys/shm.h b/sysdeps/unix/sysv/linux/include/sys/shm.h
new file mode 100644
index 0000000000..530a1cdfc9
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/include/sys/shm.h
@@ -0,0 +1,17 @@ 
+#ifndef _SYS_SHM_H
+#include <sysvipc/sys/shm.h>
+
+#ifndef _ISOMAC
+
+# include <bits/types/struct_shmid64_ds.h>
+
+# if __TIMESIZE == 64
+#  define __shmctl64 __shmctl
+# else
+extern int __shmctl64 (int shmid, int cmd, struct __shmid64_ds *buf);
+libc_hidden_proto (__shmctl64);
+# endif
+
+#endif /* _ISOMAC  */
+
+#endif /* _SYS_SHM_H  */
diff --git a/sysdeps/unix/sysv/linux/mips/bits/types/struct_shmid_ds.h b/sysdeps/unix/sysv/linux/mips/bits/types/struct_shmid_ds.h
index 8e13928980..58090e2fcb 100644
--- a/sysdeps/unix/sysv/linux/mips/bits/types/struct_shmid_ds.h
+++ b/sysdeps/unix/sysv/linux/mips/bits/types/struct_shmid_ds.h
@@ -38,9 +38,9 @@  struct shmid_ds
     __pid_t shm_lpid;			/* pid of last shmop */
     shmatt_t shm_nattch;		/* number of current attaches */
 #if __TIMESIZE == 32
-    unsigned short int __glibc_reserved1;
-    unsigned short int __glibc_reserved2;
-    unsigned short int __glibc_reserved3;
+    unsigned short int __shm_atime_high;
+    unsigned short int __shm_dtime_high;
+    unsigned short int __shm_ctime_high;
     unsigned short int __glibc_reserved4;
 #else
     __syscall_ulong_t __glibc_reserved5;
diff --git a/sysdeps/unix/sysv/linux/mips/struct_kernel_shmid64_ds.h b/sysdeps/unix/sysv/linux/mips/struct_kernel_shmid64_ds.h
new file mode 100644
index 0000000000..a4baa5614f
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/mips/struct_kernel_shmid64_ds.h
@@ -0,0 +1,27 @@ 
+/* Analogous to kernel struct shmid64_ds used on shmctl.  */
+struct kernel_shmid64_ds
+{
+  struct ipc_perm shm_perm;
+  size_t shm_segsz;
+#if __TIMESIZE == 64
+  long int shm_atime;
+  long int shm_dtime;
+  long int shm_ctime;
+#else
+  unsigned long int shm_atime;
+  unsigned long int shm_dtime;
+  unsigned long int shm_ctime;
+#endif
+  __pid_t shm_cpid;
+  __pid_t shm_lpid;
+  unsigned long int shm_nattch;
+#if __TIMESIZE == 64
+  unsigned long int __unused1;
+  unsigned long int __unused2;
+#else
+  unsigned short int shm_atime_high;
+  unsigned short int shm_dtime_high;
+  unsigned short int shm_ctime_high;
+  unsigned short int __ununsed1;
+#endif
+};
diff --git a/sysdeps/unix/sysv/linux/powerpc/bits/types/struct_shmid_ds.h b/sysdeps/unix/sysv/linux/powerpc/bits/types/struct_shmid_ds.h
index b0816fb16a..39b3e5fd3e 100644
--- a/sysdeps/unix/sysv/linux/powerpc/bits/types/struct_shmid_ds.h
+++ b/sysdeps/unix/sysv/linux/powerpc/bits/types/struct_shmid_ds.h
@@ -25,11 +25,11 @@  struct shmid_ds
   {
     struct ipc_perm shm_perm;		/* operation permission struct */
 #if __TIMESIZE == 32
-    unsigned long int __glibc_reserved1;
+    unsigned long int __shm_atime_high;
     __time_t shm_atime;			/* time of last shmat() */
-    unsigned long int __glibc_reserved2;
+    unsigned long int __shm_dtime_high;
     __time_t shm_dtime;			/* time of last shmdt() */
-    unsigned long int __glibc_reserved3;
+    unsigned long int __shm_ctime_high;
     __time_t shm_ctime;			/* time of last change by shmctl() */
     unsigned long int __glibc_reserved4;
 #else
diff --git a/sysdeps/unix/sysv/linux/powerpc/struct_kernel_shmid64_ds.h b/sysdeps/unix/sysv/linux/powerpc/struct_kernel_shmid64_ds.h
new file mode 100644
index 0000000000..ae3f3987ac
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/powerpc/struct_kernel_shmid64_ds.h
@@ -0,0 +1,18 @@ 
+/* Analogous to kernel struct shmid64_ds used on shmctl.  */
+struct kernel_shmid64_ds
+{
+  struct ipc_perm shm_perm;
+  unsigned long int shm_atime_high;
+  unsigned long int shm_atime;
+  unsigned long int shm_dtime_high;
+  unsigned long int shm_dtime;
+  unsigned long int shm_ctime_high;
+  unsigned long int shm_ctime;
+  unsigned long int __ununsed1;
+  size_t shm_segsz;
+  __pid_t shm_cpid;
+  __pid_t shm_lpid;
+  unsigned long int shm_nattch;
+  unsigned long int __unused2;
+  unsigned long int __unused3;
+};
diff --git a/sysdeps/unix/sysv/linux/shmctl.c b/sysdeps/unix/sysv/linux/shmctl.c
index f41b359b8b..aaf3946054 100644
--- a/sysdeps/unix/sysv/linux/shmctl.c
+++ b/sysdeps/unix/sysv/linux/shmctl.c
@@ -24,16 +24,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 shmid_ds){0}.shm_perm.mode)
+		== sizeof (mode_t),
+		"sizeof (shmid_ds.shm_perm.mode) != sizeof (mode_t)");
+
+#if __IPC_TIME64 == 0
+typedef struct shmid_ds shmctl_arg_t;
+#else
+# include <struct_kernel_shmid64_ds.h>
+
+static void
+shmid64_to_kshmid64 (const struct __shmid64_ds *shmid64,
+		     struct kernel_shmid64_ds *kshmid)
+{
+  kshmid->shm_perm       = shmid64->shm_perm;
+  kshmid->shm_segsz      = shmid64->shm_segsz;
+  kshmid->shm_atime      = shmid64->shm_atime;
+  kshmid->shm_atime_high = shmid64->shm_atime >> 32;
+  kshmid->shm_dtime      = shmid64->shm_dtime;
+  kshmid->shm_dtime_high = shmid64->shm_dtime >> 32;
+  kshmid->shm_ctime      = shmid64->shm_ctime;
+  kshmid->shm_ctime_high = shmid64->shm_ctime >> 32;
+  kshmid->shm_cpid       = shmid64->shm_cpid;
+  kshmid->shm_lpid       = shmid64->shm_lpid;
+  kshmid->shm_nattch     = shmid64->shm_nattch;
+}
+
+static void
+kshmid64_to_shmid64 (const struct kernel_shmid64_ds *kshmid,
+		     struct __shmid64_ds *shmid64)
+{
+  shmid64->shm_perm   = kshmid->shm_perm;
+  shmid64->shm_segsz  = kshmid->shm_segsz;
+  shmid64->shm_atime  = kshmid->shm_atime
+		        | ((__time64_t) kshmid->shm_atime_high << 32);
+  shmid64->shm_dtime  = kshmid->shm_dtime
+		        | ((__time64_t) kshmid->shm_dtime_high << 32);
+  shmid64->shm_ctime     = kshmid->shm_ctime
+		        | ((__time64_t) kshmid->shm_ctime_high << 32);
+  shmid64->shm_cpid   = kshmid->shm_cpid;
+  shmid64->shm_lpid   = kshmid->shm_lpid;
+  shmid64->shm_nattch = kshmid->shm_nattch;
+}
+
+typedef struct kernel_shmid64_ds shmctl_arg_t;
 #endif
 
 static int
-shmctl_syscall (int shmid, int cmd, struct shmid_ds *buf)
+shmctl_syscall (int shmid, int cmd, shmctl_arg_t *buf)
 {
 #ifdef __ASSUME_DIRECT_SYSVIPC_SYSCALLS
   return INLINE_SYSCALL_CALL (shmctl, shmid, cmd | __IPC_64, buf);
@@ -45,46 +84,119 @@  shmctl_syscall (int shmid, int cmd, struct shmid_ds *buf)
 
 /* Provide operations to control over shared memory segments.  */
 int
-__new_shmctl (int shmid, int cmd, struct shmid_ds *buf)
+__shmctl64 (int shmid, int cmd, struct __shmid64_ds *buf)
 {
-  /* POSIX states ipc_perm mode should have type of mode_t.  */
-  _Static_assert (sizeof ((struct shmid_ds){0}.shm_perm.mode)
-		  == sizeof (mode_t),
-		  "sizeof (msqid_ds.msg_perm.mode) != sizeof (mode_t)");
-
-#ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
-  struct shmid_ds tmpds;
-  if (cmd == IPC_SET)
+#if __IPC_TIME64
+  struct kernel_shmid64_ds kshmid, *arg = NULL;
+  if (buf != NULL)
     {
-      tmpds = *buf;
-      tmpds.shm_perm.mode *= 0x10000U;
-      buf = &tmpds;
+      shmid64_to_kshmid64 (buf, &kshmid);
+      arg = &kshmid;
     }
+# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
+  if (cmd == IPC_SET)
+      arg->shm_perm.mode *= 0x10000U;
+# endif
+#else
+  shmctl_arg_t *arg = buf;
 #endif
 
-  int ret = shmctl_syscall (shmid, cmd, buf);
+  int ret = shmctl_syscall (shmid, cmd, arg);
+  if (ret < 0)
+    return ret;
 
-  if (ret >= 0)
+  switch (cmd)
     {
-      switch (cmd)
-	{
-        case IPC_STAT:
-        case SHM_STAT:
-        case SHM_STAT_ANY:
+      case IPC_STAT:
+      case SHM_STAT:
+      case SHM_STAT_ANY:
 #ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
-          buf->shm_perm.mode >>= 16;
+        arg->shm_perm.mode >>= 16;
 #else
-	  /* Old Linux kernel versions might not clear the mode padding.  */
-	  if (sizeof ((struct shmid_ds){0}.shm_perm.mode)
-	      != sizeof (__kernel_mode_t))
-	    buf->shm_perm.mode &= 0xFFFF;
+      /* Old Linux kernel versions might not clear the mode padding.  */
+      if (sizeof ((struct shmid_ds){0}.shm_perm.mode)
+	  != sizeof (__kernel_mode_t))
+	arg->shm_perm.mode &= 0xFFFF;
+#endif
+
+#if __IPC_TIME64
+      kshmid64_to_shmid64 (arg, buf);
 #endif
-	}
     }
 
   return ret;
 }
-versioned_symbol (libc, __new_shmctl, shmctl, DEFAULT_VERSION);
+#if __TIMESIZE != 64
+libc_hidden_def (__shmctl64)
+
+static void
+shmid_to_shmid64 (struct __shmid64_ds *shm64, const struct shmid_ds *shm)
+{
+  shm64->shm_perm   = shm->shm_perm;
+  shm64->shm_segsz  = shm->shm_segsz;
+  shm64->shm_atime  = shm->shm_atime
+		        | ((__time64_t) shm->__shm_atime_high << 32);
+  shm64->shm_dtime  = shm->shm_dtime
+		        | ((__time64_t) shm->__shm_dtime_high << 32);
+  shm64->shm_ctime     = shm->shm_ctime
+		        | ((__time64_t) shm->__shm_ctime_high << 32);
+  shm64->shm_cpid   = shm->shm_cpid;
+  shm64->shm_lpid   = shm->shm_lpid;
+  shm64->shm_nattch = shm->shm_nattch;
+}
+
+static void
+shmid64_to_shmid (struct shmid_ds *shm, const struct __shmid64_ds *shm64)
+{
+  shm->shm_perm         = shm64->shm_perm;
+  shm->shm_segsz        = shm64->shm_segsz;
+  shm->shm_atime        = shm64->shm_atime;
+  shm->__shm_atime_high = 0;
+  shm->shm_dtime        = shm64->shm_dtime;
+  shm->__shm_dtime_high = 0;
+  shm->shm_ctime        = shm64->shm_ctime;
+  shm->__shm_ctime_high = 0;
+  shm->shm_cpid         = shm64->shm_cpid;
+  shm->shm_lpid         = shm64->shm_lpid;
+  shm->shm_nattch       = shm64->shm_nattch;
+}
+
+int
+__shmctl (int shmid, int cmd, struct shmid_ds *buf)
+{
+  struct __shmid64_ds shmid64, *buf64 = NULL;
+  if (buf != NULL)
+    {
+      shmid_to_shmid64 (&shmid64, buf);
+      buf64 = &shmid64;
+    }
+
+  int ret = __shmctl64 (shmid, cmd, buf64);
+  if (ret < 0)
+    return ret;
+
+  switch (cmd)
+    {
+      case IPC_STAT:
+      case SHM_STAT:
+      case SHM_STAT_ANY:
+	if (buf64 != NULL)
+	  shmid64_to_shmid (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, __shmctl, shmctl, DEFAULT_VERSION);
 
 #if defined __ASSUME_SYSVIPC_BROKEN_MODE_T \
     && SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_31)
@@ -92,7 +204,7 @@  int
 attribute_compat_text_section
 __shmctl_mode16 (int shmid, int cmd, struct shmid_ds *buf)
 {
-  return shmctl_syscall (shmid, cmd, buf);
+  return shmctl_syscall (shmid, cmd, (shmctl_arg_t *) buf);
 }
 compat_symbol (libc, __shmctl_mode16, shmctl, GLIBC_2_2);
 #endif
diff --git a/sysdeps/unix/sysv/linux/sparc/bits/types/struct_shmid_ds.h b/sysdeps/unix/sysv/linux/sparc/bits/types/struct_shmid_ds.h
index d5fb61d374..cab3a2686f 100644
--- a/sysdeps/unix/sysv/linux/sparc/bits/types/struct_shmid_ds.h
+++ b/sysdeps/unix/sysv/linux/sparc/bits/types/struct_shmid_ds.h
@@ -25,11 +25,11 @@  struct shmid_ds
   {
     struct ipc_perm shm_perm;		/* operation permission struct */
 #if __TIMESIZE == 32
-    unsigned long int __glibc_reserved1;
+    unsigned long int __shm_atime_high;
     __time_t shm_atime;			/* time of last shmat() */
-    unsigned long int __glibc_reserved2;
+    unsigned long int __shm_dtime_high;
     __time_t shm_dtime;			/* time of last shmdt() */
-    unsigned long int __glibc_reserved3;
+    unsigned long int __shm_ctime_high;
     __time_t shm_ctime;			/* time of last change by shmctl() */
 #else
     __time_t shm_atime;			/* time of last shmat() */
diff --git a/sysdeps/unix/sysv/linux/sparc/struct_kernel_shmid64_ds.h b/sysdeps/unix/sysv/linux/sparc/struct_kernel_shmid64_ds.h
new file mode 100644
index 0000000000..333a410641
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/sparc/struct_kernel_shmid64_ds.h
@@ -0,0 +1,17 @@ 
+/* Analogous to kernel struct shmid64_ds used on shmctl.  */
+struct kernel_shmid64_ds
+{
+  struct ipc_perm shm_perm;
+  unsigned long int shm_atime_high;
+  unsigned long int shm_atime;
+  unsigned long int shm_dtime_high;
+  unsigned long int shm_dtime;
+  unsigned long int shm_ctime_high;
+  unsigned long int shm_ctime;
+  size_t shm_segsz;
+  __pid_t shm_cpid;
+  __pid_t shm_lpid;
+  unsigned long int shm_nattch;
+  unsigned long int __unused1;
+  unsigned long int __unused2;
+};
diff --git a/sysdeps/unix/sysv/linux/struct_kernel_shmid64_ds.h b/sysdeps/unix/sysv/linux/struct_kernel_shmid64_ds.h
new file mode 100644
index 0000000000..6fe67afccb
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/struct_kernel_shmid64_ds.h
@@ -0,0 +1,17 @@ 
+/* Analogous to kernel struct shmid64_ds used on shmctl.  */
+struct kernel_shmid64_ds
+{
+  struct ipc_perm shm_perm;
+  size_t shm_segsz;
+  unsigned long int shm_atime;
+  unsigned long int shm_atime_high;
+  unsigned long int shm_dtime;
+  unsigned long int shm_dtime_high;
+  unsigned long int shm_ctime;
+  unsigned long int shm_ctime_high;
+  __pid_t shm_cpid;
+  __pid_t shm_lpid;
+  unsigned long int shm_nattch;
+  unsigned long int __unused1;
+  unsigned long int __unused2;
+};