From: Luca Boccassi Date: Wed, 28 Jan 2026 15:37:56 +0000 (+0000) Subject: linux: use PIDFD_GET_INFO ioctl for pidfd_getpid() if available X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f8dac91ca3b4123e8c853b1bf6b126ad6829687e;p=thirdparty%2Fglibc.git linux: use PIDFD_GET_INFO ioctl for pidfd_getpid() if available Linux v6.13 introduced a new ioctl to query info from a pidfd. The advantage of this vs. parsing /proc/ is that it works even when procfs is not mounted. It's also a single syscall, and doesn't need manual string parsing. Use it when available. Signed-off-by: Luca Boccassi Reviewed-by: Adhemerval Zanella --- diff --git a/sysdeps/unix/sysv/linux/kernel-features.h b/sysdeps/unix/sysv/linux/kernel-features.h index 01c865e2d5..94bdbbb730 100644 --- a/sysdeps/unix/sysv/linux/kernel-features.h +++ b/sysdeps/unix/sysv/linux/kernel-features.h @@ -269,4 +269,12 @@ # define __ASSUME_MSEAL 0 #endif +/* The PIDFD_GET_INFO ioctl was introduced across all architectures in Linux + 6.13. */ +#if __LINUX_KERNEL_VERSION >= 0x060D00 +# define __ASSUME_PIDFD_GET_INFO 1 +#else +# define __ASSUME_PIDFD_GET_INFO 0 +#endif + #endif /* kernel-features.h */ diff --git a/sysdeps/unix/sysv/linux/pidfd_getpid.c b/sysdeps/unix/sysv/linux/pidfd_getpid.c index 860829cf07..6bf6590877 100644 --- a/sysdeps/unix/sysv/linux/pidfd_getpid.c +++ b/sysdeps/unix/sysv/linux/pidfd_getpid.c @@ -23,8 +23,11 @@ #include #include #include +#include +#include #include +#if !__ASSUME_PIDFD_GET_INFO #define FDINFO_TO_FILENAME_PREFIX "/proc/self/fdinfo/" #define FDINFO_FILENAME_LEN \ @@ -91,15 +94,9 @@ parse_fdinfo (const char *l, void *arg) return 1; } -pid_t -pidfd_getpid (int fd) +static pid_t +getpid_fdinfo (int fd) { - if (__glibc_unlikely (fd < 0)) - { - __set_errno (EBADF); - return -1; - } - char fdinfoname[FDINFO_FILENAME_LEN]; char *p = mempcpy (fdinfoname, FDINFO_TO_FILENAME_PREFIX, @@ -126,3 +123,34 @@ pidfd_getpid (int fd) return fdinfo.pid; } +#endif + +pid_t +pidfd_getpid (int fd) +{ + struct pidfd_info info = { .mask = PIDFD_INFO_PID }; + + if (__glibc_unlikely (fd < 0)) + { + __set_errno (EBADF); + return -1; + } + + /* New in kernel 6.13 */ + if (__ioctl (fd, PIDFD_GET_INFO, &info) < 0) + { +#if __ASSUME_PIDFD_GET_INFO + /* The procfs implementation returns EBADF when called with a non-pidfd + fd, change the errno to keep it consistent across implementations. */ + if (errno == ENOTTY) + return INLINE_SYSCALL_ERROR_RETURN_VALUE (EBADF); +#else + if (errno == ENOTTY || errno == EINVAL) + return getpid_fdinfo (fd); +#endif + + return INLINE_SYSCALL_ERROR_RETURN_VALUE (errno); + } + + return info.pid; +} diff --git a/sysdeps/unix/sysv/linux/tst-pidfd_getpid.c b/sysdeps/unix/sysv/linux/tst-pidfd_getpid.c index 597a140330..0a5f4c9d9c 100644 --- a/sysdeps/unix/sysv/linux/tst-pidfd_getpid.c +++ b/sysdeps/unix/sysv/linux/tst-pidfd_getpid.c @@ -100,7 +100,9 @@ do_test (void) } TEST_COMPARE (pidfd_getpid (child1_pidfd), -1); - TEST_COMPARE (errno, EREMOTE); + /* The kernel PIDFD_GET_INFO used to return ESRCH in this case. */ + if (errno != EREMOTE) + TEST_COMPARE (errno, ESRCH); _exit (EXIT_SUCCESS); }