summaryrefslogtreecommitdiff
path: root/src/init/fs
diff options
context:
space:
mode:
authordzwdz2022-07-08 15:33:49 +0200
committerdzwdz2022-07-08 15:33:49 +0200
commit29f0f35e4f0af5e662b799186019ba496ab93219 (patch)
tree57eae5f28b3b135a21493629c7ea6258e0b5123a /src/init/fs
parent1f7e7501660123ff8f26e8c65e75c2b282b933ef (diff)
init/fs: remove fs_respond_delegate, clean up
Diffstat (limited to 'src/init/fs')
-rw-r--r--src/init/fs/misc.c225
1 files changed, 74 insertions, 151 deletions
diff --git a/src/init/fs/misc.c b/src/init/fs/misc.c
index 701db9f..a218bf5 100644
--- a/src/init/fs/misc.c
+++ b/src/init/fs/misc.c
@@ -15,103 +15,30 @@ bool fork2_n_mount(const char *path) {
return false;
}
-static void fs_respond_delegate(struct fs_wait_response *res, handle_t delegate, const char *og_buf) {
- /* 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 size;
- int ret;
-
- switch (res->op) {
- case VFSOP_READ:
- if (_syscall_fork(FORK_NOREAP, NULL)) {
- // handle reads in a child
- // this is a HORRIBLE workaround for making concurrent IO work without proper delegates
- break;
- }
- // TODO instead of truncating the size, allocate a bigger buffer
- size = res->capacity < sizeof(buf) ? res->capacity : sizeof(buf);
- ret = _syscall_read(delegate, buf, size, res->offset);
- _syscall_fs_respond(buf, ret, 0);
- _syscall_exit(0);
- break;
-
- // TODO proper writing (see above)
- case VFSOP_WRITE:
- ret = _syscall_write(delegate, og_buf, res->len, res->offset);
- _syscall_fs_respond(NULL, ret, 0);
- break;
-
- case VFSOP_CLOSE:
- _syscall_close(delegate);
- // isn't it kinda weird that i even have to respond to close()s?
- // i suppose it makes the API more consistent
- _syscall_fs_respond(NULL, 0, 0);
- break;
-
- default:
- /* unsupported / unexpected */
- _syscall_fs_respond(NULL, -1, 0);
- break;
- }
-}
-
void fs_passthru(const char *prefix) {
struct fs_wait_response res;
- static char buf[1024];
- int ret, prefix_len;
- if (prefix) prefix_len = strlen(prefix);
+ const size_t buf_len = 1024;
+ char *buf = malloc(buf_len);
+ int prefix_len = prefix ? strlen(prefix) : 0;
+ if (!buf) _syscall_exit(1);
- while (!_syscall_fs_wait(buf, sizeof(buf), &res)) {
+ while (!_syscall_fs_wait(buf, buf_len, &res)) {
switch (res.op) {
case VFSOP_OPEN:
if (prefix) {
- /* special case: rewriting the path */
- if (prefix_len + res.len <= sizeof(buf)) {
- // 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, res.flags);
- } else ret = -1;
- } else {
- ret = _syscall_open(buf, res.len, res.flags);
+ if (prefix_len + res.len > buf_len) {
+ _syscall_fs_respond(NULL, -1, 0);
+ break;
+ }
+
+ // TODO memmove
+ char tmp[64];
+ memcpy(tmp, buf, res.len);
+ memcpy(buf + prefix_len, tmp, res.len);
+ memcpy(buf, prefix, prefix_len);
+ res.len += prefix_len;
}
- _syscall_fs_respond(NULL, ret, FSR_DELEGATE);
+ _syscall_fs_respond(NULL, _syscall_open(buf, res.len, res.flags), FSR_DELEGATE);
break;
default:
@@ -124,10 +51,12 @@ void fs_passthru(const char *prefix) {
void fs_whitelist(const char **list) {
struct fs_wait_response res;
- static char buf[1024];
+ const size_t buf_len = 1024;
+ char *buf = malloc(buf_len);
bool allow;
+ if (!buf) _syscall_exit(1);
- while (!_syscall_fs_wait(buf, sizeof(buf), &res)) {
+ while (!_syscall_fs_wait(buf, buf_len, &res)) {
switch (res.op) {
case VFSOP_OPEN:
allow = false;
@@ -153,92 +82,86 @@ void fs_whitelist(const char **list) {
void fs_dir_inject(const char *path) {
struct fs_dir_handle {
- bool taken;
- int delegate;
const char *inject;
+ int delegate, inject_len;
};
const size_t path_len = strlen(path);
struct fs_wait_response res;
- struct fs_dir_handle handles[16] = {0}; // TODO hardcoded FD_MAX - use malloc instead
- static char buf[1024];
- int ret;
+ struct fs_dir_handle *data;
+ const size_t buf_len = 1024;
+ char *buf = malloc(buf_len);
+ int ret, inject_len;
+
+ if (!buf) _syscall_exit(1);
- while (!_syscall_fs_wait(buf, sizeof buf, &res)) {
+ while (!_syscall_fs_wait(buf, buf_len, &res)) {
+ data = res.id;
switch (res.op) {
case VFSOP_OPEN:
- int hid = -1;
- for (int hid2 = 0; hid2 * sizeof(*handles) < sizeof(handles); hid2++) {
- if (!handles[hid2].taken) {
- hid = hid2;
+ if (buf[res.len - 1] == '/' &&
+ res.len < path_len && !memcmp(path, buf, res.len))
+ {
+ /* opening a directory that we're injecting into */
+
+ if (res.flags & OPEN_CREATE) {
+ _syscall_fs_respond(NULL, -1, 0);
break;
}
- }
- if (hid < 0) _syscall_fs_respond(NULL, -2, 0); // we ran out of handles
- ret = _syscall_open(buf, res.len, res.flags); /* errors handled in inject handler */
- handles[hid].delegate = ret;
- handles[hid].inject = NULL;
- handles[hid].taken = true;
+ data = malloc(sizeof *data);
+ data->delegate = _syscall_open(buf, res.len, res.flags);
+ data->inject = path + res.len;
- if (buf[res.len - 1] == '/' &&
- res.len < path_len && !memcmp(path, buf, res.len)) {
- /* we're injecting */
- handles[hid].inject = path + res.len;
+ /* inject up to the next slash */
+ inject_len = 0;
+ while (data->inject[inject_len] && data->inject[inject_len] != '/')
+ inject_len++;
+ if (data->inject[inject_len] == '/')
+ inject_len++;
+ data->inject_len = inject_len;
- /* if we're making up the opened directory, disallow create */
- if (ret < 0 && (res.flags & OPEN_CREATE)) hid = ret;
- _syscall_fs_respond((void*)hid, hid, 0);
+ _syscall_fs_respond(data, 0, 0);
} else {
- /* not injecting, don't allow opening nonexistent stuff */
-
- handles[hid].taken = false;
- _syscall_fs_respond(NULL, ret, FSR_DELEGATE);
+ _syscall_fs_respond(NULL, _syscall_open(buf, res.len, res.flags), FSR_DELEGATE);
}
break;
case VFSOP_CLOSE:
- if (handles[(int)res.id].delegate >= 0)
- _syscall_close(handles[(int)res.id].delegate);
- handles[(int)res.id].taken = false;
+ if (data->delegate >= 0)
+ _syscall_close(data->delegate);
_syscall_fs_respond(NULL, 0, 0);
break;
case VFSOP_READ:
- if (handles[(int)res.id].inject) {
- if (res.offset > 0) _syscall_fs_respond(NULL, 0, 0); // TODO working offsets
- struct fs_dir_handle h = handles[(int)res.id];
-
- int out_len = 0;
- while (h.inject[out_len] && h.inject[out_len] != '/')
- out_len++;
- if (h.inject[out_len] == '/')
- out_len++;
- memcpy(buf, h.inject, out_len);
- buf[out_len++] = '\0';
-
- if (h.delegate >= 0) {
- int to_read = res.capacity < sizeof(buf) ? res.capacity : sizeof(buf);
- to_read -= out_len;
- ret = _syscall_read(h.delegate, buf + out_len, to_read, 0);
- if (ret > 0) out_len += ret;
- // TODO deduplicate entries
- }
-
- _syscall_fs_respond(buf, out_len, 0);
- break;
+ if (res.offset > 0) _syscall_fs_respond(NULL, 0, 0); // TODO working offsets
+
+ int out_len = data->inject_len;
+ memcpy(buf, data->inject, out_len);
+ buf[out_len++] = '\0';
+
+ if (data->delegate >= 0) {
+ int to_read = res.capacity < buf_len ? res.capacity : buf_len;
+ to_read -= out_len;
+ ret = _syscall_read(data->delegate, buf + out_len, to_read, 0);
+ if (ret > 0) out_len += ret;
+ // TODO deduplicate entries
}
- /* fallthrough */
+ _syscall_fs_respond(buf, out_len, 0);
+ break;
- default: {
- struct fs_dir_handle h = handles[(int)res.id];
- if (h.delegate < 0)
- _syscall_fs_respond(NULL, -1, 0);
+ case VFSOP_WRITE:
+ if (data->delegate >= 0)
+ ret = _syscall_write(data->delegate, buf, res.len, res.offset);
else
- fs_respond_delegate(&res, h.delegate, buf);
+ ret = -1;
+ _syscall_fs_respond(NULL, ret, 0);
+ break;
+
+ default:
+ _syscall_fs_respond(NULL, -1, 0);
break;
- }
}
}
_syscall_exit(0);