1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 07:47:37 +00:00

Kernel+LibC+Tests: Implement pwritev(2)

While this isn't really POSIX, it's needed by the Zig port and was
simple enough to implement.
This commit is contained in:
sin-ack 2022-10-01 13:21:20 +00:00 committed by Andrew Kaster
parent 70337f3a4b
commit 9b425b860c
6 changed files with 28 additions and 12 deletions

View file

@ -195,7 +195,7 @@ enum class NeedsBigProcessLock {
S(utimensat, NeedsBigProcessLock::No) \ S(utimensat, NeedsBigProcessLock::No) \
S(waitid, NeedsBigProcessLock::Yes) \ S(waitid, NeedsBigProcessLock::Yes) \
S(write, NeedsBigProcessLock::Yes) \ S(write, NeedsBigProcessLock::Yes) \
S(writev, NeedsBigProcessLock::Yes) \ S(pwritev, NeedsBigProcessLock::Yes) \
S(yield, NeedsBigProcessLock::No) S(yield, NeedsBigProcessLock::No)
namespace Syscall { namespace Syscall {

View file

@ -317,7 +317,7 @@ public:
ErrorOr<FlatPtr> sys$pread(int fd, Userspace<u8*>, size_t, Userspace<off_t const*>); ErrorOr<FlatPtr> sys$pread(int fd, Userspace<u8*>, size_t, Userspace<off_t const*>);
ErrorOr<FlatPtr> sys$readv(int fd, Userspace<const struct iovec*> iov, int iov_count); ErrorOr<FlatPtr> sys$readv(int fd, Userspace<const struct iovec*> iov, int iov_count);
ErrorOr<FlatPtr> sys$write(int fd, Userspace<u8 const*>, size_t); ErrorOr<FlatPtr> sys$write(int fd, Userspace<u8 const*>, size_t);
ErrorOr<FlatPtr> sys$writev(int fd, Userspace<const struct iovec*> iov, int iov_count); ErrorOr<FlatPtr> sys$pwritev(int fd, Userspace<const struct iovec*> iov, int iov_count, Userspace<off_t const*>);
ErrorOr<FlatPtr> sys$fstat(int fd, Userspace<stat*>); ErrorOr<FlatPtr> sys$fstat(int fd, Userspace<stat*>);
ErrorOr<FlatPtr> sys$stat(Userspace<Syscall::SC_stat_params const*>); ErrorOr<FlatPtr> sys$stat(Userspace<Syscall::SC_stat_params const*>);
ErrorOr<FlatPtr> sys$lseek(int fd, Userspace<off_t*>, int whence); ErrorOr<FlatPtr> sys$lseek(int fd, Userspace<off_t*>, int whence);
@ -602,7 +602,7 @@ private:
void delete_perf_events_buffer(); void delete_perf_events_buffer();
ErrorOr<void> do_exec(NonnullLockRefPtr<OpenFileDescription> main_program_description, NonnullOwnPtrVector<KString> arguments, NonnullOwnPtrVector<KString> environment, LockRefPtr<OpenFileDescription> interpreter_description, Thread*& new_main_thread, u32& prev_flags, const ElfW(Ehdr) & main_program_header); ErrorOr<void> do_exec(NonnullLockRefPtr<OpenFileDescription> main_program_description, NonnullOwnPtrVector<KString> arguments, NonnullOwnPtrVector<KString> environment, LockRefPtr<OpenFileDescription> interpreter_description, Thread*& new_main_thread, u32& prev_flags, const ElfW(Ehdr) & main_program_header);
ErrorOr<FlatPtr> do_write(OpenFileDescription&, UserOrKernelBuffer const&, size_t); ErrorOr<FlatPtr> do_write(OpenFileDescription&, UserOrKernelBuffer const&, size_t, Optional<off_t> = {});
ErrorOr<FlatPtr> do_statvfs(FileSystem const& path, Custody const*, statvfs* buf); ErrorOr<FlatPtr> do_statvfs(FileSystem const& path, Custody const*, statvfs* buf);

View file

@ -11,7 +11,9 @@
namespace Kernel { namespace Kernel {
ErrorOr<FlatPtr> Process::sys$writev(int fd, Userspace<const struct iovec*> iov, int iov_count) // NOTE: The offset is passed by pointer because off_t is 64bit,
// hence it can't be passed by register on 32bit platforms.
ErrorOr<FlatPtr> Process::sys$pwritev(int fd, Userspace<const struct iovec*> iov, int iov_count, Userspace<off_t const*> userspace_offset)
{ {
VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this); VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this);
TRY(require_promise(Pledge::stdio)); TRY(require_promise(Pledge::stdio));
@ -31,26 +33,32 @@ ErrorOr<FlatPtr> Process::sys$writev(int fd, Userspace<const struct iovec*> iov,
return EINVAL; return EINVAL;
} }
// NOTE: Negative offset means "operate like writev" which seeks the file.
auto base_offset = TRY(copy_typed_from_user(userspace_offset));
auto description = TRY(open_file_description(fd)); auto description = TRY(open_file_description(fd));
if (!description->is_writable()) if (!description->is_writable())
return EBADF; return EBADF;
if (base_offset >= 0 && !description->file().is_seekable())
return EINVAL;
int nwritten = 0; int nwritten = 0;
off_t current_offset = base_offset;
for (auto& vec : vecs) { for (auto& vec : vecs) {
auto buffer = TRY(UserOrKernelBuffer::for_user_buffer((u8*)vec.iov_base, vec.iov_len)); auto buffer = TRY(UserOrKernelBuffer::for_user_buffer((u8*)vec.iov_base, vec.iov_len));
auto result = do_write(*description, buffer, vec.iov_len); auto result = do_write(*description, buffer, vec.iov_len, base_offset >= 0 ? current_offset : Optional<off_t> {});
if (result.is_error()) { if (result.is_error()) {
if (nwritten == 0) if (nwritten == 0)
return result.release_error(); return result.release_error();
return nwritten; return nwritten;
} }
nwritten += result.value(); nwritten += result.value();
current_offset += result.value();
} }
return nwritten; return nwritten;
} }
ErrorOr<FlatPtr> Process::do_write(OpenFileDescription& description, UserOrKernelBuffer const& data, size_t data_size) ErrorOr<FlatPtr> Process::do_write(OpenFileDescription& description, UserOrKernelBuffer const& data, size_t data_size, Optional<off_t> offset)
{ {
size_t total_nwritten = 0; size_t total_nwritten = 0;
@ -72,7 +80,9 @@ ErrorOr<FlatPtr> Process::do_write(OpenFileDescription& description, UserOrKerne
} }
// TODO: handle exceptions in unblock_flags // TODO: handle exceptions in unblock_flags
} }
auto nwritten_or_error = description.write(data.offset(total_nwritten), data_size - total_nwritten); auto nwritten_or_error = offset.has_value()
? description.write(offset.value() + total_nwritten, data.offset(total_nwritten), data_size - total_nwritten)
: description.write(data.offset(total_nwritten), data_size - total_nwritten);
if (nwritten_or_error.is_error()) { if (nwritten_or_error.is_error()) {
if (total_nwritten > 0) if (total_nwritten > 0)
return total_nwritten; return total_nwritten;

View file

@ -44,7 +44,7 @@ static bool is_bad_idea(int fn, size_t const* direct_sc_args, size_t const* fake
// FIXME: Known bug: https://github.com/SerenityOS/serenity/issues/5328 // FIXME: Known bug: https://github.com/SerenityOS/serenity/issues/5328
return direct_sc_args[0] == 1; return direct_sc_args[0] == 1;
case SC_write: case SC_write:
case SC_writev: case SC_pwritev:
// FIXME: Known bug: https://github.com/SerenityOS/serenity/issues/5328 // FIXME: Known bug: https://github.com/SerenityOS/serenity/issues/5328
return direct_sc_args[0] == 0; return direct_sc_args[0] == 0;
case SC_pledge: case SC_pledge:

View file

@ -13,10 +13,7 @@ extern "C" {
ssize_t writev(int fd, const struct iovec* iov, int iov_count) ssize_t writev(int fd, const struct iovec* iov, int iov_count)
{ {
__pthread_maybe_cancel(); return pwritev(fd, iov, iov_count, -1);
int rc = syscall(SC_writev, fd, iov, iov_count);
__RETURN_WITH_ERRNO(rc, rc, -1);
} }
ssize_t readv(int fd, const struct iovec* iov, int iov_count) ssize_t readv(int fd, const struct iovec* iov, int iov_count)
@ -26,4 +23,12 @@ ssize_t readv(int fd, const struct iovec* iov, int iov_count)
int rc = syscall(SC_readv, fd, iov, iov_count); int rc = syscall(SC_readv, fd, iov, iov_count);
__RETURN_WITH_ERRNO(rc, rc, -1); __RETURN_WITH_ERRNO(rc, rc, -1);
} }
ssize_t pwritev(int fd, struct iovec const* iov, int iov_count, off_t offset)
{
__pthread_maybe_cancel();
int rc = syscall(SC_pwritev, fd, iov, iov_count, &offset);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
} }

View file

@ -13,5 +13,6 @@ __BEGIN_DECLS
ssize_t writev(int fd, const struct iovec*, int iov_count); ssize_t writev(int fd, const struct iovec*, int iov_count);
ssize_t readv(int fd, const struct iovec*, int iov_count); ssize_t readv(int fd, const struct iovec*, int iov_count);
ssize_t pwritev(int fd, const struct iovec*, int iov_count, off_t);
__END_DECLS __END_DECLS