From 6c7ced1f010488c2afcd0a9e7e013bf787dc6b58 Mon Sep 17 00:00:00 2001 From: Augustin Cavalier Date: Fri, 28 Jun 2024 16:31:54 -0400 Subject: [PATCH] kernel/fs: Try to use real vectored I/O in common_vector_io. We can only do this if the underlying I/O will not be cached, since the I/O hook bypasses any cache. But that should be fine, as in the event that reads and writes are going through the file cache, calling read and write multiple times isn't especially expensive. On the other hand, when the underlying device is not a file or something else cache-backed, making many I/O calls instead of just one can be very expensive. The BFS journal flush seems to routinely call writev() with over 100 iovecs on a regular basis during high disk activity, and doing 100+ separate writes to an external drive vs. just one makes a big difference. Should help with #15585. Change-Id: I433e9d9948634f8cdccf7999710c6c5e6b6c8850 Reviewed-on: https://review.haiku-os.org/c/haiku/+/7824 Reviewed-by: Adrien Destugues Reviewed-by: waddlesplash Tested-by: Commit checker robot --- src/system/kernel/fs/fd.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/system/kernel/fs/fd.cpp b/src/system/kernel/fs/fd.cpp index d19ab6f951..d85450c99e 100644 --- a/src/system/kernel/fs/fd.cpp +++ b/src/system/kernel/fs/fd.cpp @@ -29,6 +29,7 @@ #include #include +#include "Vnode.h" #include "vfs_tracing.h" @@ -722,7 +723,30 @@ common_vector_io(int fd, off_t pos, const iovec* vecs, size_t count, bool write, return B_BAD_VALUE; } + // See if we can bypass the loop and perform I/O directly. We can only do this + // for vnodes that have no cache, as the I/O hook bypasses the cache entirely. + struct vnode* vnode = descriptor->u.vnode; status_t status = B_OK; + if (!movePosition && pos != -1 && count > 1 && descriptor->type == FDTYPE_FILE + && vnode != NULL && vnode->cache == NULL && vnode->ops->io != NULL) { + BStackOrHeapArray iovecs(count); + if (!iovecs.IsValid()) + return B_NO_MEMORY; + + generic_size_t length = 0; + for (size_t i = 0; i < count; i++) { + iovecs[i].base = (generic_addr_t)vecs[i].iov_base; + iovecs[i].length = vecs[i].iov_len; + length += vecs[i].iov_len; + } + + status = (write ? vfs_write_pages : vfs_read_pages)(vnode, + descriptor->cookie, pos, iovecs, count, 0, &length); + if (length > 0) + return length; + return status; + } + ssize_t bytesTransferred = 0; for (size_t i = 0; i < count; i++) { if (vecs[i].iov_base == NULL)