diff mbox series

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

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

Commit Message

Miao Wang via B4 Relay Aug. 21, 2024, 4:14 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 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       |  8 ++++++--
 sysdeps/unix/sysv/linux/fxstat64.c        |  3 +--
 sysdeps/unix/sysv/linux/internal-stat.h   | 31 +++++++++++++++++++++++++++++++
 sysdeps/unix/sysv/linux/kernel-features.h |  5 +++++
 4 files changed, 43 insertions(+), 4 deletions(-)


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

Best regards,

Comments

Miao Wang Aug. 23, 2024, 5:20 p.m. UTC | #1
Hi, all

I've received a notification from patchwork stating this patch caused a
regression for the test tst-valgrind-smoke [1].


I'm able to reproduce this in my working environment, using qemu userspace
emulation. The output of valgrind is:

> ==469== Syscall param statx(filename) points to unaddressable byte(s)
> ==469==    at 0x11A536: __libc_do_syscall (libc-do-syscall.S:47)
> ==469==    by 0x11BAF1: __statx_empty_path (internal-stat.h:47)
> ==469==    by 0x11BAF1: fstatat64_time64_statx (fstatat64.c:53)
> ==469==    by 0x11BAF1: __fstatat64_time64 (fstatat64.c:154)
> ==469==    by 0x10C4EF: _dl_get_file_id (dl-fileid.h:37)
> ==469==    by 0x10C4EF: _dl_map_object_from_fd (dl-load.c:955)
> ==469==    by 0x10D0E3: _dl_map_object (dl-load.c:2190)
> ==469==    by 0x116E39: map_doit (rtld.c:644)
> ==469==    by 0x108DDF: _dl_catch_exception (dl-catch.c:241)
> ==469==    by 0x108EAB: _dl_catch_error (dl-catch.c:260)
> ==469==    by 0x116DE7: do_preload (rtld.c:818)
> ==469==    by 0x117ACD: handle_preload_list (rtld.c:894)
> ==469==    by 0x119B0B: dl_main (rtld.c:1849)
> ==469==    by 0x1167B3: _dl_sysdep_start (dl-sysdep.c:141)
> ==469==    by 0x117817: _dl_start_final (rtld.c:494)
> ==469==    by 0x117817: _dl_start (rtld.c:581)
> ==469==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
> ==469== 

It is because valgrind has not been updated to adapt for the newly
introduced statx(fd, NULL, AT_EMPTY_PATH). The related code of valgrind
is at [2].



[1]: https://ci.linaro.org/job/tcwg_glibc_check--master-arm-precommit/2361/artifact/artifacts/artifacts.precommit/notify/mail-body.txt
[2]: https://sourceware.org/git/?p=valgrind.git;a=blob;f=coregrind/m_syswrap/syswrap-linux.c;h=9f3c51c17948378e501f2200be8b141aa13016b6;hb=HEAD#l4211

Cheers,

Miao Wang
Florian Weimer Aug. 26, 2024, 1:39 p.m. UTC | #2
* Miao Wang:

> I've received a notification from patchwork stating this patch caused a
> regression for the test tst-valgrind-smoke [1].
>
>
> I'm able to reproduce this in my working environment, using qemu userspace
> emulation. The output of valgrind is:
>
>> ==469== Syscall param statx(filename) points to unaddressable byte(s)
>> ==469==    at 0x11A536: __libc_do_syscall (libc-do-syscall.S:47)
>> ==469==    by 0x11BAF1: __statx_empty_path (internal-stat.h:47)
>> ==469==    by 0x11BAF1: fstatat64_time64_statx (fstatat64.c:53)
>> ==469==    by 0x11BAF1: __fstatat64_time64 (fstatat64.c:154)
>> ==469==    by 0x10C4EF: _dl_get_file_id (dl-fileid.h:37)
>> ==469==    by 0x10C4EF: _dl_map_object_from_fd (dl-load.c:955)
>> ==469==    by 0x10D0E3: _dl_map_object (dl-load.c:2190)
>> ==469==    by 0x116E39: map_doit (rtld.c:644)
>> ==469==    by 0x108DDF: _dl_catch_exception (dl-catch.c:241)
>> ==469==    by 0x108EAB: _dl_catch_error (dl-catch.c:260)
>> ==469==    by 0x116DE7: do_preload (rtld.c:818)
>> ==469==    by 0x117ACD: handle_preload_list (rtld.c:894)
>> ==469==    by 0x119B0B: dl_main (rtld.c:1849)
>> ==469==    by 0x1167B3: _dl_sysdep_start (dl-sysdep.c:141)
>> ==469==    by 0x117817: _dl_start_final (rtld.c:494)
>> ==469==    by 0x117817: _dl_start (rtld.c:581)
>> ==469==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
>> ==469== 
>
> It is because valgrind has not been updated to adapt for the newly
> introduced statx(fd, NULL, AT_EMPTY_PATH). The related code of valgrind
> is at [2].
>
>
>
> [1]: https://ci.linaro.org/job/tcwg_glibc_check--master-arm-precommit/2361/artifact/artifacts/artifacts.precommit/notify/mail-body.txt
> [2]: https://sourceware.org/git/?p=valgrind.git;a=blob;f=coregrind/m_syswrap/syswrap-linux.c;h=9f3c51c17948378e501f2200be8b141aa13016b6;hb=HEAD#l4211

