diff mbox series

LoongArch: Add fstat64 and fstatat64.

Message ID 20240912080328.166693-2-caiyinyu@loongson.cn
State New
Headers show
Series LoongArch: Add fstat64 and fstatat64. | expand

Commit Message

caiyinyu Sept. 12, 2024, 8:03 a.m. UTC
In Linux 6.11, the fstat (80) and newfstatat (79) syscalls have been
reintroduced. The definitions of these two syscalls have already been
backported to version 6.10.6 in the stable tree.

In this patch, we are adding dynamically probed implementations of
fstat64 and fstatat64 specifically for syscalls 79 and 80. This ensures
compatibility while maintaining relatively good performance on kernels
that both support and do not support syscalls 79 and 80.

By running an experiment where we invoke fstat64 and fstatat64 100
million times, we gathered the following efficiency statistics:

1. On kernels that support syscalls 79 and 80 (tested on version
   6.10.6), fstat64 and fstatat64 can directly invoke these syscalls
   [1]. The time overhead of our dynamic probing implementation
   increased by 0.5%-2.5% compared to directly calling the syscalls.
2. On kernels that support syscalls 79 and 80 (tested on version
   6.10.6), our dynamically probed implementation reduces the time
   overhead by more than 60% compared to directly invoking the statx
   (291) syscall.
3. On kernels that do not support syscalls 79 and 80 (tested on version
   6.8.0), fstat64 and fstatat64 fall back to using the statx (291)
   syscall (as before). In this case, the overhead of our dynamic
   probing implementation increased by 0.1%-1.3% compared to directly
   invoking statx.

[1][PATCH v5] Loongarch: adapt for the re-introduction of fstat and newfstatat in 6.10.6
https://sourceware.org/pipermail/libc-alpha/2024-August/159469.html

Signed-off-by: caiyinyu <caiyinyu@loongson.cn>
Reviewed-by: Xi Ruoyao <xry111@xry111.site>
Reviewed-by: Miao Wang <shankerwangmiao@gmail.com>

Changes in V2:
- Use __LINUX_KERNEL_VERSION to determine whether to use dynamic probing
  if the kernel version is high enough.

Link to v1: https://sourceware.org/pipermail/libc-alpha/2024-September/159862.html

---
 sysdeps/unix/sysv/linux/loongarch/fstat64.c   | 64 +++++++++++++++++++
 sysdeps/unix/sysv/linux/loongarch/fstatat64.c | 59 +++++++++++++++++
 .../linux/loongarch/fstatat64_time64_statx.h  | 54 ++++++++++++++++
 3 files changed, 177 insertions(+)
 create mode 100644 sysdeps/unix/sysv/linux/loongarch/fstat64.c
 create mode 100644 sysdeps/unix/sysv/linux/loongarch/fstatat64.c
 create mode 100644 sysdeps/unix/sysv/linux/loongarch/fstatat64_time64_statx.h
diff mbox series

Patch

