Skip to content

Commit

Permalink
syscall(fs): implement readv and writev
Browse files Browse the repository at this point in the history
  • Loading branch information
mosmeh committed Nov 9, 2024
1 parent 4ca986e commit 80919b2
Show file tree
Hide file tree
Showing 8 changed files with 102 additions and 3 deletions.
8 changes: 8 additions & 0 deletions kernel/api/sys/uio.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#pragma once

#include <stddef.h>

struct iovec {
void* iov_base; // Starting address
size_t iov_len; // Size of the memory pointed to by iov_base.
};
2 changes: 1 addition & 1 deletion kernel/fs/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ typedef struct multiboot_mod_list multiboot_module_t;

// Open file description
struct file {
struct mutex offset_lock;
struct inode* inode;
atomic_int flags;
uint64_t offset;
struct mutex offset_lock;
void* private_data;
atomic_size_t ref_count;
};
Expand Down
71 changes: 71 additions & 0 deletions kernel/syscall/fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <kernel/api/dirent.h>
#include <kernel/api/fcntl.h>
#include <kernel/api/sys/limits.h>
#include <kernel/api/sys/uio.h>
#include <kernel/api/unistd.h>
#include <kernel/fs/fs.h>
#include <kernel/fs/path.h>
Expand Down Expand Up @@ -93,6 +94,41 @@ ssize_t sys_ia32_pread64(int fd, void* user_buf, size_t count, uint32_t pos_lo,
return rc;
}

ssize_t sys_readv(int fd, const struct iovec* user_iov, int iovcnt) {
if (!user_iov || !is_user_range(user_iov, iovcnt * sizeof(struct iovec)))
return -EFAULT;
struct file* file = task_get_file(fd);
if (IS_ERR(file))
return PTR_ERR(file);
mutex_lock(&file->offset_lock);
ssize_t ret = 0;
for (int i = 0; i < iovcnt; ++i) {
struct iovec iov;
if (copy_from_user(&iov, user_iov + i, sizeof(struct iovec))) {
ret = -EFAULT;
goto fail;
}
if (!is_user_range(iov.iov_base, iov.iov_len)) {
ret = -EFAULT;
goto fail;
}
ssize_t nread = file_read_to_end(file, iov.iov_base, iov.iov_len);
if (nread == -EINTR) {
if (ret == 0)
ret = -ERESTARTSYS;
break;
}
if (IS_ERR(nread)) {
ret = nread;
goto fail;
}
ret += nread;
}
fail:
mutex_unlock(&file->offset_lock);
return ret;
}

ssize_t sys_readlink(const char* user_pathname, char* user_buf, size_t bufsiz) {
char pathname[PATH_MAX];
int rc = copy_pathname_from_user(pathname, user_pathname);
Expand Down Expand Up @@ -153,6 +189,41 @@ ssize_t sys_ia32_pwrite64(int fd, const void* buf, size_t count,
return rc;
}

ssize_t sys_writev(int fd, const struct iovec* user_iov, int iovcnt) {
if (!user_iov || !is_user_range(user_iov, iovcnt * sizeof(struct iovec)))
return -EFAULT;
struct file* file = task_get_file(fd);
if (IS_ERR(file))
return PTR_ERR(file);
mutex_lock(&file->offset_lock);
ssize_t ret = 0;
for (int i = 0; i < iovcnt; ++i) {
struct iovec iov;
if (copy_from_user(&iov, user_iov + i, sizeof(struct iovec))) {
ret = -EFAULT;
goto fail;
}
if (!is_user_range(iov.iov_base, iov.iov_len)) {
ret = -EFAULT;
goto fail;
}
ssize_t nwritten = file_write_all(file, iov.iov_base, iov.iov_len);
if (nwritten == -EINTR) {
if (ret == 0)
ret = -ERESTARTSYS;
break;
}
if (IS_ERR(nwritten)) {
ret = nwritten;
goto fail;
}
ret += nwritten;
}
fail:
mutex_unlock(&file->offset_lock);
return ret;
}

static int truncate(const char* user_path, uint64_t length) {
char path[PATH_MAX];
int rc = copy_pathname_from_user(path, user_path);
Expand Down
4 changes: 4 additions & 0 deletions kernel/syscall/syscall.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@
F(_llseek, sys_llseek, 0) \
F(getdents, sys_getdents, 0) \
F(_newselect, sys_select, 0) \
F(readv, sys_readv, 0) \
F(writev, sys_writev, 0) \
F(sched_yield, sys_sched_yield, 0) \
F(nanosleep, sys_nanosleep_time32, 0) \
F(poll, sys_poll, 0) \
Expand Down Expand Up @@ -229,6 +231,8 @@ int sys_llseek(unsigned int fd, unsigned long offset_high,
ssize_t sys_getdents(int fd, struct linux_dirent* dirp, size_t count);
int sys_select(int nfds, unsigned long* readfds, unsigned long* writefds,
unsigned long* exceptfds, struct linux_timeval* timeout);
ssize_t sys_readv(int fd, const struct iovec* iov, int iovcnt);
ssize_t sys_writev(int fd, const struct iovec* iov, int iovcnt);
int sys_sched_yield(void);
int sys_nanosleep_time32(const struct timespec32* duration,
struct timespec32* rem);
Expand Down
2 changes: 0 additions & 2 deletions kernel/syscall/unimplemented.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,6 @@
F(setfsgid) \
F(flock) \
F(msync) \
F(readv) \
F(writev) \
F(getsid) \
F(fdatasync) \
F(mlock) \
Expand Down
1 change: 1 addition & 0 deletions userland/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ LIB_OBJS := \
lib/sys/sysinfo.o \
lib/sys/time.o \
lib/sys/times.o \
lib/sys/uio.o \
lib/sys/utsname.o \
lib/sys/wait.o \
lib/termios.o \
Expand Down
10 changes: 10 additions & 0 deletions userland/lib/sys/uio.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#include "uio.h"
#include <private.h>

ssize_t readv(int fd, const struct iovec* iov, int iovcnt) {
RETURN_WITH_ERRNO(ssize_t, SYSCALL3(readv, fd, iov, iovcnt));
}

ssize_t writev(int fd, const struct iovec* iov, int iovcnt) {
RETURN_WITH_ERRNO(ssize_t, SYSCALL3(writev, fd, iov, iovcnt));
}
7 changes: 7 additions & 0 deletions userland/lib/sys/uio.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#pragma once

#include <kernel/api/sys/uio.h>
#include <sys/types.h>

ssize_t readv(int fd, const struct iovec* iov, int iovcnt);
ssize_t writev(int fd, const struct iovec* iov, int iovcnt);

0 comments on commit 80919b2

Please sign in to comment.