diff options
author | dzwdz | 2021-11-20 16:16:32 +0100 |
---|---|---|
committer | dzwdz | 2021-11-20 16:16:32 +0100 |
commit | bb1abf9e6eaee879d399ff3dde6cf6baf9caddaa (patch) | |
tree | b3ee9c0c7358240acf9dc13a239afa0d452dbc8f /src/init/fs/misc.c | |
parent | 6caac6e940ab79960b1c1ca0e5ed8f28aa49a3a9 (diff) |
shared: fs_request_delegate stub
my thoughts on this are already in that giant comment, go read it
Diffstat (limited to 'src/init/fs/misc.c')
-rw-r--r-- | src/init/fs/misc.c | 101 |
1 files changed, 71 insertions, 30 deletions
diff --git a/src/init/fs/misc.c b/src/init/fs/misc.c index cb94ef5..f98259f 100644 --- a/src/init/fs/misc.c +++ b/src/init/fs/misc.c @@ -10,6 +10,64 @@ bool fork2_n_mount(const char *path) { return h; } +static void fs_respond_delegate(struct fs_wait_response *res, handle_t delegate) { + /* The idea behind this function is that many fs implementations (e.g. for + * overlay fs) will want to forward received requests to the original fs + * implementation. + * + * Having some special support for this in the kernel makes sense - it would + * avoid a lot of unnecessary copies. However, it wouldn't be necessary for + * a working kernel - and since I want the "base" of this system to be a small + * as possible, I want to have an alternative implementation of this in the + * userland which works in exactly the same way. The libc would then choose + * the best available implementation. + * + * (note: this wouldn't be an issue if i treated everything like functions + * in the ruby prototype) + * + * This function was supposed to avoid unnecessary copies on delegated reads. + * It is being executed /after/ the write read, though. I don't currently see + * a good way to fix that. Here are a few loose ideas: + * - a fs_wait flag which requires a separate syscall to get the write copy + * - a way to "mark" returned handles + * - no write copy mark + * - mark with delegate handle + * every vfs op would go directly to that delegate handle + * probably the fastest way + * - treat open() just like in the ruby prototype + * Instead of just returning a handle, the driver would return a list + * of functions. Here's how it would work, in pseudocode: + * ``` + * # for full delegation + * respond_new_handle({ + * read: {DELEGATE, handle}, // extract the read function from `handle` + * write: {DELEGATE, handle}, + * close: {DELEGATE, handle} + * }); + * ``` + */ + static char buf[1024]; + int buf_size = 1024; + int size; + int ret; + + switch (res->op) { + case VFSOP_READ: + // TODO instead of truncating the size, allocate a bigger buffer + size = res->capacity < buf_size ? res->capacity : buf_size; + ret = _syscall_read(delegate, buf, size, res->offset); + _syscall_fs_respond(buf, ret); + break; + + // TODO writing (see above) + + default: + /* unsupported / unexpected */ + _syscall_fs_respond(NULL, -1); + break; + } +} + void fs_passthru(const char *prefix) { struct fs_wait_response res; int buf_size = 64; @@ -18,36 +76,19 @@ void fs_passthru(const char *prefix) { if (prefix) prefix_len = strlen(prefix); while (!_syscall_fs_wait(buf, buf_size, &res)) { - switch (res.op) { - case VFSOP_OPEN: - if (prefix) { - if (prefix_len + res.len <= buf_size) { - // TODO memmove - char tmp[64]; - memcpy(tmp, buf, res.len); - memcpy(buf, prefix, prefix_len); - memcpy(buf + prefix_len, tmp, res.len); - ret = _syscall_open(buf, res.len + prefix_len); - } else ret = -1; - } else { - ret = _syscall_open(buf, res.len); - } - _syscall_fs_respond(NULL, ret); - break; - - case VFSOP_READ: - if (res.capacity > buf_size) - res.capacity = buf_size; /* don't overflow the buffer */ - ret = _syscall_read(res.id, buf, res.capacity, res.offset); - _syscall_fs_respond(buf, ret); - break; - - // temporarily doesn't support writing - // also TODO closing - - default: - _syscall_fs_respond(NULL, -1); - break; + if (prefix && res.op == VFSOP_OPEN) { + /* the only special case: rewriting the path */ + if (prefix_len + res.len <= buf_size) { + // TODO memmove + char tmp[64]; + memcpy(tmp, buf, res.len); + memcpy(buf, prefix, prefix_len); + memcpy(buf + prefix_len, tmp, res.len); + ret = _syscall_open(buf, res.len + prefix_len); + } else ret = -1; + _syscall_fs_respond(NULL, ret); + } else { + fs_respond_delegate(&res, res.id); } } _syscall_exit(0); |