fs: implement file abstraction
This commit is contained in:
parent
9ca76d71ad
commit
d20da423ec
10 changed files with 218 additions and 21 deletions
|
@ -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
42
include/ardix/file.h
Normal 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.
|
||||
*/
|
|
@ -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@
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
122
kernel/fs/file.c
Normal 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.
|
||||
*/
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
Loading…
Reference in a new issue