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 <[email protected]>
Reviewed-by: waddlesplash <[email protected]>
Tested-by: Commit checker robot <[email protected]>
This commit is contained in:
Augustin Cavalier
2024-07-08 15:51:13 +00:00
committed by waddlesplash
parent cf638bb14b
commit 6c7ced1f01
+24
View File
@@ -29,6 +29,7 @@
#include <vfs.h>
#include <wait_for_objects.h>
#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<generic_io_vec, 8> 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)