fs: implement file abstraction

This commit is contained in:
anna 2021-08-01 04:22:09 +02:00
parent 9ca76d71ad
commit d20da423ec
Signed by: fef
GPG key ID: EC22E476DC2D3D84
10 changed files with 218 additions and 21 deletions

View file

@ -5,6 +5,7 @@
#include <ardix/kent.h>
#include <ardix/list.h>
#include <ardix/malloc.h>
#include <ardix/mutex.h>
#include <ardix/types.h>
#include <stddef.h>
@ -12,6 +13,9 @@
/** Top-level abstraction for any device connected to the system. */
struct device {
struct kent kent;
struct mutex lock;
ssize_t (*read)(void *dest, struct device *device, size_t size, off_t offset);
ssize_t (*write)(struct device *device, const void *src, size_t size, off_t offset);
};
/** Cast a kent out to its containing struct device */

42
include/ardix/file.h Normal file
View file

@ -0,0 +1,42 @@
/* See the end of this file for copyright, license, and warranty information. */
#pragma once
#include <ardix/kent.h>
#include <ardix/mutex.h>
#include <ardix/types.h>
enum file_type {
FILE_TYPE_REGULAR,
FILE_TYPE_PIPE,
};
struct file {
struct kent kent;
int fd;
loff_t pos;
struct mutex lock;
struct device *device;
enum file_type type;
};
struct file *file_create(struct device *dev, enum file_type type, int *err);
struct file *file_get(int fd);
void file_put(struct file *file);
ssize_t file_write(struct file *file, const void *buf, size_t len);
ssize_t file_read(void *buf, struct file *file, size_t len);
/*
* This file is part of Ardix.
* Copyright (c) 2020, 2021 Felix Kopp <owo@fef.moe>.
*
* Ardix is non-violent software: you may only use, redistribute,
* and/or modify it under the terms of the CNPLv6+ as found in
* the LICENSE file in the source code root directory or at
* <https://git.pixie.town/thufie/CNPL>.
*
* Ardix comes with ABSOLUTELY NO WARRANTY, to the extent
* permitted by applicable law. See the CNPLv6+ for details.
*/

View file

@ -10,6 +10,7 @@
#cmakedefine DEBUG
#cmakedefine ARCH
#define CONFIG_NFILE @CONFIG_NFILE@
#define CONFIG_STACK_SIZE @CONFIG_STACK_SIZE@
#define CONFIG_SCHED_MAXPROC @CONFIG_SCHED_MAXPROC@

View file

@ -41,14 +41,12 @@ static void device_destroy(struct kent *kent)
int device_init(struct device *dev)
{
if (devices_kent == NULL)
return -ENOENT;
if (dev->kent.destroy == NULL)
dev->kent.destroy = device_destroy;
if (dev->kent.parent == NULL)
dev->kent.parent = devices_kent;
mutex_init(&dev->lock);
return kent_init(&dev->kent);
}

View file

@ -7,6 +7,7 @@ target_compile_options(ardix_kernel_fs PRIVATE ${ARDIX_COMPILE_OPTIONS})
target_include_directories(ardix_kernel_fs PRIVATE ${ARDIX_INCLUDE_DIRS})
target_sources(ardix_kernel_fs PRIVATE
file.c
read.c
write.c
)

122
kernel/fs/file.c Normal file
View file

@ -0,0 +1,122 @@
/* See the end of this file for copyright, license, and warranty information. */
#include <ardix/device.h>
#include <ardix/file.h>
#include <ardix/malloc.h>
#include <config.h>
#include <errno.h>
#include <stddef.h>
static struct file *fdtab[CONFIG_NFILE];
static MUTEX(fdtab_lock);
static void file_destroy(struct kent *kent)
{
struct file *file = container_of(kent, struct file, kent);
mutex_lock(&fdtab_lock);
fdtab[file->fd] = NULL;
mutex_unlock(&fdtab_lock);
free(file);
}
struct file *file_create(struct device *device, enum file_type type, int *err)
{
struct file *f;
struct file **slot;
int fd;
mutex_lock(&fdtab_lock);
for (fd = 0; fd < CONFIG_NFILE; fd++) {
slot = &fdtab[fd];
if (*slot == NULL)
break;
}
if (*slot != NULL) {
*err = -EMFILE;
mutex_unlock(&fdtab_lock);
return NULL;
}
f = malloc(sizeof(*f));
if (f == NULL) {
*err = -ENOMEM;
mutex_unlock(&fdtab_lock);
return NULL;
}
*slot = f;
mutex_unlock(&fdtab_lock);
f->kent.parent = &device->kent;
f->kent.destroy = file_destroy;
kent_init(&f->kent);
f->fd = fd;
f->device = device;
f->pos = 0;
f->type = type;
mutex_init(&f->lock);
return f;
}
struct file *file_get(int fd)
{
struct file *f = NULL;
if (fd < CONFIG_NFILE) {
mutex_lock(&fdtab_lock);
f = fdtab[fd];
if (f != NULL)
kent_get(&f->kent);
mutex_unlock(&fdtab_lock);
}
return f;
}
void file_put(struct file *f)
{
kent_put(&f->kent);
}
ssize_t file_read(void *buf, struct file *file, size_t len)
{
ssize_t ret;
mutex_lock(&file->lock);
ret = file->device->read(buf, file->device, len, file->pos);
if (file->type == FILE_TYPE_REGULAR && ret > 0)
file->pos += ret;
mutex_unlock(&file->lock);
return ret;
}
ssize_t file_write(struct file *file, const void *buf, size_t len)
{
ssize_t ret;
mutex_lock(&file->lock);
ret = file->device->write(file->device, buf, len, file->pos);
if (file->type == FILE_TYPE_REGULAR && ret > 0)
file->pos += ret;
mutex_unlock(&file->lock);
return ret;
}
/*
* This file is part of Ardix.
* Copyright (c) 2020, 2021 Felix Kopp <owo@fef.moe>.
*
* Ardix is non-violent software: you may only use, redistribute,
* and/or modify it under the terms of the CNPLv6+ as found in
* the LICENSE file in the source code root directory or at
* <https://git.pixie.town/thufie/CNPL>.
*
* Ardix comes with ABSOLUTELY NO WARRANTY, to the extent
* permitted by applicable law. See the CNPLv6+ for details.
*/