Would you please raise this as a valgrind issue?

  <https://bugs.kde.org/enter_bug.cgi?product=valgrind>

I think valgrind really needs to be fixed (upstream) before
distributions can upgrade to a glibc version with this change.  The
valgrind test should NOT be disabled, as a reminder that the valgrind
fix needs to be backported as well.

I don't know how easy it is to fix this.  Currently valgrind has this:

   // Work around Rust's dubious use of statx, as described here:
   // https://github.com/rust-lang/rust/blob/
   //    ccd238309f9dce92a05a23c2959e2819668c69a4/
   //    src/libstd/sys/unix/fs.rs#L128-L142
   // in which it passes NULL for both filename and buf, and then looks at the
   // return value, so as to determine whether or not this syscall is supported.
   Bool both_filename_and_buf_are_null = ARG2 == 0 && ARG5 == 0;
   if (!both_filename_and_buf_are_null) {
      PRE_MEM_RASCIIZ( "statx(filename)", ARG2 );
      PRE_MEM_WRITE( "statx(buf)", ARG5, sizeof(struct vki_statx) );
   }

But I think we need some sort of valgrind patch before we can merge this
change into glibc (or at least we'd have to revert it for Fedora
rawhide).

Thanks,
Florian
Miao Wang Aug. 26, 2024, 1:48 p.m. UTC | #3
>> 
>> It is because valgrind has not been updated to adapt for the newly
>> introduced statx(fd, NULL, AT_EMPTY_PATH). The related code of valgrind
>> is at [2].
>> 
>> 
> 
> Would you please raise this as a valgrind issue?
> 

I've sent out a patch for valgrind, but it seems that the patch fails
to reach the mailing list on source forge. Attached is my original patch.
I wonder if someone can send it for me.

Cheers,

Miao Wang 
> 
> Thanks,
> Florian
>
From: Miao Wang <shankerwangmiao@gmail.com>

statx(fd, NULL, AT_EMPTY_PATH) is supported since Linux 6.11 and this
patch addes the support to valgrind, so that it won't complain when
NULL is used as |filename| and |flags| includes AT_EMPTY_PATH.

Ref: commit 0ef625bba6fb ("vfs: support statx(..., NULL, AT_EMPTY_PATH, ...)")

Signed-off-by: Miao Wang <shankerwangmiao@gmail.com>
---
 coregrind/m_syswrap/syswrap-linux.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/coregrind/m_syswrap/syswrap-linux.c b/coregrind/m_syswrap/syswrap-linux.c
index 9f3c51c17..453385599 100644
--- a/coregrind/m_syswrap/syswrap-linux.c
+++ b/coregrind/m_syswrap/syswrap-linux.c
@@ -4209,8 +4209,12 @@ PRE(sys_statx)
    // in which it passes NULL for both filename and buf, and then looks at the
    // return value, so as to determine whether or not this syscall is supported.
    Bool both_filename_and_buf_are_null = ARG2 == 0 && ARG5 == 0;
