diff --git a/src/system/kernel/fs/fd.cpp b/src/system/kernel/fs/fd.cpp index 3a660e60f6..b49e1f02da 100644 --- a/src/system/kernel/fs/fd.cpp +++ b/src/system/kernel/fs/fd.cpp @@ -29,7 +29,6 @@ #include #include -#include "Vnode.h" #include "vfs_tracing.h" @@ -709,30 +708,22 @@ 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 && fd_is_file(descriptor.Get()) - && 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; + if (!movePosition && count > 1 && (write ? descriptor->ops->fd_writev != NULL + : descriptor->ops->fd_readv != NULL)) { + ssize_t result; + if (write) { + result = descriptor->ops->fd_writev(descriptor.Get(), pos, + vecs, count); + } else { + result = descriptor->ops->fd_readv(descriptor.Get(), pos, + vecs, count); } - - status = (write ? vfs_write_pages : vfs_read_pages)(vnode, - descriptor->cookie, pos, iovecs, count, 0, &length); - if (length > 0) - return length; - return status; + if (result != B_UNSUPPORTED) + return result; + // If not supported, just fall back to the loop. } + status_t status = B_OK; ssize_t bytesTransferred = 0; for (size_t i = 0; i < count; i++) { if (vecs[i].iov_base == NULL) @@ -743,8 +734,8 @@ common_vector_io(int fd, off_t pos, const iovec* vecs, size_t count, bool write, status = descriptor->ops->fd_write(descriptor.Get(), pos, vecs[i].iov_base, &length); } else { - status = descriptor->ops->fd_read(descriptor.Get(), pos, vecs[i].iov_base, - &length); + status = descriptor->ops->fd_read(descriptor.Get(), pos, + vecs[i].iov_base, &length); } if (status != B_OK) { diff --git a/src/system/kernel/fs/vfs.cpp b/src/system/kernel/fs/vfs.cpp index 8cfc38a43e..f5d681dcde 100644 --- a/src/system/kernel/fs/vfs.cpp +++ b/src/system/kernel/fs/vfs.cpp @@ -358,6 +358,10 @@ static status_t file_read(struct file_descriptor* descriptor, off_t pos, void* buffer, size_t* _bytes); static status_t file_write(struct file_descriptor* descriptor, off_t pos, const void* buffer, size_t* _bytes); +static ssize_t file_readv(struct file_descriptor* descriptor, off_t pos, + const struct iovec *vecs, int count); +static ssize_t file_writev(struct file_descriptor* descriptor, off_t pos, + const struct iovec *vecs, int count); static off_t file_seek(struct file_descriptor* descriptor, off_t pos, int seekType); static void file_free_fd(struct file_descriptor* descriptor); @@ -435,8 +439,8 @@ static struct fd_ops sFileOps = { file_free_fd, file_read, file_write, - NULL, // readv() - NULL, // writev() + file_readv, + file_writev, file_seek, common_ioctl, NULL, // set_flags() @@ -5725,6 +5729,63 @@ file_write(struct file_descriptor* descriptor, off_t pos, const void* buffer, } +static ssize_t +file_vector_io(struct file_descriptor* descriptor, off_t pos, + const struct iovec *vecs, int count, bool write) +{ + struct vnode* vnode = descriptor->u.vnode; + if (pos != -1 && descriptor->pos == -1) + return ESPIPE; + if (S_ISDIR(vnode->Type())) + return B_IS_A_DIRECTORY; + + if (pos == -1) + return B_UNSUPPORTED; + if (!HAS_FS_CALL(vnode, io)) + return B_UNSUPPORTED; + + // We can only perform real vectored I/O for vnodes that have no cache, + // because the I/O hook bypasses the cache entirely. + if (vnode->cache != NULL) + return B_UNSUPPORTED; + + BStackOrHeapArray iovecs(count); + if (!iovecs.IsValid()) + return B_NO_MEMORY; + + generic_size_t length = 0; + for (int 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_t status = (write ? vfs_write_pages : vfs_read_pages)(vnode, + descriptor->cookie, pos, iovecs, count, 0, &length); + if (length > 0) + return length; + return status; +} + + +static ssize_t +file_readv(struct file_descriptor* descriptor, off_t pos, + const struct iovec *vecs, int count) +{ + FUNCTION(("file_readv: pos %" B_PRIdOFF "\n", pos)); + return file_vector_io(descriptor, pos, vecs, count, false); +} + + +static ssize_t +file_writev(struct file_descriptor* descriptor, off_t pos, + const struct iovec *vecs, int count) +{ + FUNCTION(("file_writev: pos %" B_PRIdOFF "\n", pos)); + return file_vector_io(descriptor, pos, vecs, count, true); +} + + static off_t file_seek(struct file_descriptor* descriptor, off_t pos, int seekType) {