[RFC PATCH 0/3] io_uring: add IORING_OP_UTIMENSAT
From: Méven Car
Date: Fri Oct 30 2026 - 08:40:44 EST
A file manager or cp -p that copies many files sets the times of every
copy after its last write. KDE's KIO does not use io_uring yet, but
could in the future. In a KIO prototype that copies batches of small
files through io_uring, open, create, read and write run in the ring,
but the metadata of each copy is set outside the ring, with futimens()
and, when needed, fchmod() and fchown(). On NFS and SMB each of these
calls is a round trip to the server.
In that prototype, setting the metadata from a pool of 16 threads
instead of one file at a time cut the copy of 200 files of 4 KiB by 22%
on NFS and 45% on SMB. The test copied from ext4 to an NFS 4.2 and an
SMB mount of the same machine, over loopback with a netem delay of 2 ms
each way. An opcode would give the same parallelism from the ring, and
would let a copy be one linked chain per file: WRITE, UTIMENSAT, CLOSE.
Patch 1 splits filename_utimensat() out of do_utimes_path(), so that
io_uring can pass a name imported at submission time, as it does for
mkdirat and the other path ops.
Patch 2 adds IORING_OP_UTIMENSAT with the semantics of utimensat(2).
Like the other path ops it runs from io-wq.
Patch 3 is the RFC part. On a local filesystem the handoff to io-wq
costs more than the setattr: in a qemu guest on v7.2.3, setting the
times of 2000 files on tmpfs took 6-8 ms with utimensat(2) and 19-29 ms
through the ring with patch 2 alone, 32 requests per submit. The patch
tries the request inline with LOOKUP_CACHED and trylocks, on filesystems
that declare FS_SETATTR_TIMES_NOWAIT, which only tmpfs sets. The ring
then matches the syscall (6.4-6.8 ms). ext4, xfs and btrfs cannot set
the flag, because their ->setattr() starts a journal transaction. Is a
per-filesystem flag acceptable here, or would you rather keep patch 2
alone?
IORING_OP_FCHMOD was proposed in 2024 [1] and not merged. The same
questions apply to fchmod and fchown, which a copy also needs, and a
single setattr opcode could set the mode, owner and times in one
->setattr() call. I started with the times because a copy always sets
them.
Testing: a userspace test of 28 cases (paths, AT_EMPTY_PATH on O_PATH
fds, NULL path, UTIME_OMIT, permission and read-only errors, links, copy
at submission, inline on tmpfs and punt on ramfs) passes in a qemu
guest, on v7.2.3 and on for-7.4/io_uring. A liburing helper, test and
man page will follow if the interface is acceptable.
[1] https://lore.kernel.org/io-uring/e291085644e14b3eb4d1c3995098bf4e@xxxxxxxxxx/
Méven Car (3):
fs: add filename_utimensat()
io_uring: add support for utimensat
io_uring: set times inline when the filesystem cannot sleep
fs/internal.h | 3 +
fs/namespace.c | 20 +++++++
fs/utimes.c | 56 ++++++++++++++----
include/linux/fs.h | 1 +
include/uapi/linux/io_uring.h | 2 +
io_uring/fs.c | 105 ++++++++++++++++++++++++++++++++++
io_uring/fs.h | 4 ++
io_uring/opdef.c | 8 +++
mm/shmem.c | 3 +-
9 files changed, 191 insertions(+), 11 deletions(-)
base-commit: ecb6817b769fd7d71af2c9f446188649020b2e53
--
2.56.0