@@ -105,11 +105,14 @@ cfg_has_statx! {{
105105        flags:  i32 , 
106106        mask:  u32 , 
107107    )  -> Option <io:: Result <FileAttr >> { 
108-         use  crate :: sync:: atomic:: { AtomicBool ,  Ordering } ; 
108+         use  crate :: sync:: atomic:: { AtomicU8 ,  Ordering } ; 
109109
110110        // Linux kernel prior to 4.11 or glibc prior to glibc 2.28 don't support `statx` 
111-         // We store the availability in a global to avoid unnecessary syscalls 
112-         static  HAS_STATX :  AtomicBool  = AtomicBool :: new( true ) ; 
111+         // We store the availability in global to avoid unnecessary syscalls. 
112+         // 0: Unknown 
113+         // 1: Not available 
114+         // 2: Available 
115+         static  STATX_STATE :  AtomicU8  = AtomicU8 :: new( 0 ) ; 
113116        syscall! { 
114117            fn  statx( 
115118                fd:  c_int, 
@@ -120,21 +123,36 @@ cfg_has_statx! {{
120123            )  -> c_int
121124        } 
122125
123-         if  !HAS_STATX . load( Ordering :: Relaxed )  { 
124-             return  None ; 
125-         } 
126- 
127-         let  mut  buf:  libc:: statx = mem:: zeroed( ) ; 
128-         let  ret = cvt( statx( fd,  path,  flags,  mask,  & mut  buf) ) ; 
129-         match  ret { 
130-             Err ( err)  => match  err. raw_os_error( )  { 
131-                 Some ( libc:: ENOSYS )  => { 
132-                     HAS_STATX . store( false ,  Ordering :: Relaxed ) ; 
133-                     return  None ; 
126+         match  STATX_STATE . load( Ordering :: Relaxed )  { 
127+             // For the first time, we try to call on current working directory 
128+             // to check if it is available. 
129+             0  => { 
130+                 let  mut  buf:  libc:: statx = mem:: zeroed( ) ; 
131+                 let  err = cvt( statx( 
132+                     libc:: AT_FDCWD , 
133+                     b".\0 " . as_ptr( ) . cast( ) , 
134+                     0 , 
135+                     libc:: STATX_ALL , 
136+                     & mut  buf, 
137+                 ) ) 
138+                     . err( ) 
139+                     . and_then( |e| e. raw_os_error( ) ) ; 
140+                 // `seccomp` will emit `EPERM` on denied syscall. 
141+                 // See: https://github.com/rust-lang/rust/issues/65662 
142+                 if  err == Some ( libc:: ENOSYS )  || err == Some ( libc:: EPERM )  { 
143+                     STATX_STATE . store( 1 ,  Ordering :: Relaxed ) ; 
144+                 }  else { 
145+                     STATX_STATE . store( 2 ,  Ordering :: Relaxed ) ; 
134146                } 
135-                 _ =>  return   Some ( Err ( err ) ) , 
147+                 try_statx ( fd ,  path ,  flags ,  mask ) 
136148            } 
137-             Ok ( _)  => { 
149+             1  => None , 
150+             _ => { 
151+                 let  mut  buf:  libc:: statx = mem:: zeroed( ) ; 
152+                 if  let  Err ( err)  = cvt( statx( fd,  path,  flags,  mask,  & mut  buf) )  { 
153+                     return  Some ( Err ( err) ) ; 
154+                 } 
155+ 
138156                // We cannot fill `stat64` exhaustively because of private padding fields. 
139157                let  mut  stat:  stat64 = mem:: zeroed( ) ; 
140158                // `c_ulong` on gnu-mips, `dev_t` otherwise 
0 commit comments