View file

@ -1,7 +1,7 @@
/* See the end of this file for copyright, license, and warranty information. */
#include <ardix/file.h>
#include <ardix/malloc.h>
#include <ardix/serial.h>
#include <ardix/syscall.h>
#include <ardix/userspace.h>
@ -14,19 +14,20 @@ ssize_t sys_read(int fd, __user void *buf, size_t len)
ssize_t ret;
void *copy;
if (fd != 0) /* we only support stdin (serial console) right now */
struct file *f = file_get(fd);
if (f == NULL)
return -EBADF;
copy = malloc(len);
if (copy == NULL)
return -ENOMEM;
ret = serial_read(copy, serial_default_device, len);
if (ret > 0)
copy_to_user(buf, copy, (size_t)ret);
ret = file_read(copy, f, len);
if (ret >= 0)
ret = copy_to_user(buf, copy, ret);
free(copy);
file_put(f);
return ret;
}

View file

@ -1,10 +1,7 @@
/* See the end of this file for copyright, license, and warranty information. */
#include <arch/serial.h>
#include <ardix/dma.h>
#include <ardix/file.h>
#include <ardix/malloc.h>
#include <ardix/serial.h>
#include <ardix/syscall.h>
#include <ardix/userspace.h>
@ -15,20 +12,23 @@
ssize_t sys_write(int fd, __user const void *buf, size_t len)
{
ssize_t ret;
struct dmabuf *dma;
void *copy;
if (fd != 1) /* we only support stdout (serial console) right now */
struct file *f = file_get(fd);
if (f == NULL)
return -EBADF;
dma = dmabuf_create(&serial_default_device->device, len);
if (dma == NULL)
copy = malloc(len);
if (copy == NULL) {
file_put(f);
return -ENOMEM;
}
copy_from_user(dma->data, buf, len);
/* TODO: reschedule if blocking */
ret = serial_write_dma(serial_default_device, dma);
dmabuf_put(dma);
len = copy_from_user(copy, buf, len);
ret = file_write(f, copy, len);
free(copy);
file_put(f);
return ret;
}

View file

@ -2,6 +2,7 @@
#include <ardix/atomic.h>
#include <ardix/device.h>
#include <ardix/mutex.h>
#include <ardix/ringbuf.h>
#include <ardix/sched.h>
#include <ardix/serial.h>
@ -10,6 +11,30 @@
#include <stddef.h>
static ssize_t serial_device_read(void *dest, struct device *dev, size_t len)
{
ssize_t ret;
struct serial_device *serial_dev = container_of(dev, struct serial_device, device);
mutex_lock(&dev->lock);
ret = serial_read(dest, serial_dev, len);
mutex_unlock(&dev->lock);
return ret;
}
static ssize_t serial_device_write(struct device *dev, const void *src, size_t len)
{
ssize_t ret;
struct serial_device *serial_dev = container_of(dev, struct serial_device, device);
mutex_lock(&dev->lock);
ret = serial_write(serial_dev, src, len);
mutex_unlock(&dev->lock);
return ret;
}
int serial_init(struct serial_device *dev, long int baud)
{
int err = -1;
@ -17,6 +42,8 @@ int serial_init(struct serial_device *dev, long int baud)
if (dev->id < 0)
return -1; /* invalid dev */
dev->device.read = serial_device_read;
dev->device.write = serial_device_write;
err = device_init(&dev->device);
dev->baud = baud;

View file

@ -1,5 +1,6 @@
# See the end of this file for copyright and license terms.
set(CONFIG_NFILE 16 CACHE STRING "Maximum number of open files")
set(CONFIG_STACK_SIZE 2048 CACHE STRING "Stack size in bytes")
set(CONFIG_SCHED_MAXPROC 8 CACHE STRING "Maximum number of processes")