+   Bool statx_null_path = (ARG2 == 0) && (ARG3 & VKI_AT_EMPTY_PATH);
    if (!both_filename_and_buf_are_null) {
-      PRE_MEM_RASCIIZ( "statx(filename)", ARG2 );
+      // Since Linux 6.11, the kernel allows passing a NULL filename when
+      // the AT_EMPTY_PATH flag is set.
+      if (!statx_null_path)
+         PRE_MEM_RASCIIZ( "statx(filename)", ARG2 );
       PRE_MEM_WRITE( "statx(buf)", ARG5, sizeof(struct vki_statx) );
    }
 }

---
base-commit: 61e44a4aef8775b925a7a91f403ebd7f4f6670a4
change-id: 20240824-statx-null-path-8eec6e0da3bc

Best regards,
Florian Weimer Aug. 26, 2024, 1:53 p.m. UTC | #4
* Miao Wang:

>>> 
>>> It is because valgrind has not been updated to adapt for the newly
>>> introduced statx(fd, NULL, AT_EMPTY_PATH). The related code of valgrind
>>> is at [2].
>>> 
>>> 
>> 
>> Would you please raise this as a valgrind issue?
>> 
>
> I've sent out a patch for valgrind, but it seems that the patch fails
> to reach the mailing list on source forge. Attached is my original patch.
> I wonder if someone can send it for me.

You could attach it to a bug in the valgrind bug tracker:

  <https://bugs.kde.org/enter_bug.cgi?product=valgrind>

Thanks,
Florian
Miao Wang Aug. 26, 2024, 2:15 p.m. UTC | #5
> 2024年8月26日 21:53,Florian Weimer <fweimer@redhat.com> 写道:
> 
> * Miao Wang:
> 
>>>> 
>>>> It is because valgrind has not been updated to adapt for the newly
>>>> introduced statx(fd, NULL, AT_EMPTY_PATH). The related code of valgrind
>>>> is at [2].
>>>> 
>>>> 
>>> 
>>> Would you please raise this as a valgrind issue?
>>> 
>> 
>> I've sent out a patch for valgrind, but it seems that the patch fails
>> to reach the mailing list on source forge. Attached is my original patch.
>> I wonder if someone can send it for me.
> 
> You could attach it to a bug in the valgrind bug tracker:
> 
>  <https://bugs.kde.org/enter_bug.cgi?product=valgrind>

Bug created at https://bugs.kde.org/show_bug.cgi?id=492214

Cheers,

Miao Wang

> 
> Thanks,
> Florian
Adhemerval Zanella Aug. 27, 2024, 6:18 p.m. UTC | #6
On 21/08/24 13:14, Miao Wang via B4 Relay wrote:
> 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 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       |  8 ++++++--
>  sysdeps/unix/sysv/linux/fxstat64.c        |  3 +--
>  sysdeps/unix/sysv/linux/internal-stat.h   | 31 +++++++++++++++++++++++++++++++
>  sysdeps/unix/sysv/linux/kernel-features.h |  5 +++++
>  4 files changed, 43 insertions(+), 4 deletions(-)
> 
> diff --git a/sysdeps/unix/sysv/linux/fstatat64.c b/sysdeps/unix/sysv/linux/fstatat64.c
> index da496177c9..b67a5f4469 100644
> --- a/sysdeps/unix/sysv/linux/fstatat64.c
> +++ b/sysdeps/unix/sysv/linux/fstatat64.c
> @@ -47,8 +47,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;

It fails to build on arc-linux-gnuhf, with a missing '__statx_empty_path'. Add:

diff --git a/sysdeps/unix/sysv/linux/fxstat64.c b/sysdeps/unix/sysv/linux/fxstat64.c
index 2ece683992..1578d55eb4 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>

To fix it.

