[PATCH v8] linux: use PIDFD_GET_INFO ioctl for pidfd_getpid() if available
Adhemerval Zanella Netto
adhemerval.zanella@linaro.org
Fri Jan 30 13:58:14 GMT 2026
On 28/01/26 12:37, luca.boccassi@gmail.com wrote:
> From: Luca Boccassi <luca.boccassi@gmail.com>
>
> 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 <luca.boccassi@gmail.com>
This version look ok to me. I though about documenting the possible errno
value different when ioctl is used, but since you state that it being
changed on kernel I think it is not really worth.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
> ---
> v2: use sys/pidfd.h instead of installed kernel headers
>
> v3: add __ASSUME_PIDFD_GET_INFO
> use atomics for support cache var
>
> v4: drop support cache var
>
> v5: drop static helper given it's just the ioctl call now, simplifies the flow
>
> v6: map ENOTTY to EBADF to avoid breaking documented behaviour
>
> v7: switch from ioctl() to __ioctl()
>
> v8: adapt tst-pidfd_getpid to PIDFD_GET_INFO which might return ESRCH
> when querying a pid in another namespace. A fix has been sent, but
> existing kernels need to be supported too.
>
> sysdeps/unix/sysv/linux/kernel-features.h | 8 ++++
> sysdeps/unix/sysv/linux/pidfd_getpid.c | 44 ++++++++++++++++++----
> sysdeps/unix/sysv/linux/tst-pidfd_getpid.c | 4 +-
> 3 files changed, 47 insertions(+), 9 deletions(-)
>
> 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 <stdlib.h>
> #include <string.h>
> #include <sysdep.h>
> +#include <sys/ioctl.h>
> +#include <sys/pidfd.h>
> #include <unistd.h>
>
> +#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);
> }
More information about the Libc-alpha
mailing list