aboutsummaryrefslogtreecommitdiff
path: root/src/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel')
-rw-r--r--src/kernel/include/vfs.h12
-rw-r--r--src/kernel/user/syscall.c10
-rw-r--r--src/kernel/user/vfs.c13
3 files changed, 31 insertions, 4 deletions
diff --git a/src/kernel/include/vfs.h b/src/kernel/include/vfs.h
index 37b28b9..bae4e6f 100644
--- a/src/kernel/include/vfs.h
+++ b/src/kernel/include/vfs.h
@@ -18,10 +18,15 @@
// some data managed by the underlying filesystem. The following types are aliases to void*,
// but are used to disambiguate the different types of void* : fs_handle_ptr, fs_node_ptr, fs_ptr
+// Conventions :
+// - ioctl returns negative values on error. null or positives are valid return values from underlying
+// driver
+
// About thread safety :
-// - The VFS implements a locking mechanism on handles so that only one operation is executed
-// at the same time on a given handle
-// - Same for FS nodes
+// - The VFS implements a locking mechanism on FS nodes so that only one operation is executed
+// at the same time on a given node (including: open, stat, walk, delete, move, create, ioctl)
+// - The VFS does not implement locks on handles : several simultaneous read/writes are possible, and
+// it is the driver's responsiblity to prevent that if necessary
// - The VFS does not lock nodes that have a handle open to them : it is the FS code's responsibility
// to refuse some commands if neccessary on a node that is open.
// - The VFS does not implement any locking mechanism on filesystems themselves (e.g. the add_source
@@ -166,6 +171,7 @@ int file_get_mode(fs_handle_t *f);
size_t file_read(fs_handle_t *f, size_t offset, size_t len, char* buf);
size_t file_write(fs_handle_t *f, size_t offset, size_t len, const char* buf);
bool file_stat(fs_handle_t *f, stat_t *st);
+int file_ioctl(fs_handle_t *f, int command, void* data);
bool file_readdir(fs_handle_t *f, dirent_t *d);
/* vim: set ts=4 sw=4 tw=0 noet :*/
diff --git a/src/kernel/user/syscall.c b/src/kernel/user/syscall.c
index 8a2cf18..6fdd633 100644
--- a/src/kernel/user/syscall.c
+++ b/src/kernel/user/syscall.c
@@ -263,6 +263,15 @@ static uint32_t stat_open_sc(sc_args_t args) {
return file_stat(h, o);
}
+static uint32_t ioctl_open_sc(sc_args_t args) {
+ fs_handle_t *h = proc_read_fd(current_process(), args.a);
+ if (h == 0) return -1;
+
+ void* data = (void*)args.c;
+ if (data >= (void*)K_HIGHHALF_ADDR) return -1;
+ return file_ioctl(h, args.b, data);
+}
+
static uint32_t get_mode_sc(sc_args_t args) {
fs_handle_t *h = proc_read_fd(current_process(), args.a);
if (h == 0) return 0;
@@ -296,6 +305,7 @@ void setup_syscall_table() {
sc_handlers[SC_WRITE] = write_sc;
sc_handlers[SC_READDIR] = readdir_sc;
sc_handlers[SC_STAT_OPEN] = stat_open_sc;
+ sc_handlers[SC_IOCTL_OPEN] = ioctl_open_sc;
sc_handlers[SC_GET_MODE] = get_mode_sc;
}
diff --git a/src/kernel/user/vfs.c b/src/kernel/user/vfs.c
index a5d56ef..ab49553 100644
--- a/src/kernel/user/vfs.c
+++ b/src/kernel/user/vfs.c
@@ -356,7 +356,7 @@ bool fs_stat(fs_t *fs, const char* file, stat_t *st) {
int fs_ioctl(fs_t *fs, const char* file, int command, void* data) {
fs_node_t* n = fs_walk_path(&fs->root, file);
- if (n == 0) return false;
+ if (n == 0) return -1;
mutex_lock(&n->lock);
int ret = (n->ops->ioctl ? n->ops->ioctl(n->data, command, data) : -1);
@@ -461,6 +461,17 @@ bool file_stat(fs_handle_t *f, stat_t *st) {
return ret;
}
+int file_ioctl(fs_handle_t *f, int command, void* data) {
+ if (!(f->mode & FM_IOCTL)) return -1;
+
+ mutex_lock(&f->node->lock);
+ int ret = -1;
+ if (f->node->ops->ioctl) ret = f->node->ops->ioctl(f->node->data, command, data);
+ mutex_unlock(&f->node->lock);
+
+ return ret;
+}
+
bool file_readdir(fs_handle_t *f, dirent_t *d) {
if (!(f->mode & FM_READDIR)) return 0;