[RFC PATCH 1/3] fs: add filename_utimensat()

From: Méven Car

Date: Fri Oct 30 2026 - 08:45:10 EST


Copy utilities that preserve timestamps, like cp -p or a file manager,
set the times of every copy after its last write. To do that through
io_uring, the request needs the utimensat() lookup on a name that was
imported at submission time.

io_uring takes the path of a request when it is submitted and looks it
up later, from a worker thread. The path ops it already has call the
filename_*() helpers of fs/namei.c with a struct filename. utimensat(2)
had no such helper: do_utimes_path() took the user pointer and imported
the name itself.

Split the lookup and the vfs_utimes() call out of do_utimes_path() into
filename_utimensat(), declared in fs/internal.h next to the other
filename_*() helpers. do_utimes_path() now only imports the name.

Signed-off-by: Méven Car <meven@xxxxxxx>
---
fs/internal.h | 2 ++
fs/utimes.c | 12 +++++++++---
2 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/fs/internal.h b/fs/internal.h
index c658c8a5ebd5..985b2bc5895e 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -63,6 +63,8 @@ int filename_mknodat(int dfd, struct filename *name, umode_t mode, unsigned int
int filename_symlinkat(struct filename *from, int newdfd, struct filename *to);
int filename_linkat(int olddfd, struct filename *old, int newdfd,
struct filename *new, int flags);
+int filename_utimensat(int dfd, struct filename *name,
+ struct timespec64 *times, int flags);
int vfs_tmpfile(struct mnt_idmap *idmap,
const struct path *parentpath,
struct file *file, umode_t mode);
diff --git a/fs/utimes.c b/fs/utimes.c
index e22664e4115f..8072f05ac8dc 100644
--- a/fs/utimes.c
+++ b/fs/utimes.c
@@ -79,8 +79,8 @@ int vfs_utimes(const struct path *path, struct timespec64 *times)
}
EXPORT_SYMBOL_GPL(vfs_utimes);

-static int do_utimes_path(int dfd, const char __user *filename,
- struct timespec64 *times, int flags)
+int filename_utimensat(int dfd, struct filename *name,
+ struct timespec64 *times, int flags)
{
struct path path;
int lookup_flags = 0, error;
@@ -91,7 +91,6 @@ static int do_utimes_path(int dfd, const char __user *filename,
if (!(flags & AT_SYMLINK_NOFOLLOW))
lookup_flags |= LOOKUP_FOLLOW;

- CLASS(filename_uflags, name)(filename, flags);
retry:
error = filename_lookup(dfd, name, lookup_flags, &path, NULL);
if (error)
@@ -105,6 +104,13 @@ static int do_utimes_path(int dfd, const char __user *filename,
return error;
}

+static int do_utimes_path(int dfd, const char __user *filename,
+ struct timespec64 *times, int flags)
+{
+ CLASS(filename_uflags, name)(filename, flags);
+ return filename_utimensat(dfd, name, times, flags);
+}
+
static int do_utimes_fd(int fd, struct timespec64 *times, int flags)
{
if (flags)
--
2.56.0