Message ID | 20180419143737.606138-2-arnd@arndb.de |
---|---|
State | New |
Headers | show |
Series | y2038: Convert IPC syscalls | expand |
Arnd Bergmann <arnd@arndb.de> writes: > Most architectures now use the asm-generic copy of the sysvipc data > structures (msqid64_ds, semid64_ds, shmid64_ds), which use 32-bit > __kernel_time_t on 32-bit architectures but have padding behind them to > allow extending the type to 64-bit. > > Unfortunately, that fails on all big-endian architectures, which have the > padding on the wrong side. As so many of them get it wrong, we decided to > not bother even trying to fix it up when we introduced the asm-generic > copy. Instead we always use the padding word now to provide the upper > 32 bits of the seconds value, regardless of the endianess. > > A libc implementation on a typical big-endian system can deal with > this by providing its own copy of the structure definition to user > space, and swapping the two 32-bit words before returning from the > semctl/shmctl/msgctl system calls. > > ARM64 and s/390 are architectures that use these generic headers and > also provide support for compat mode on 64-bit kernels, so we adapt > their copies here as well. > > Signed-off-by: Arnd Bergmann <arnd@arndb.de> > --- > include/uapi/asm-generic/msgbuf.h | 17 ++++++++--------- > include/uapi/asm-generic/sembuf.h | 26 ++++++++++++++++---------- > include/uapi/asm-generic/shmbuf.h | 17 ++++++++--------- > 3 files changed, 32 insertions(+), 28 deletions(-) > > diff --git a/include/uapi/asm-generic/msgbuf.h b/include/uapi/asm-generic/msgbuf.h > index fb306ebdb36f..d2169cae93b8 100644 > --- a/include/uapi/asm-generic/msgbuf.h > +++ b/include/uapi/asm-generic/msgbuf.h > @@ -18,23 +18,22 @@ > * On big-endian systems, the padding is in the wrong place. > * > * Pad space is left for: > - * - 64-bit time_t to solve y2038 problem > * - 2 miscellaneous 32-bit values > */ > > struct msqid64_ds { > struct ipc64_perm msg_perm; > +#if __BITS_PER_LONG == 64 > __kernel_time_t msg_stime; /* last msgsnd time */ > -#if __BITS_PER_LONG != 64 > - unsigned long __unused1; > -#endif > __kernel_time_t msg_rtime; /* last msgrcv time */ > -#if __BITS_PER_LONG != 64 > - unsigned long __unused2; > -#endif > __kernel_time_t msg_ctime; /* last change time */ > -#if __BITS_PER_LONG != 64 > - unsigned long __unused3; > +#else > + unsigned long msg_stime; /* last msgsnd time */ > + unsigned long msg_stime_high; > + unsigned long msg_rtime; /* last msgrcv time */ > + unsigned long msg_rtime_high; > + unsigned long msg_ctime; /* last change time */ > + unsigned long msg_ctime_high; > #endif I suspect you want to use __kernel_ulong_t here instead of a raw unsigned long. If nothing else it seems inconsistent to use typedefs in one half of the structure and no typedefs in the other half. > __kernel_ulong_t msg_cbytes; /* current number of bytes on queue */ > __kernel_ulong_t msg_qnum; /* number of messages in queue */ > diff --git a/include/uapi/asm-generic/sembuf.h b/include/uapi/asm-generic/sembuf.h > index cbf9cfe977d6..0bae010f1b64 100644 > --- a/include/uapi/asm-generic/sembuf.h > +++ b/include/uapi/asm-generic/sembuf.h > @@ -13,23 +13,29 @@ > * everyone just ended up making identical copies without specific > * optimizations, so we may just as well all use the same one. > * > - * 64 bit architectures typically define a 64 bit __kernel_time_t, > + * 64 bit architectures use a 64-bit __kernel_time_t here, while > + * 32 bit architectures have a pair of unsigned long values. > * so they do not need the first two padding words. > - * On big-endian systems, the padding is in the wrong place. > * > - * Pad space is left for: > - * - 64-bit time_t to solve y2038 problem > - * - 2 miscellaneous 32-bit values > + * On big-endian systems, the padding is in the wrong place for > + * historic reasons, so user space has to reconstruct a time_t > + * value using > + * > + * user_semid_ds.sem_otime = kernel_semid64_ds.sem_otime + > + * ((long long)kernel_semid64_ds.sem_otime_high << 32) > + * > + * Pad space is left for 2 miscellaneous 32-bit values > */ > struct semid64_ds { > struct ipc64_perm sem_perm; /* permissions .. see ipc.h */ > +#if __BITS_PER_LONG == 64 > __kernel_time_t sem_otime; /* last semop time */ > -#if __BITS_PER_LONG != 64 > - unsigned long __unused1; > -#endif > __kernel_time_t sem_ctime; /* last change time */ > -#if __BITS_PER_LONG != 64 > - unsigned long __unused2; > +#else > + unsigned long sem_otime; /* last semop time */ > + unsigned long sem_otime_high; > + unsigned long sem_ctime; /* last change time */ > + unsigned long sem_ctime_high; > #endif > unsigned long sem_nsems; /* no. of semaphores in array */ > unsigned long __unused3; > diff --git a/include/uapi/asm-generic/shmbuf.h b/include/uapi/asm-generic/shmbuf.h > index 2b6c3bb97f97..602f1b5b462b 100644 > --- a/include/uapi/asm-generic/shmbuf.h > +++ b/include/uapi/asm-generic/shmbuf.h > @@ -19,24 +19,23 @@ > * > * > * Pad space is left for: > - * - 64-bit time_t to solve y2038 problem > * - 2 miscellaneous 32-bit values > */ > > struct shmid64_ds { > struct ipc64_perm shm_perm; /* operation perms */ > size_t shm_segsz; /* size of segment (bytes) */ > +#if __BITS_PER_LONG == 64 > __kernel_time_t shm_atime; /* last attach time */ > -#if __BITS_PER_LONG != 64 > - unsigned long __unused1; > -#endif > __kernel_time_t shm_dtime; /* last detach time */ > -#if __BITS_PER_LONG != 64 > - unsigned long __unused2; > -#endif > __kernel_time_t shm_ctime; /* last change time */ > -#if __BITS_PER_LONG != 64 > - unsigned long __unused3; > +#else > + unsigned long shm_atime; /* last attach time */ > + unsigned long shm_atime_high; > + unsigned long shm_dtime; /* last detach time */ > + unsigned long shm_dtime_high; > + unsigned long shm_ctime; /* last change time */ > + unsigned long shm_ctime_high; > #endif > __kernel_pid_t shm_cpid; /* pid of creator */ > __kernel_pid_t shm_lpid; /* pid of last operator */
On Thu, Apr 19, 2018 at 4:59 PM, Eric W. Biederman <ebiederm@xmission.com> wrote: > Arnd Bergmann <arnd@arndb.de> writes: >> >> struct msqid64_ds { >> struct ipc64_perm msg_perm; >> +#if __BITS_PER_LONG == 64 >> __kernel_time_t msg_stime; /* last msgsnd time */ >> -#if __BITS_PER_LONG != 64 >> - unsigned long __unused1; >> -#endif >> __kernel_time_t msg_rtime; /* last msgrcv time */ >> -#if __BITS_PER_LONG != 64 >> - unsigned long __unused2; >> -#endif >> __kernel_time_t msg_ctime; /* last change time */ >> -#if __BITS_PER_LONG != 64 >> - unsigned long __unused3; >> +#else >> + unsigned long msg_stime; /* last msgsnd time */ >> + unsigned long msg_stime_high; >> + unsigned long msg_rtime; /* last msgrcv time */ >> + unsigned long msg_rtime_high; >> + unsigned long msg_ctime; /* last change time */ >> + unsigned long msg_ctime_high; >> #endif > > I suspect you want to use __kernel_ulong_t here instead of a raw > unsigned long. If nothing else it seems inconsistent to use typedefs > in one half of the structure and no typedefs in the other half. Good catch, there is definitely something wrong here, but I think using __kernel_ulong_t for all members would also be wrong, as that still changes the layout on x32, which effectively is struct msqid64_ds { ipc64_perm msg_perm; u64 msg_stime; u32 __unused1; /* 32 bit implict padding */ u64 msg_rtime; u32 __unused2; /* 32 bit implict padding */ u64 msg_ctime; u32 __unused3; /* 32 bit implict padding */ __kernel_pid_t shm_cpid; /* pid of creator */ __kernel_pid_t shm_lpid; /* pid of last operator */ .... }; The choices here would be to either use a mix of __kernel_ulong_t and unsigned long, or taking the x32 version back into arch/x86/include/uapi/asm/ so the generic version at least makes some sense. I can't use __kernel_time_t for the lower half on 32-bit since it really should be unsigned. Arnd
On Thu, Apr 19, 2018 at 5:30 PM, Zack Weinberg <zackw@panix.com> wrote: > On Thu, Apr 19, 2018 at 10:37 AM, Arnd Bergmann <arnd@arndb.de> wrote: >> Most architectures now use the asm-generic copy of the sysvipc data >> structures (msqid64_ds, semid64_ds, shmid64_ds), which use 32-bit >> __kernel_time_t on 32-bit architectures but have padding behind them to >> allow extending the type to 64-bit. >> >> Unfortunately, that fails on all big-endian architectures, which have the >> padding on the wrong side. As so many of them get it wrong, we decided to >> not bother even trying to fix it up when we introduced the asm-generic >> copy. Instead we always use the padding word now to provide the upper >> 32 bits of the seconds value, regardless of the endianess. >> >> A libc implementation on a typical big-endian system can deal with >> this by providing its own copy of the structure definition to user >> space, and swapping the two 32-bit words before returning from the >> semctl/shmctl/msgctl system calls. > > This seems generally like a sound approach, but I need to ask whether > any of the structures involved can ever appear in a sendmsg() control > message (that is, in the data pointed to by msg_control), or an > AF_NETLINK message, or any other situation where the kernel > communicates a structured message of arbitrary size to user space or > vice versa. libc can't munge those messages, because new message > types can be added faster than libc can keep up with them, and because > I/O primitives like sendmsg() generally aren't allowed to allocate > arbitrarily-large scratch buffers. I'm fairly sure that the sysvipc data structures are entirely distinct from the structures that get passed over sockets, so the question of socket data is unrelated to this series and will be addressed in a separate series. To give some background on what needs to be done for sockets, the only incompatibility I'm aware of are socket timestamps that get enabled with SO_TIMESTAMP, SO_TIMESTAMPNS or SO_TIMESTAMPING and get passed from kernel to user space as SCM_TIMESTAMP/SCM_TIMESTAMPNS/SCM_TIMESTAMPING cmsg data. We already have code for handling 32-bit compat applications on 64-bit kernels, but that cannot work for 32-bit applications if the kernel has no idea whether the application uses 32-bit or 64-bit time_t, and we don't have a function like in_compat_syscall() that we can use to find that out. Our plan here is to change asm/socket.h to have three additional timestamp flags that correspond to the existing SO_TIMESTAMP* flags but signify that user space expects the new structure layout (which is compatible with the existing layout on 64-bit kernels). For each flag, the kernel then defines a wrapper that (on 32-bit user space) looks like #define SO_TIMESTAMP (sizeof(time_t) > sizeof(__kernel_long_t) ? \ SO_TIMESTAMP_TIME64 : SO_TIMESTAMP_OLD) Any application asking for SO_TIMESTAMP_OLD will get the traditional behavior, while applications that are built with a 64-bit time_t will pass SO_TIMESTAMP_TIME64 into setsockopts, causing the kernel to use the new behavior. In 64-bit tasks, we probably want to define both to have existing behavior even though one would never see the new macro. Arnd
On Thu, Apr 19, 2018 at 5:20 PM, Arnd Bergmann <arnd@arndb.de> wrote: > On Thu, Apr 19, 2018 at 4:59 PM, Eric W. Biederman <ebiederm@xmission.com> wrote: >> I suspect you want to use __kernel_ulong_t here instead of a raw >> unsigned long. If nothing else it seems inconsistent to use typedefs >> in one half of the structure and no typedefs in the other half. > > Good catch, there is definitely something wrong here, but I think using > __kernel_ulong_t for all members would also be wrong, as that > still changes the layout on x32, which effectively is > > struct msqid64_ds { > ipc64_perm msg_perm; > u64 msg_stime; > u32 __unused1; > /* 32 bit implict padding */ > u64 msg_rtime; > u32 __unused2; > /* 32 bit implict padding */ > u64 msg_ctime; > u32 __unused3; > /* 32 bit implict padding */ > __kernel_pid_t shm_cpid; /* pid of creator */ > __kernel_pid_t shm_lpid; /* pid of last operator */ > .... > }; > > The choices here would be to either use a mix of > __kernel_ulong_t and unsigned long, or taking the x32 > version back into arch/x86/include/uapi/asm/ so the > generic version at least makes some sense. > > I can't use __kernel_time_t for the lower half on 32-bit > since it really should be unsigned. After thinking about it some more, I conclude that the structure is simply incorrect on x32: The __kernel_ulong_t usage was introduced in 2013 in commit b9cd5ca22d67 ("uapi: Use __kernel_ulong_t in struct msqid64_ds") and apparently was correct initially as __BITS_PER_LONG evaluated to 64, but it broke with commit f4b4aae18288 ("x86/headers/uapi: Fix __BITS_PER_LONG value for x32 builds") that changed the value of __BITS_PER_LONG and introduced the extra padding in 2015. The same change apparently also broke a lot of other definitions, e.g. $ echo "#include <linux/types.h>" | gcc -mx32 -E -xc - | grep -A3 __kernel_size_t typedef unsigned int __kernel_size_t; typedef int __kernel_ssize_t; typedef int __kernel_ptrdiff_t; Those used to be defined as 'unsigned long long' and 'long long' respectively, so now all kernel interfaces using those on x32 became incompatible! Arnd
Arnd Bergmann <arnd@arndb.de> writes: > On Thu, Apr 19, 2018 at 5:20 PM, Arnd Bergmann <arnd@arndb.de> wrote: >> On Thu, Apr 19, 2018 at 4:59 PM, Eric W. Biederman <ebiederm@xmission.com> wrote: >>> I suspect you want to use __kernel_ulong_t here instead of a raw >>> unsigned long. If nothing else it seems inconsistent to use typedefs >>> in one half of the structure and no typedefs in the other half. >> >> Good catch, there is definitely something wrong here, but I think using >> __kernel_ulong_t for all members would also be wrong, as that >> still changes the layout on x32, which effectively is >> >> struct msqid64_ds { >> ipc64_perm msg_perm; >> u64 msg_stime; >> u32 __unused1; >> /* 32 bit implict padding */ >> u64 msg_rtime; >> u32 __unused2; >> /* 32 bit implict padding */ >> u64 msg_ctime; >> u32 __unused3; >> /* 32 bit implict padding */ >> __kernel_pid_t shm_cpid; /* pid of creator */ >> __kernel_pid_t shm_lpid; /* pid of last operator */ >> .... >> }; >> >> The choices here would be to either use a mix of >> __kernel_ulong_t and unsigned long, or taking the x32 >> version back into arch/x86/include/uapi/asm/ so the >> generic version at least makes some sense. >> >> I can't use __kernel_time_t for the lower half on 32-bit >> since it really should be unsigned. > > After thinking about it some more, I conclude that the structure is simply > incorrect on x32: The __kernel_ulong_t usage was introduced in 2013 > in commit b9cd5ca22d67 ("uapi: Use __kernel_ulong_t in struct > msqid64_ds") and apparently was correct initially as __BITS_PER_LONG > evaluated to 64, but it broke with commit f4b4aae18288 ("x86/headers/uapi: > Fix __BITS_PER_LONG value for x32 builds") that changed the value > of __BITS_PER_LONG and introduced the extra padding in 2015. > > The same change apparently also broke a lot of other definitions, e.g. > > $ echo "#include <linux/types.h>" | gcc -mx32 -E -xc - | grep -A3 > __kernel_size_t > typedef unsigned int __kernel_size_t; > typedef int __kernel_ssize_t; > typedef int __kernel_ptrdiff_t; > > Those used to be defined as 'unsigned long long' and 'long long' > respectively, so now all kernel interfaces using those on x32 > became incompatible! That seems like a real mess. Is this just for the uapi header as seen by userspace? I expect we are using the a normal kernel interface with 64bit longs and 64bit pointers when we build the kernel. If this is just a header as seen from userspace mess it seems unfortunate but fixable. Eric
On Fri, Apr 20, 2018 at 12:12 AM, Eric W. Biederman <ebiederm@xmission.com> wrote: > Arnd Bergmann <arnd@arndb.de> writes: > >> On Thu, Apr 19, 2018 at 5:20 PM, Arnd Bergmann <arnd@arndb.de> wrote: >>> On Thu, Apr 19, 2018 at 4:59 PM, Eric W. Biederman <ebiederm@xmission.com> wrote: >>>> I suspect you want to use __kernel_ulong_t here instead of a raw >>>> unsigned long. If nothing else it seems inconsistent to use typedefs >>>> in one half of the structure and no typedefs in the other half. >>> >>> Good catch, there is definitely something wrong here, but I think using >>> __kernel_ulong_t for all members would also be wrong, as that >>> still changes the layout on x32, which effectively is >>> >>> struct msqid64_ds { >>> ipc64_perm msg_perm; >>> u64 msg_stime; >>> u32 __unused1; >>> /* 32 bit implict padding */ >>> u64 msg_rtime; >>> u32 __unused2; >>> /* 32 bit implict padding */ >>> u64 msg_ctime; >>> u32 __unused3; >>> /* 32 bit implict padding */ >>> __kernel_pid_t shm_cpid; /* pid of creator */ >>> __kernel_pid_t shm_lpid; /* pid of last operator */ >>> .... >>> }; >>> >>> The choices here would be to either use a mix of >>> __kernel_ulong_t and unsigned long, or taking the x32 >>> version back into arch/x86/include/uapi/asm/ so the >>> generic version at least makes some sense. >>> >>> I can't use __kernel_time_t for the lower half on 32-bit >>> since it really should be unsigned. >> >> After thinking about it some more, I conclude that the structure is simply >> incorrect on x32: The __kernel_ulong_t usage was introduced in 2013 >> in commit b9cd5ca22d67 ("uapi: Use __kernel_ulong_t in struct >> msqid64_ds") and apparently was correct initially as __BITS_PER_LONG >> evaluated to 64, but it broke with commit f4b4aae18288 ("x86/headers/uapi: >> Fix __BITS_PER_LONG value for x32 builds") that changed the value >> of __BITS_PER_LONG and introduced the extra padding in 2015. >> >> The same change apparently also broke a lot of other definitions, e.g. >> >> $ echo "#include <linux/types.h>" | gcc -mx32 -E -xc - | grep -A3 >> __kernel_size_t >> typedef unsigned int __kernel_size_t; >> typedef int __kernel_ssize_t; >> typedef int __kernel_ptrdiff_t; >> >> Those used to be defined as 'unsigned long long' and 'long long' >> respectively, so now all kernel interfaces using those on x32 >> became incompatible! > > Is this just for the uapi header as seen by userspace? I expect we are > using the a normal kernel interface with 64bit longs and 64bit pointers > when we build the kernel. Yes, that patch shouldn't have changed anything in the kernel, which continues to be built with __BITS_PER_LONG=64. I haven't checked the vdso, which is the only bit of the kernel that gets built with -mx32, but I assume it's fine as well. > If this is just a header as seen from userspace mess it seems > unfortunate but fixable. Right. I'll fix the IPC stuff for this series to make it work with any value of __BITS_PER_LONG on x32, but I don't plan to do anything about the rest of x32. The patch that caused the problem was intended as a bugfix, so we can't just revert it without first understanding how to properly fix the original bug, and which other interfaces have now come to rely on __BITS_PER_LONG=32 for x32. Adding a few other folks that have been involved in the x32 kernel support or the Debian port in the past. Maybe one of them is motivated to figure out how to fix this properly. Arnd
On Fri, Apr 20, 2018 at 7:38 AM, Arnd Bergmann <arnd@arndb.de> wrote: > On Fri, Apr 20, 2018 at 3:53 PM, Jeffrey Walton <noloader@gmail.com> wrote: >>> +#if !defined(__x86_64__) || !defined(__ilp32__) >>> #include <asm-generic/msgbuf.h> >>> +#else >> >> I understand there's some progress having Clang compile the kernel. >> Clang treats __ILP32__ and friends differently than GCC. I believe >> ILP32 shows up just about everywhere there are 32-bit ints, longs and >> pointers. You might find it on Aarch64 or you might find it on MIPS64 >> when using Clang. >> >> I think that means this may be a little suspicious: >> >> > +#if !defined(__x86_64__) || !defined(__ilp32__) >> >> I kind of felt LLVM was wandering away from the x32 ABI, but the LLVM >> devs insisted they were within their purview. Also see >> https://lists.llvm.org/pipermail/cfe-dev/2015-December/046300.html. >> >> Sorry about the top-post. I just wanted to pick out that one piece. > > It seems I made a typo and it needs to be __ILP32__ rather than > __ilp32__ (corrected that locally, will resend once we have resolved > this). > > Aside from that, the #if check seems to be correct to me: this > is an x86-specific header, so it won't ever be seen on other > architectures. On x86-32, __x86_64__ isn't set, so we don't care > about whether __ilp32__ is set or not, and on x86-64 (lp64), > __ilp32__ is never set, so we still get the asm-generic header. > Glibc has correct header files for system calls. I have a very old program to check if Linux kernel header files are correct for user space: https://github.com/hjl-tools/linux-header It needs update to check uapi. -- H.J.
diff --git a/include/uapi/asm-generic/msgbuf.h b/include/uapi/asm-generic/msgbuf.h index fb306ebdb36f..d2169cae93b8 100644 --- a/include/uapi/asm-generic/msgbuf.h +++ b/include/uapi/asm-generic/msgbuf.h @@ -18,23 +18,22 @@ * On big-endian systems, the padding is in the wrong place. * * Pad space is left for: - * - 64-bit time_t to solve y2038 problem * - 2 miscellaneous 32-bit values */ struct msqid64_ds { struct ipc64_perm msg_perm; +#if __BITS_PER_LONG == 64 __kernel_time_t msg_stime; /* last msgsnd time */ -#if __BITS_PER_LONG != 64 - unsigned long __unused1; -#endif __kernel_time_t msg_rtime; /* last msgrcv time */ -#if __BITS_PER_LONG != 64 - unsigned long __unused2; -#endif __kernel_time_t msg_ctime; /* last change time */ -#if __BITS_PER_LONG != 64 - unsigned long __unused3; +#else + unsigned long msg_stime; /* last msgsnd time */ + unsigned long msg_stime_high; + unsigned long msg_rtime; /* last msgrcv time */ + unsigned long msg_rtime_high; + unsigned long msg_ctime; /* last change time */ + unsigned long msg_ctime_high; #endif __kernel_ulong_t msg_cbytes; /* current number of bytes on queue */ __kernel_ulong_t msg_qnum; /* number of messages in queue */ diff --git a/include/uapi/asm-generic/sembuf.h b/include/uapi/asm-generic/sembuf.h index cbf9cfe977d6..0bae010f1b64 100644 --- a/include/uapi/asm-generic/sembuf.h +++ b/include/uapi/asm-generic/sembuf.h @@ -13,23 +13,29 @@ * everyone just ended up making identical copies without specific * optimizations, so we may just as well all use the same one. * - * 64 bit architectures typically define a 64 bit __kernel_time_t, + * 64 bit architectures use a 64-bit __kernel_time_t here, while + * 32 bit architectures have a pair of unsigned long values. * so they do not need the first two padding words. - * On big-endian systems, the padding is in the wrong place. * - * Pad space is left for: - * - 64-bit time_t to solve y2038 problem - * - 2 miscellaneous 32-bit values + * On big-endian systems, the padding is in the wrong place for + * historic reasons, so user space has to reconstruct a time_t + * value using + * + * user_semid_ds.sem_otime = kernel_semid64_ds.sem_otime + + * ((long long)kernel_semid64_ds.sem_otime_high << 32) + * + * Pad space is left for 2 miscellaneous 32-bit values */ struct semid64_ds { struct ipc64_perm sem_perm; /* permissions .. see ipc.h */ +#if __BITS_PER_LONG == 64 __kernel_time_t sem_otime; /* last semop time */ -#if __BITS_PER_LONG != 64 - unsigned long __unused1; -#endif __kernel_time_t sem_ctime; /* last change time */ -#if __BITS_PER_LONG != 64 - unsigned long __unused2; +#else + unsigned long sem_otime; /* last semop time */ + unsigned long sem_otime_high; + unsigned long sem_ctime; /* last change time */ + unsigned long sem_ctime_high; #endif unsigned long sem_nsems; /* no. of semaphores in array */ unsigned long __unused3; diff --git a/include/uapi/asm-generic/shmbuf.h b/include/uapi/asm-generic/shmbuf.h index 2b6c3bb97f97..602f1b5b462b 100644 --- a/include/uapi/asm-generic/shmbuf.h +++ b/include/uapi/asm-generic/shmbuf.h @@ -19,24 +19,23 @@ * * * Pad space is left for: - * - 64-bit time_t to solve y2038 problem * - 2 miscellaneous 32-bit values */ struct shmid64_ds { struct ipc64_perm shm_perm; /* operation perms */ size_t shm_segsz; /* size of segment (bytes) */ +#if __BITS_PER_LONG == 64 __kernel_time_t shm_atime; /* last attach time */ -#if __BITS_PER_LONG != 64 - unsigned long __unused1; -#endif __kernel_time_t shm_dtime; /* last detach time */ -#if __BITS_PER_LONG != 64 - unsigned long __unused2; -#endif __kernel_time_t shm_ctime; /* last change time */ -#if __BITS_PER_LONG != 64 - unsigned long __unused3; +#else + unsigned long shm_atime; /* last attach time */ + unsigned long shm_atime_high; + unsigned long shm_dtime; /* last detach time */ + unsigned long shm_dtime_high; + unsigned long shm_ctime; /* last change time */ + unsigned long shm_ctime_high; #endif __kernel_pid_t shm_cpid; /* pid of creator */ __kernel_pid_t shm_lpid; /* pid of last operator */
Most architectures now use the asm-generic copy of the sysvipc data structures (msqid64_ds, semid64_ds, shmid64_ds), which use 32-bit __kernel_time_t on 32-bit architectures but have padding behind them to allow extending the type to 64-bit. Unfortunately, that fails on all big-endian architectures, which have the padding on the wrong side. As so many of them get it wrong, we decided to not bother even trying to fix it up when we introduced the asm-generic copy. Instead we always use the padding word now to provide the upper 32 bits of the seconds value, regardless of the endianess. A libc implementation on a typical big-endian system can deal with this by providing its own copy of the structure definition to user space, and swapping the two 32-bit words before returning from the semctl/shmctl/msgctl system calls. ARM64 and s/390 are architectures that use these generic headers and also provide support for compat mode on 64-bit kernels, so we adapt their copies here as well. Signed-off-by: Arnd Bergmann <arnd@arndb.de> --- include/uapi/asm-generic/msgbuf.h | 17 ++++++++--------- include/uapi/asm-generic/sembuf.h | 26 ++++++++++++++++---------- include/uapi/asm-generic/shmbuf.h | 17 ++++++++--------- 3 files changed, 32 insertions(+), 28 deletions(-) -- 2.9.0