summaryrefslogtreecommitdiff
path: root/src/kernel/vfs/request.c
diff options
context:
space:
mode:
authordzwdz2023-01-11 19:35:44 +0100
committerdzwdz2023-01-11 19:37:46 +0100
commitec81fa16d837f430add92b4d2ee4bd3727ca6c6d (patch)
tree43c91abe8d6a76fcec006fe67c1b585573d3662f /src/kernel/vfs/request.c
parentc178ab5d5ca328d5b0072d54e3dc66d1b198df7b (diff)
kernel: return EPIPE when fs_waiting on a dead filesystem
Diffstat (limited to 'src/kernel/vfs/request.c')
-rw-r--r--src/kernel/vfs/request.c48
1 files changed, 37 insertions, 11 deletions
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);
}