>  
> diff --git a/sysdeps/unix/sysv/linux/fxstat64.c b/sysdeps/unix/sysv/linux/fxstat64.c
> index 230374cb22..2ece683992 100644
> --- a/sysdeps/unix/sysv/linux/fxstat64.c
> +++ b/sysdeps/unix/sysv/linux/fxstat64.c
> @@ -53,8 +53,7 @@ ___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);
> +  int r = __statx_empty_path (fd, 0, &tmp);
>    if (r == 0)
>      __cp_stat64_statx (buf, &tmp);
>    return r;
> diff --git a/sysdeps/unix/sysv/linux/internal-stat.h b/sysdeps/unix/sysv/linux/internal-stat.h
> index 9334059765..ee30cb1bd6 100644
> --- a/sysdeps/unix/sysv/linux/internal-stat.h
> +++ b/sysdeps/unix/sysv/linux/internal-stat.h
> @@ -29,3 +29,34 @@
>  #else
>  # define FSTATAT_USE_STATX 0
>  #endif
> +
> +#if FSTATAT_USE_STATX || XSTAT_IS_XSTAT64
> +
> +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
> +  static int statx_null_path_supported = -1;
> +  int r;
> +  int supported = atomic_load_relaxed (&statx_null_path_supported);
> +  if (supported != 0)
> +    {
> +      r = INTERNAL_SYSCALL_CALL (statx, fd, NULL, flag, STATX_BASIC_STATS, buf);
> +      if (__glibc_likely (supported == 1))
> +	return r;
> +      if (r != -EFAULT)
> +	{
> +	  if (r == 0)
> +	    atomic_store_relaxed (&statx_null_path_supported, 1);
> +	  return r;
> +	}
> +      atomic_store_relaxed (&statx_null_path_supported, 0);
> +    }
> +  return INTERNAL_SYSCALL_CALL (statx, fd, "", flag, STATX_BASIC_STATS, buf);

I don't think you need a tri-state here, you can assume that it is supported
and set to unsupported once the syscall fails with EFAULT (similar to how we
handle other fallbacks, like mips64 gendents64).

Also, you are replacing a INLINE_SYSCALL_CALL, which sets errno. so you should
follow the same semantic:


  flag |= AT_EMPTY_PATH;
  int r;
#ifdef __ASSUME_STATX_NULL_PATH
  r = INTERNAL_SYSCALL_CALL (statx, fd, NULL, flag, STATX_BASIC_STATS, buf);
#else
  static int statx_null_path_supported = 1;
  if (atomic_load_relaxed (&statx_null_path_supported))
    {
      int r = INTERNAL_SYSCALL_CALL (statx, fd, NULL, flag, STATX_BASIC_STATS, buf);
      if (r == 0 || r != -EFAULT)
	goto out;
      atomic_store_relaxed (&statx_null_path_supported, 0);
    }
  r = INTERNAL_SYSCALL_CALL (statx, fd, "", flag, STATX_BASIC_STATS, buf);
out:
#endif
  return INTERNAL_SYSCALL_ERROR_P (r)
         ? INLINE_SYSCALL_ERROR_RETURN_VALUE (-r)
         : 0;
  

> +#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 Aug. 27, 2024, 7:44 p.m. UTC | #7
> 2024年8月28日 02:18,Adhemerval Zanella Netto <adhemerval.zanella@linaro.org> 写道:
> 
> It fails to build on arc-linux-gnuhf, with a missing '__statx_empty_path'. Add:
> 
> diff --git a/sysdeps/unix/sysv/linux/fxstat64.c b/sysdeps/unix/sysv/linux/fxstat64.c
> index 2ece683992..1578d55eb4 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>
> 
> To fix it.

Many thanks for pointing it out, will be fixed in v3.

> 
>> 
>> diff --git a/sysdeps/unix/sysv/linux/fxstat64.c b/sysdeps/unix/sysv/linux/fxstat64.c
>> index 230374cb22..2ece683992 100644
>> --- a/sysdeps/unix/sysv/linux/fxstat64.c
>> +++ b/sysdeps/unix/sysv/linux/fxstat64.c
>> @@ -53,8 +53,7 @@ ___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);
>> +  int r = __statx_empty_path (fd, 0, &tmp);
>>   if (r == 0)
>>     __cp_stat64_statx (buf, &tmp);
>>   return r;
>> diff --git a/sysdeps/unix/sysv/linux/internal-stat.h b/sysdeps/unix/sysv/linux/internal-stat.h
>> index 9334059765..ee30cb1bd6 100644
>> --- a/sysdeps/unix/sysv/linux/internal-stat.h
>> +++ b/sysdeps/unix/sysv/linux/internal-stat.h
>> @@ -29,3 +29,34 @@
>> #else
>> # define FSTATAT_USE_STATX 0
>> #endif
>> +
>> +#if FSTATAT_USE_STATX || XSTAT_IS_XSTAT64
>> +
>> +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
>> +  static int statx_null_path_supported = -1;
>> +  int r;
>> +  int supported = atomic_load_relaxed (&statx_null_path_supported);
>> +  if (supported != 0)
>> +    {
>> +      r = INTERNAL_SYSCALL_CALL (statx, fd, NULL, flag, STATX_BASIC_STATS, buf);
>> +      if (__glibc_likely (supported == 1))
>> + return r;
>> +      if (r != -EFAULT)
>> + {
>> +   if (r == 0)
>> +     atomic_store_relaxed (&statx_null_path_supported, 1);
>> +   return r;
>> + }
>> +      atomic_store_relaxed (&statx_null_path_supported, 0);
>> +    }
>> +  return INTERNAL_SYSCALL_CALL (statx, fd, "", flag, STATX_BASIC_STATS, buf);
> 
> I don't think you need a tri-state here, you can assume that it is supported
> and set to unsupported once the syscall fails with EFAULT (similar to how we
> handle other fallbacks, like mips64 gendents64).