diff --git a/sysdeps/unix/sysv/linux/loongarch/fstat64.c b/sysdeps/unix/sysv/linux/loongarch/fstat64.c
new file mode 100644
index 0000000000..7bcb04a628
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/loongarch/fstat64.c
@@ -0,0 +1,64 @@ 
+/* Get file status.  LoongArch version.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#if __LINUX_KERNEL_VERSION >= 0x060a06 || !defined(__loongarch_lp64)
+#include "../fstat64.c"
+#else
+#define __fstat __redirect___fstat
+#define fstat   __redirect_fstat
+#include <sys/stat.h>
+#undef __fstat
+#undef fstat
+
+#include "fstatat64_time64_statx.h"
+
+static int __fstat_syscall_supported = 1;
+
+int
+__fstat64 (int fd, struct __stat64_t64 *buf)
+{
+  int r;
+  int supported = atomic_load_relaxed (&__fstat_syscall_supported);
+  if (supported)
+  {
+    r = INTERNAL_SYSCALL_CALL (fstat, fd, buf);
+    if (r == 0)
+      return r;
+    else if (r != -ENOSYS)
+      return INLINE_SYSCALL_ERROR_RETURN_VALUE (-r);
+
+    atomic_store_relaxed (&__fstat_syscall_supported, 0);
+  }
+
+  if (fd < 0)
+  {
+    __set_errno (EBADF);
+    return -1;
+  }
+
+  r = fstatat64_time64_statx (fd, "", buf, AT_EMPTY_PATH);
+  return INTERNAL_SYSCALL_ERROR_P (r)
+    ? INLINE_SYSCALL_ERROR_RETURN_VALUE (-r)
+    : 0;
+}
+
+hidden_def (__fstat64)
+weak_alias (__fstat64, fstat64)
+strong_alias (__fstat64, __fstat)
+weak_alias (__fstat64, fstat)
+#endif
diff --git a/sysdeps/unix/sysv/linux/loongarch/fstatat64.c b/sysdeps/unix/sysv/linux/loongarch/fstatat64.c
new file mode 100644
index 0000000000..a45d23558d
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/loongarch/fstatat64.c
@@ -0,0 +1,59 @@ 
+/* Get file status.  LoongArch version.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#if __LINUX_KERNEL_VERSION >= 0x060a06 || !defined(__loongarch_lp64)
+#include "../fstatat64.c"
+#else
+#define __fstatat __redirect___fstatat
+#define fstatat   __redirect_fstatat
+#include <sys/stat.h>
+#undef __fstatat
+#undef fstatat
+
+#include "fstatat64_time64_statx.h"
+
+static int __newfstatat_syscall_supported = 1;
+
+int
+__fstatat64 (int fd, const char *file, struct __stat64_t64 *buf,
+		    int flag)
+{
+  int r;
+  int supported = atomic_load_relaxed (&__newfstatat_syscall_supported);
+  if (supported)
+  {
+    r = INTERNAL_SYSCALL_CALL (newfstatat, fd, file, buf, flag);
+    if (r == 0)
+      return r;
+    else if (r != -ENOSYS)
+      return INLINE_SYSCALL_ERROR_RETURN_VALUE (-r);
+    atomic_store_relaxed (&__newfstatat_syscall_supported, 0);
+  }
+
+  r = fstatat64_time64_statx (fd, file, buf, flag);
+  return INTERNAL_SYSCALL_ERROR_P (r)
+	 ? INLINE_SYSCALL_ERROR_RETURN_VALUE (-r)
+	 : 0;
+}
+
+hidden_def (__fstatat64)
+weak_alias (__fstatat64, fstatat64)
+strong_alias (__fstatat64, __fstatat)
+weak_alias (__fstatat64, fstatat)
+strong_alias (__fstatat64, __GI___fstatat);
+#endif
diff --git a/sysdeps/unix/sysv/linux/loongarch/fstatat64_time64_statx.h b/sysdeps/unix/sysv/linux/loongarch/fstatat64_time64_statx.h
new file mode 100644
index 0000000000..97920a820f
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/loongarch/fstatat64_time64_statx.h
@@ -0,0 +1,54 @@ 
+/* Get file status.  LoongArch version.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <fcntl.h>
+#include <sys/sysmacros.h>
+#include <internal-stat.h>
+
+static inline int
+fstatat64_time64_statx (int fd, const char *file, struct __stat64_t64 *buf,
+			int flag)
+{
+  struct statx tmp;
+  int r = INTERNAL_SYSCALL_CALL (statx, fd, file, AT_NO_AUTOMOUNT | flag,
+				 STATX_BASIC_STATS, &tmp);
+  if (r != 0)
+    return r;
+
+  *buf = (struct __stat64_t64)
+  {
+    .st_dev = __gnu_dev_makedev (tmp.stx_dev_major, tmp.stx_dev_minor),
+    .st_rdev = __gnu_dev_makedev (tmp.stx_rdev_major, tmp.stx_rdev_minor),
+    .st_ino = tmp.stx_ino,
+    .st_mode = tmp.stx_mode,
+    .st_nlink = tmp.stx_nlink,
+    .st_uid = tmp.stx_uid,
+    .st_gid = tmp.stx_gid,
+    .st_atime = tmp.stx_atime.tv_sec,
+    .st_atim.tv_nsec = tmp.stx_atime.tv_nsec,
+    .st_mtime = tmp.stx_mtime.tv_sec,
+    .st_mtim.tv_nsec = tmp.stx_mtime.tv_nsec,
+    .st_ctime = tmp.stx_ctime.tv_sec,
+    .st_ctim.tv_nsec = tmp.stx_ctime.tv_nsec,
+    .st_size = tmp.stx_size,
+    .st_blocks = tmp.stx_blocks,
+    .st_blksize = tmp.stx_blksize,
+  };
+
+  return r;
+}