Просмотр исходного кода

mips: only n32/n64 always need IPC_64, not o32

1cea0a036 set IPC_64 unconditionally for all of mips.  That is right for
n32/n64, whose *ctl entries are sys_old_semctl & co. (n32: the compat_
variants) on every kernel version, so ipc_parse_version() always strips the
bit out of cmd.  It is wrong for o32: besides the ipc() multiplexer, o32 got
direct semctl/shmctl/msgctl entries as 394/396/402 in 5.1, and those land in
SYSCALL_DEFINE3(shmctl) -> ksys_shmctl(..., IPC_64) with cmd unchanged.  The
bit then survives into the switch, IPC_RMID becomes 0x100 and the kernel
answers -EINVAL -- which is what nginx trips over as
"shmctl(IPC_RMID) failed (22)".

Give o32 the same treatment as i386 and m68k, whose *ctl syscalls appeared in
5.1 for the same reason, and keep the unconditional bit for n32/n64.

Preprocessor-checked with the o32, n32 and n64 toolchains against 4.19.56 and
6.1.60 headers: only the o32/>=5.1 combination changes (0x100 -> 0x0), every
other one keeps its value.  Runtime side: with the mips o32 target added to
the CI matrix at 6.1.60 headers, sem, tst-semctl, tst-shmctl and tst-msgctl
failed with EINVAL, while the same build against 4.19.56 headers passed.

Signed-off-by: Ramin Moussavi <ramin.moussavi@yacoub.de>
ramin 2 недель назад
Родитель
Сommit
97958e275d
1 измененных файлов с 12 добавлено и 8 удалено
  1. 12 8
      libc/misc/sysvipc/ipc.h

+ 12 - 8
libc/misc/sysvipc/ipc.h

@@ -3,19 +3,23 @@
 #include <syscall.h>
 #include <bits/kernel-features.h>
 #include <bits/wordsize.h>
+#ifdef __mips__
+#include <sgidefs.h>
+#endif
 
 #ifndef __ARCH_HAS_DEPRECATED_SYSCALLS__
 #  define __IPC_64	0x0
-#elif defined __mips__
-/* mips routes the *ctl syscalls through sys_old_*ctl (and the ipc()
-   multiplexer), which call ipc_parse_version() and so strip IPC_64 out of
-   cmd to select the layout on every kernel version -- including n64.  The
-   bit must therefore always be set, otherwise the kernel returns the
-   ancient struct and e.g. sem_nsems comes back as 0.  */
+#elif defined __mips__ && _MIPS_SIM != _ABIO32
+/* n32/n64 route the *ctl syscalls through sys_old_*ctl (n32: the compat_
+   variants), which call ipc_parse_version() and so strip IPC_64 out of cmd to
+   select the layout on every kernel version.  The bit must therefore always be
+   set, otherwise the kernel returns the ancient struct and e.g. sem_nsems
+   comes back as 0.  */
 #  define __IPC_64	0x100
-#elif defined __m68k__ || defined __i386__
+#elif defined __m68k__ || defined __i386__ || defined __mips__
 /* 5.1+ uses the direct *ctl syscalls, which (unlike ipc()) do not strip
-   IPC_64 -- passing it would make them fail with EINVAL.  */
+   IPC_64 -- passing it would make them fail with EINVAL.  mips o32 got them
+   as 394/396/402 and belongs here; n32/n64 are handled above.  */
 # if __LINUX_KERNEL_VERSION < 0x050100
 #  define __IPC_64      0x100
 # else