diff mbox series

[v5] linux: Add linux statx(fd, NULL, AT_EMPTY_PATH) support

Message ID 20240829-statx-null-path-v5-1-5356c9c35c7e@gmail.com
State New
Headers show
Series [v5] linux: Add linux statx(fd, NULL, AT_EMPTY_PATH) support | expand

Commit Message

Miao Wang via B4 Relay Aug. 28, 2024, 4:11 p.m. UTC
From: Miao Wang <shankerwangmiao@gmail.com>

Linux supports passing NULL instead of an empty string as the second
parameter when AT_EMPTY_PATH is set in the flags, starting from 6.11,
which brings a performance gain since it is much more efficient to
detect a NULL parameter than to detect an empty string in the kernel.
We utilize this feature if statx is used for fstat, when glibc is
compiled to target kernel versions afterwards, and dynamically probe
the kernel support of it, when targeting previous versions.

Signed-off-by: Miao Wang <shankerwangmiao@gmail.com>
---
Kernel 6.11 adds support for passing NULL to statx(fd, NULL,
AT_EMPTY_PATH), which improves the performance. This series utilize this
feature when statx is used to implement fstat, on some 32-bit platforms
and on loongarch with targeting kernel version below 6.10.6.
---
Changes in v5:
- Use a hidden global varible to store if statx(... NULL ...) is
  supported.
- Link to v4: https://sourceware.org/pipermail/libc-alpha/2024-August/159479.html

Changes in v4:
- Give up tri-state flag implementation and adopt a binary flag.
- Link to v3: https://sourceware.org/pipermail/libc-alpha/2024-August/159468.html

Changes in v3:
- Fixed build error and failure to set errno in fxstat64.
- Utilize tri-state supported flag to eliminate possible data read
  barrier instructions after whether it is supported is determined.
- Link to v2: https://sourceware.org/pipermail/libc-alpha/2024-August/159336.html

Changes in v2:
- Separate this patch out from the series.
- Put the added __statx_empty_path() into internal-stat.h.
- Minor fixes according as suggested by Ruoyao.
- Link to v1: https://sourceware.org/pipermail/libc-alpha/2024-August/159333.html
---
 sysdeps/unix/sysv/linux/fstatat64.c       | 14 ++++++++++++--
 sysdeps/unix/sysv/linux/fxstat64.c        | 12 ++++++------
 sysdeps/unix/sysv/linux/internal-stat.h   | 28 ++++++++++++++++++++++++++++
 sysdeps/unix/sysv/linux/kernel-features.h |  5 +++++
 4 files changed, 51 insertions(+), 8 deletions(-)


---
base-commit: 2eee835eca960c9d4119279804214b7a1ed5d156
change-id: 20240821-statx-null-path-531c0775bba4

Best regards,

Comments

Miao Wang Sept. 24, 2024, 3:57 p.m. UTC | #1
Hi, all

Ping on this patch, since valgrind has been fixed to support statx(..., NULL,
AT_EMPTY_PATH, ...) syscall.

Cheers,

Miao Wang