Tri-state here is needed to prevent generating data barrier instructions after
whether it is supported is finally decided. Will improve this in v3.

> 
> Also, you are replacing a INLINE_SYSCALL_CALL, which sets errno. so you should
> follow the same semantic:
> 
> 
>  flag |= AT_EMPTY_PATH;
>  int r;
> #ifdef __ASSUME_STATX_NULL_PATH
>  r = INTERNAL_SYSCALL_CALL (statx, fd, NULL, flag, STATX_BASIC_STATS, buf);
> #else
>  static int statx_null_path_supported = 1;
>  if (atomic_load_relaxed (&statx_null_path_supported))
>    {
>      int r = INTERNAL_SYSCALL_CALL (statx, fd, NULL, flag, STATX_BASIC_STATS, buf);
>      if (r == 0 || r != -EFAULT)
> goto out;
>      atomic_store_relaxed (&statx_null_path_supported, 0);
>    }
>  r = INTERNAL_SYSCALL_CALL (statx, fd, "", flag, STATX_BASIC_STATS, buf);
> out:
> #endif
>  return INTERNAL_SYSCALL_ERROR_P (r)
>         ? INLINE_SYSCALL_ERROR_RETURN_VALUE (-r)
>         : 0;
> 

This will be fixed in fxstat64.c in v3, since the replaced statement is
INTERNAL_SYSCALL_CALL in fstatat64.c

Cheers,

Miao Wang
diff mbox series

Patch

diff --git a/sysdeps/unix/sysv/linux/fstatat64.c b/sysdeps/unix/sysv/linux/fstatat64.c
index da496177c9..b67a5f4469 100644
--- a/sysdeps/unix/sysv/linux/fstatat64.c
+++ b/sysdeps/unix/sysv/linux/fstatat64.c
@@ -47,8 +47,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..2ece683992 100644
--- a/sysdeps/unix/sysv/linux/fxstat64.c
+++ b/sysdeps/unix/sysv/linux/fxstat64.c
@@ -53,8 +53,7 @@  ___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);
+  int r = __statx_empty_path (fd, 0, &tmp);
   if (r == 0)
     __cp_stat64_statx (buf, &tmp);
   return r;
diff --git a/sysdeps/unix/sysv/linux/internal-stat.h b/sysdeps/unix/sysv/linux/internal-stat.h
index 9334059765..ee30cb1bd6 100644
--- a/sysdeps/unix/sysv/linux/internal-stat.h
+++ b/sysdeps/unix/sysv/linux/internal-stat.h
@@ -29,3 +29,34 @@ 
 #else
 # define FSTATAT_USE_STATX 0
 #endif
+
+#if FSTATAT_USE_STATX || XSTAT_IS_XSTAT64
+
+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
+  static int statx_null_path_supported = -1;
+  int r;
+  int supported = atomic_load_relaxed (&statx_null_path_supported);
+  if (supported != 0)
+    {
+      r = INTERNAL_SYSCALL_CALL (statx, fd, NULL, flag, STATX_BASIC_STATS, buf);
+      if (__glibc_likely (supported == 1))
+	return r;
+      if (r != -EFAULT)
+	{
+	  if (r == 0)
+	    atomic_store_relaxed (&statx_null_path_supported, 1);
+	  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 */