From: Miao Wang via B4 Relay <devnull+shankerwangmiao.gmail.com@kernel.org>
To: Greg Kroah-Hartman <gregkh@linuxfoundation.org>, stable@vger.kernel.org
Cc: Xi Ruoyao <xry111@xry111.site>, Mateusz Guzik <mjguzik@gmail.com>,
Christian Brauner <brauner@kernel.org>,
Alexander Viro <viro@zeniv.linux.org.uk>,
linux-fsdevel@vger.kernel.org, stable@vger.kernel.org,
Miao Wang <shankerwangmiao@gmail.com>
Subject: [PATCH v5.15-v5.10 4/4] vfs: support statx(..., NULL, AT_EMPTY_PATH, ...)
Date: Wed, 18 Sep 2024 22:10:40 +0800 [thread overview]
Message-ID: <20240918-statx-stable-linux-5-15-y-v1-4-5afb4401ddbe@gmail.com> (raw)
In-Reply-To: <20240918-statx-stable-linux-5-15-y-v1-0-5afb4401ddbe@gmail.com>
From: Mateusz Guzik <mjguzik@gmail.com>
commit 0ef625b upstream.
The newly used helper also checks for empty ("") paths.
NULL paths with any flag value other than AT_EMPTY_PATH go the usual
route and end up with -EFAULT to retain compatibility (Rust is abusing
calls of the sort to detect availability of statx).
This avoids path lookup code, lockref management, memory allocation and
in case of NULL path userspace memory access (which can be quite
expensive with SMAP on x86_64).
Benchmarked with statx(..., AT_EMPTY_PATH, ...) running on Sapphire
Rapids, with the "" path for the first two cases and NULL for the last
one.
Results in ops/s:
stock: 4231237
pre-check: 5944063 (+40%)
NULL path: 6601619 (+11%/+56%)
Signed-off-by: Mateusz Guzik <mjguzik@gmail.com>
Link: https://lore.kernel.org/r/20240625151807.620812-1-mjguzik@gmail.com
Tested-by: Xi Ruoyao <xry111@xry111.site>
[brauner: use path_mounted() and other tweaks]
Signed-off-by: Christian Brauner <brauner@kernel.org>
Cc: <stable@vger.kernel.org> # 5.10.x-5.15.x
Signed-off-by: Miao Wang <shankerwangmiao@gmail.com>
Tested-by: Xi Ruoyao <xry111@xry111.site>
---
fs/stat.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++------------
1 file changed, 52 insertions(+), 12 deletions(-)
diff --git a/fs/stat.c b/fs/stat.c
index b8faa3f4b046..f02361a2ae54 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -184,6 +184,37 @@ int vfs_fstat(int fd, struct kstat *stat)
return error;
}
+static int vfs_statx_path(struct path *path, int flags, struct kstat *stat,
+ u32 request_mask)
+{
+ int error = vfs_getattr(path, stat, request_mask, flags);
+
+ stat->mnt_id = real_mount(path->mnt)->mnt_id;
+ stat->result_mask |= STATX_MNT_ID;
+ if (path->mnt->mnt_root == path->dentry)
+ stat->attributes |= STATX_ATTR_MOUNT_ROOT;
+ stat->attributes_mask |= STATX_ATTR_MOUNT_ROOT;
+
+ return error;
+}
+
+static int vfs_statx_fd(int fd, int flags, struct kstat *stat,
+ u32 request_mask)
+{
+ int rc;
+ struct fd f = fdget_raw(fd);
+
+ if (!f.file) {
+ rc = -EBADF;
+ goto err;
+ }
+ rc = vfs_statx_path(&f.file->f_path, flags, stat, request_mask);
+
+err:
+ fdput(f);
+ return rc;
+}
+
/**
* vfs_statx - Get basic and extra attributes by filename
* @dfd: A file descriptor representing the base dir for a relative filename
@@ -220,20 +251,13 @@ static int vfs_statx(int dfd, const char __user *filename, int flags,
retry:
error = user_path_at(dfd, filename, lookup_flags, &path);
if (error)
- goto out;
-
- error = vfs_getattr(&path, stat, request_mask, flags);
- stat->mnt_id = real_mount(path.mnt)->mnt_id;
- stat->result_mask |= STATX_MNT_ID;
- if (path.mnt->mnt_root == path.dentry)
- stat->attributes |= STATX_ATTR_MOUNT_ROOT;
- stat->attributes_mask |= STATX_ATTR_MOUNT_ROOT;
+ return error;
+ error = vfs_statx_path(&path, flags, stat, request_mask);
path_put(&path);
if (retry_estale(error, lookup_flags)) {
lookup_flags |= LOOKUP_REVAL;
goto retry;
}
-out:
return error;
}
@@ -615,13 +639,28 @@ int do_statx(int dfd, const char __user *filename, unsigned flags,
{
struct kstat stat;
int error;
+ unsigned lflags;
if (mask & STATX__RESERVED)
return -EINVAL;
if ((flags & AT_STATX_SYNC_TYPE) == AT_STATX_SYNC_TYPE)
return -EINVAL;
- error = vfs_statx(dfd, filename, flags, &stat, mask);
+ /*
+ * Short-circuit handling of NULL and "" paths.
+ *
+ * For a NULL path we require and accept only the AT_EMPTY_PATH flag
+ * (possibly |'d with AT_STATX flags).
+ *
+ * However, glibc on 32-bit architectures implements fstatat as statx
+ * with the "" pathname and AT_NO_AUTOMOUNT | AT_EMPTY_PATH flags.
+ * Supporting this results in the uglification below.
+ */
+ lflags = flags & ~(AT_NO_AUTOMOUNT | AT_STATX_SYNC_TYPE);
+ if (lflags == AT_EMPTY_PATH && vfs_empty_path(dfd, filename))
+ error = vfs_statx_fd(dfd, flags & ~AT_NO_AUTOMOUNT, &stat, mask);
+ else
+ error = vfs_statx(dfd, filename, flags, &stat, mask);
if (error)
return error;
@@ -631,13 +670,14 @@ int do_statx(int dfd, const char __user *filename, unsigned flags,
/**
* sys_statx - System call to get enhanced stats
* @dfd: Base directory to pathwalk from *or* fd to stat.
- * @filename: File to stat or "" with AT_EMPTY_PATH
+ * @filename: File to stat or either NULL or "" with AT_EMPTY_PATH
* @flags: AT_* flags to control pathwalk.
* @mask: Parts of statx struct actually required.
* @buffer: Result buffer.
*
* Note that fstat() can be emulated by setting dfd to the fd of interest,
- * supplying "" as the filename and setting AT_EMPTY_PATH in the flags.
+ * supplying "" (or preferably NULL) as the filename and setting AT_EMPTY_PATH
+ * in the flags.
*/
SYSCALL_DEFINE5(statx,
int, dfd, const char __user *, filename, unsigned, flags,
--
2.43.0
prev parent reply other threads:[~2024-09-18 14:10 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-09-18 14:10 [PATCH 0/4] Backport statx(..., NULL, AT_EMPTY_PATH, ...) Miao Wang via B4 Relay
2024-09-18 14:10 ` [PATCH v5.15-v5.10 1/4] vfs: mostly undo glibc turning 'fstat()' into 'fstatat(AT_EMPTY_PATH)' Miao Wang via B4 Relay
2024-09-18 14:10 ` [PATCH v5.15-v5.10 2/4] fs: new helper vfs_empty_path() Miao Wang via B4 Relay
2024-09-18 14:10 ` [PATCH v5.15-v5.10 3/4] stat: use vfs_empty_path() helper Miao Wang via B4 Relay
2024-09-18 14:10 ` Miao Wang via B4 Relay [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240918-statx-stable-linux-5-15-y-v1-4-5afb4401ddbe@gmail.com \
--to=devnull+shankerwangmiao.gmail.com@kernel.org \
--cc=brauner@kernel.org \
--cc=gregkh@linuxfoundation.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=mjguzik@gmail.com \
--cc=shankerwangmiao@gmail.com \
--cc=stable@vger.kernel.org \
--cc=viro@zeniv.linux.org.uk \
--cc=xry111@xry111.site \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).