> 2024年8月29日 00:11,Miao Wang via B4 Relay <devnull+shankerwangmiao.gmail.com@kernel.org> 写道:
> 
> From: Miao Wang <shankerwangmiao@gmail.com>
> 
> Linux supports passing NULL instead of an empty string as the second
> parameter when AT_EMPTY_PATH is set in the flags, starting from 6.11,
> which brings a performance gain since it is much more efficient to
> detect a NULL parameter than to detect an empty string in the kernel.
> We utilize this feature if statx is used for fstat, when glibc is
> compiled to target kernel versions afterwards, and dynamically probe
> the kernel support of it, when targeting previous versions.
> 
> Signed-off-by: Miao Wang <shankerwangmiao@gmail.com>
> ---
> Kernel 6.11 adds support for passing NULL to statx(fd, NULL,
> AT_EMPTY_PATH), which improves the performance. This series utilize this
> feature when statx is used to implement fstat, on some 32-bit platforms
> and on loongarch with targeting kernel version below 6.10.6.
> ---
> Changes in v5:
> - Use a hidden global varible to store if statx(... NULL ...) is
>  supported.
> - Link to v4: https://sourceware.org/pipermail/libc-alpha/2024-August/159479.html
> 
> Changes in v4:
> - Give up tri-state flag implementation and adopt a binary flag.
> - Link to v3: https://sourceware.org/pipermail/libc-alpha/2024-August/159468.html
> 
> Changes in v3:
> - Fixed build error and failure to set errno in fxstat64.
> - Utilize tri-state supported flag to eliminate possible data read
>  barrier instructions after whether it is supported is determined.
> - Link to v2: https://sourceware.org/pipermail/libc-alpha/2024-August/159336.html
> 
> Changes in v2:
> - Separate this patch out from the series.
> - Put the added __statx_empty_path() into internal-stat.h.
> - Minor fixes according as suggested by Ruoyao.
> - Link to v1: https://sourceware.org/pipermail/libc-alpha/2024-August/159333.html
> ---
> sysdeps/unix/sysv/linux/fstatat64.c       | 14 ++++++++++++--
> sysdeps/unix/sysv/linux/fxstat64.c        | 12 ++++++------
> sysdeps/unix/sysv/linux/internal-stat.h   | 28 ++++++++++++++++++++++++++++
> sysdeps/unix/sysv/linux/kernel-features.h |  5 +++++
> 4 files changed, 51 insertions(+), 8 deletions(-)
> 
> diff --git a/sysdeps/unix/sysv/linux/fstatat64.c b/sysdeps/unix/sysv/linux/fstatat64.c
> index da496177c9..59b461cbcf 100644
> --- a/sysdeps/unix/sysv/linux/fstatat64.c
> +++ b/sysdeps/unix/sysv/linux/fstatat64.c
> @@ -38,6 +38,12 @@ _Static_assert (sizeof (__blkcnt_t) == sizeof (__blkcnt64_t),
>                 "__blkcnt_t and __blkcnt64_t must match");
> #endif
> 
> +#if FSTATAT_USE_STATX || XSTAT_IS_XSTAT64
> +# ifndef __ASSUME_STATX_NULL_PATH
> +int __statx_null_path_supported attribute_hidden = 1;
> +# endif
> +#endif
> +
> #if FSTATAT_USE_STATX
> 
> static inline int
> @@ -47,8 +53,12 @@ fstatat64_time64_statx (int fd, const char *file, struct __stat64_t64 *buf,
>   /* 32-bit kABI with default 64-bit time_t, e.g. arc, riscv32.   Also
>      64-bit time_t support is done through statx syscall.  */
>   struct statx tmp;
> -  int r = INTERNAL_SYSCALL_CALL (statx, fd, file, AT_NO_AUTOMOUNT | flag,
> - STATX_BASIC_STATS, &tmp);
> +  flag |= AT_NO_AUTOMOUNT;
> +  int r;
> +  if ((flag & AT_EMPTY_PATH) && (file == NULL || *file == '\0'))
> +    r = __statx_empty_path (fd, flag, &tmp);
> +  else
> +    r = INTERNAL_SYSCALL_CALL (statx, fd, file, flag, STATX_BASIC_STATS, &tmp);
>   if (r != 0)
>     return r;
> 
> diff --git a/sysdeps/unix/sysv/linux/fxstat64.c b/sysdeps/unix/sysv/linux/fxstat64.c
> index 230374cb22..bbe52de36d 100644
> --- a/sysdeps/unix/sysv/linux/fxstat64.c
> +++ b/sysdeps/unix/sysv/linux/fxstat64.c
> @@ -20,7 +20,7 @@
> #include <sys/stat.h>
> #undef __fxstat
> #include <fcntl.h>
> -#include <kernel_stat.h>
> +#include <internal-stat.h>
> #include <sysdep.h>
> #include <xstatconv.h>
> #include <statx_cp.h>
> @@ -53,11 +53,11 @@ ___fxstat64 (int vers, int fd, struct stat64 *buf)
> # else
>   /* New 32-bit kABIs with only 64-bit time_t support, e.g. arc, riscv32.  */
>   struct statx tmp;
> -  int r = INLINE_SYSCALL_CALL (statx, fd, "", AT_EMPTY_PATH,
> -       STATX_BASIC_STATS, &tmp);
> -  if (r == 0)
> -    __cp_stat64_statx (buf, &tmp);
> -  return r;
> +  int r = __statx_empty_path (fd, 0, &tmp);
> +  if (INTERNAL_SYSCALL_ERROR_P (r))
> +    return INLINE_SYSCALL_ERROR_RETURN_VALUE (-r);
> +  __cp_stat64_statx (buf, &tmp);
> +  return 0;
> # endif
> #else
>   /* All kABIs with non-LFS support, e.g. arm, csky, i386, hppa, m68k,
> diff --git a/sysdeps/unix/sysv/linux/internal-stat.h b/sysdeps/unix/sysv/linux/internal-stat.h
> index 9334059765..acaa11e21d 100644
> --- a/sysdeps/unix/sysv/linux/internal-stat.h
> +++ b/sysdeps/unix/sysv/linux/internal-stat.h
> @@ -29,3 +29,31 @@
> #else
> # define FSTATAT_USE_STATX 0
> #endif
> +
> +#if FSTATAT_USE_STATX || XSTAT_IS_XSTAT64
> +
> +/* buf MUST be a valid buffer, or the feature detection may not work properly */
> +
> +static inline int
> +__statx_empty_path (int fd, int flag, struct statx *buf)
> +{
> +  flag |= AT_EMPTY_PATH;
> +#ifdef __ASSUME_STATX_NULL_PATH
> +  return INTERNAL_SYSCALL_CALL (statx, fd, NULL, flag, STATX_BASIC_STATS, buf);
> +#else
> +  /* Defined in fstatat64.c.  */
> +  extern int __statx_null_path_supported attribute_hidden;
> +  int r;
> +  int supported = atomic_load_relaxed (&__statx_null_path_supported);
> +  if (__glibc_likely (supported))
> +    {
> +      r = INTERNAL_SYSCALL_CALL (statx, fd, NULL, flag, STATX_BASIC_STATS, buf);
> +      if (r != -EFAULT)
> + return r;
> +      atomic_store_relaxed (&__statx_null_path_supported, 0);
> +    }
> +  return INTERNAL_SYSCALL_CALL (statx, fd, "", flag, STATX_BASIC_STATS, buf);
> +#endif
> +}
> +
> +#endif
> diff --git a/sysdeps/unix/sysv/linux/kernel-features.h b/sysdeps/unix/sysv/linux/kernel-features.h
> index a25cf07e9f..78aaf43a82 100644
> --- a/sysdeps/unix/sysv/linux/kernel-features.h
> +++ b/sysdeps/unix/sysv/linux/kernel-features.h
> @@ -257,4 +257,9 @@
> # define __ASSUME_FCHMODAT2 0
> #endif
> 
> +/* statx(fd, NULL, AT_EMPTY_PATH) was introduced in Linux 6.11. */
> +#if __LINUX_KERNEL_VERSION >= 0x060b00
> +# define __ASSUME_STATX_NULL_PATH 1
> +#endif
> +
> #endif /* kernel-features.h */
> 
> ---
> base-commit: 2eee835eca960c9d4119279804214b7a1ed5d156
> change-id: 20240821-statx-null-path-531c0775bba4
> 
> Best regards,
> -- 
> Miao Wang <shankerwangmiao@gmail.com>
> 
>
diff mbox series

Patch

diff --git a/sysdeps/unix/sysv/linux/fstatat64.c b/sysdeps/unix/sysv/linux/fstatat64.c
index da496177c9..59b461cbcf 100644
--- a/sysdeps/unix/sysv/linux/fstatat64.c
+++ b/sysdeps/unix/sysv/linux/fstatat64.c
@@ -38,6 +38,12 @@  _Static_assert (sizeof (__blkcnt_t) == sizeof (__blkcnt64_t),
                 "__blkcnt_t and __blkcnt64_t must match");
 #endif
 
+#if FSTATAT_USE_STATX || XSTAT_IS_XSTAT64
+# ifndef __ASSUME_STATX_NULL_PATH
+int __statx_null_path_supported attribute_hidden = 1;
+# endif
+#endif
+
 #if FSTATAT_USE_STATX
 
 static inline int
@@ -47,8 +53,12 @@  fstatat64_time64_statx (int fd, const char *file, struct __stat64_t64 *buf,
   /* 32-bit kABI with default 64-bit time_t, e.g. arc, riscv32.   Also
      64-bit time_t support is done through statx syscall.  */
   struct statx tmp;
-  int r = INTERNAL_SYSCALL_CALL (statx, fd, file, AT_NO_AUTOMOUNT | flag,
-				 STATX_BASIC_STATS, &tmp);
+  flag |= AT_NO_AUTOMOUNT;
+  int r;
+  if ((flag & AT_EMPTY_PATH) && (file == NULL || *file == '\0'))
+    r = __statx_empty_path (fd, flag, &tmp);
+  else
+    r = INTERNAL_SYSCALL_CALL (statx, fd, file, flag, STATX_BASIC_STATS, &tmp);
   if (r != 0)
     return r;
 
diff --git a/sysdeps/unix/sysv/linux/fxstat64.c b/sysdeps/unix/sysv/linux/fxstat64.c
index 230374cb22..bbe52de36d 100644
--- a/sysdeps/unix/sysv/linux/fxstat64.c
+++ b/sysdeps/unix/sysv/linux/fxstat64.c
@@ -20,7 +20,7 @@ 
 #include <sys/stat.h>
 #undef __fxstat
 #include <fcntl.h>
-#include <kernel_stat.h>
+#include <internal-stat.h>
 #include <sysdep.h>
 #include <xstatconv.h>
 #include <statx_cp.h>
@@ -53,11 +53,11 @@  ___fxstat64 (int vers, int fd, struct stat64 *buf)
 # else
   /* New 32-bit kABIs with only 64-bit time_t support, e.g. arc, riscv32.  */
   struct statx tmp;
-  int r = INLINE_SYSCALL_CALL (statx, fd, "", AT_EMPTY_PATH,
-			       STATX_BASIC_STATS, &tmp);
-  if (r == 0)
-    __cp_stat64_statx (buf, &tmp);
-  return r;
+  int r = __statx_empty_path (fd, 0, &tmp);
+  if (INTERNAL_SYSCALL_ERROR_P (r))
+    return INLINE_SYSCALL_ERROR_RETURN_VALUE (-r);
+  __cp_stat64_statx (buf, &tmp);
+  return 0;
 # endif
 #else
   /* All kABIs with non-LFS support, e.g. arm, csky, i386, hppa, m68k,
diff --git a/sysdeps/unix/sysv/linux/internal-stat.h b/sysdeps/unix/sysv/linux/internal-stat.h
index 9334059765..acaa11e21d 100644
--- a/sysdeps/unix/sysv/linux/internal-stat.h
+++ b/sysdeps/unix/sysv/linux/internal-stat.h
@@ -29,3 +29,31 @@ 
 #else
 # define FSTATAT_USE_STATX 0
 #endif
+
+#if FSTATAT_USE_STATX || XSTAT_IS_XSTAT64
+
+/* buf MUST be a valid buffer, or the feature detection may not work properly */
+
+static inline int
+__statx_empty_path (int fd, int flag, struct statx *buf)
+{
+  flag |= AT_EMPTY_PATH;
+#ifdef __ASSUME_STATX_NULL_PATH
+  return INTERNAL_SYSCALL_CALL (statx, fd, NULL, flag, STATX_BASIC_STATS, buf);
+#else
+  /* Defined in fstatat64.c.  */
+  extern int __statx_null_path_supported attribute_hidden;
+  int r;
+  int supported = atomic_load_relaxed (&__statx_null_path_supported);
+  if (__glibc_likely (supported))
+    {
+      r = INTERNAL_SYSCALL_CALL (statx, fd, NULL, flag, STATX_BASIC_STATS, buf);
+      if (r != -EFAULT)
+	return r;
+      atomic_store_relaxed (&__statx_null_path_supported, 0);
+    }
+  return INTERNAL_SYSCALL_CALL (statx, fd, "", flag, STATX_BASIC_STATS, buf);
+#endif
+}
+
+#endif
diff --git a/sysdeps/unix/sysv/linux/kernel-features.h b/sysdeps/unix/sysv/linux/kernel-features.h
index a25cf07e9f..78aaf43a82 100644
--- a/sysdeps/unix/sysv/linux/kernel-features.h
+++ b/sysdeps/unix/sysv/linux/kernel-features.h
@@ -257,4 +257,9 @@ 
 # define __ASSUME_FCHMODAT2 0
 #endif
 
+/* statx(fd, NULL, AT_EMPTY_PATH) was introduced in Linux 6.11. */
+#if __LINUX_KERNEL_VERSION >= 0x060b00
+# define __ASSUME_STATX_NULL_PATH 1
+#endif
+
 #endif /* kernel-features.h */