diff options
author | dzwdz | 2023-01-11 19:35:44 +0100 |
---|---|---|
committer | dzwdz | 2023-01-11 19:37:46 +0100 |
commit | ec81fa16d837f430add92b4d2ee4bd3727ca6c6d (patch) | |
tree | 43c91abe8d6a76fcec006fe67c1b585573d3662f /src/kernel/vfs | |
parent | c178ab5d5ca328d5b0072d54e3dc66d1b198df7b (diff) |
kernel: return EPIPE when fs_waiting on a dead filesystem
Diffstat (limited to 'src/kernel/vfs')
-rw-r--r-- | src/kernel/vfs/mount.c | 16 | ||||
-rw-r--r-- | src/kernel/vfs/procfs.c | 4 | ||||
-rw-r--r-- | src/kernel/vfs/request.c | 48 | ||||
-rw-r--r-- | src/kernel/vfs/request.h | 22 |
4 files changed, 62 insertions, 28 deletions
diff --git a/src/kernel/vfs/mount.c b/src/kernel/vfs/mount.c index aa73acb..2815bb9 100644 --- a/src/kernel/vfs/mount.c +++ b/src/kernel/vfs/mount.c @@ -14,8 +14,8 @@ void vfs_root_register(const char *path, void (*accept)(struct vfs_request *)) { struct vfs_mount *mount = kmalloc(sizeof *mount); *backend = (struct vfs_backend) { .is_user = false, - .potential_handlers = 1, - .refcount = 1, + .usehcnt = 1, + .provhcnt = 1, .kern.accept = accept, }; *mount = (struct vfs_mount){ @@ -55,11 +55,15 @@ void vfs_mount_remref(struct vfs_mount *mnt) { if (--(mnt->refs) > 0) return; struct vfs_mount *prev = mnt->prev; - if (mnt->backend) - vfs_backend_refdown(mnt->backend); - if (mnt->prefix_owned) + if (mnt->backend) { + vfs_backend_refdown(mnt->backend, true); + } + if (mnt->prefix_owned) { kfree((void*)mnt->prefix); + } kfree(mnt); - if (prev) vfs_mount_remref(prev); + if (prev) { + vfs_mount_remref(prev); + } } diff --git a/src/kernel/vfs/procfs.c b/src/kernel/vfs/procfs.c index e434c45..0f65f93 100644 --- a/src/kernel/vfs/procfs.c +++ b/src/kernel/vfs/procfs.c @@ -110,8 +110,8 @@ procfs_backend(struct process *proc) struct vfs_backend *be = kzalloc(sizeof(struct vfs_backend)); *be = (struct vfs_backend) { .is_user = false, - .potential_handlers = 1, - .refcount = 1, + .provhcnt = 1, + .usehcnt = 1, .kern.accept = procfs_accept, .kern.data = proc, .kern.cleanup = procfs_cleanup, diff --git a/src/kernel/vfs/request.c b/src/kernel/vfs/request.c index 2288de5..1cd2787 100644 --- a/src/kernel/vfs/request.c +++ b/src/kernel/vfs/request.c @@ -21,7 +21,10 @@ void vfsreq_create(struct vfs_request req_) { req = kmalloc(sizeof *req); } memcpy(req, &req_, sizeof *req); - if (req->backend) req->backend->refcount++; + if (req->backend) { + assert(req->backend->usehcnt); + req->backend->usehcnt++; + } if (req->type == VFSOP_OPEN && !(req->flags & OPEN_WRITE) && (req->flags & OPEN_CREATE)) { vfsreq_finish_short(req, -EINVAL); @@ -30,7 +33,7 @@ void vfsreq_create(struct vfs_request req_) { // TODO if i add a handle field to vfs_request, check ->readable ->writeable here - if (req->backend && req->backend->potential_handlers) { + if (req->backend && req->backend->provhcnt) { struct vfs_request **iter = &req->backend->queue; while (*iter != NULL) // find free spot in queue iter = &(*iter)->queue_next; @@ -49,7 +52,8 @@ void vfsreq_finish(struct vfs_request *req, char __user *stored, long ret, if (!(flags & FSR_DELEGATE)) { /* default behavior - create a new handle for the file, wrap the id */ h = handle_init(HANDLE_FILE); - h->backend = req->backend; req->backend->refcount++; + h->backend = req->backend; + req->backend->usehcnt++; h->file_id = stored; h->readable = OPEN_READABLE(req->flags); h->writeable = OPEN_WRITEABLE(req->flags); @@ -74,7 +78,7 @@ void vfsreq_finish(struct vfs_request *req, char __user *stored, long ret, kfree(req->input.buf_kern); if (req->backend) - vfs_backend_refdown(req->backend); + vfs_backend_refdown(req->backend, true); if (req->caller) { assert(req->caller->state == PS_WAITS4FS); @@ -151,13 +155,35 @@ static void vfs_backend_user_accept(struct vfs_request *req) { return; } -void vfs_backend_refdown(struct vfs_backend *b) { +void vfs_backend_refdown(struct vfs_backend *b, bool use) { + size_t *field = use ? &b->usehcnt : &b->provhcnt; assert(b); - assert(b->refcount > 0); - if (--(b->refcount) > 0) return; - assert(!b->queue); - if (!b->is_user && b->kern.cleanup) { - b->kern.cleanup(b); + assert(0 < *field); + *field -= 1; + + if (b->provhcnt == 0 && use == false) { + struct vfs_request *q = b->queue; + while (q) { + struct vfs_request *q2 = q->queue_next; + vfsreq_finish_short(q, -1); + q = q2; + } + b->queue = NULL; + } + if (b->usehcnt == 0 && use == true) { + if (!b->is_user && b->kern.cleanup) { + b->kern.cleanup(b); + } + if (b->is_user && b->user.handler) { + struct process *p = b->user.handler; + b->user.handler = NULL; + assert(p->state == PS_WAITS4REQUEST); + regs_savereturn(&p->regs, -EPIPE); + process_transition(p, PS_RUNNING); + } + } + if (b->usehcnt == 0 && b->provhcnt == 0) { + assert(!b->queue); + kfree(b); } - kfree(b); } diff --git a/src/kernel/vfs/request.h b/src/kernel/vfs/request.h index ef7c83a..4d7fa01 100644 --- a/src/kernel/vfs/request.h +++ b/src/kernel/vfs/request.h @@ -5,15 +5,17 @@ // describes something which can act as an access function struct vfs_backend { - /* references: - * struct vfs_mount - * struct vfs_request - * struct process - * struct handle - */ - size_t refcount; + /* amount of using references + * struct vfs_mount + * struct vfs_request + * struct handle + * once it reaches 0, it'll never increase */ + size_t usehcnt; /* struct vfs_mount */ + /* amount of providing references + * struct process + * 0 - orphaned, will never increase */ + size_t provhcnt; - size_t potential_handlers; // 0 - orphaned struct vfs_request *queue; bool is_user; union { @@ -72,4 +74,6 @@ static inline void vfsreq_finish_short(struct vfs_request *req, long ret) { /** Try to accept an enqueued request */ void vfs_backend_tryaccept(struct vfs_backend *); -void vfs_backend_refdown(struct vfs_backend *); +// TODO the bool arg is confusing. maybe this should just be a function +// that verified the refcount and potentially frees the backend +void vfs_backend_refdown(struct vfs_backend *, bool use); |