From 329829c0e94f265739210134824f62aee1006871 Mon Sep 17 00:00:00 2001 From: Max Wash Date: Tue, 24 Mar 2026 20:25:13 +0000 Subject: [PATCH] lib: fs: implement file cleanup using disconnect and detach events --- lib/libfs/context.c | 109 +++++++++++++++++++++++++++++++++---- lib/libfs/file.h | 3 + lib/libfs/interface/map.c | 1 + lib/libfs/interface/open.c | 1 + 4 files changed, 102 insertions(+), 12 deletions(-) diff --git a/lib/libfs/context.c b/lib/libfs/context.c index 247bbfe..65df1b5 100644 --- a/lib/libfs/context.c +++ b/lib/libfs/context.c @@ -141,6 +141,28 @@ kern_handle_t fs_context_get_vm_controller(const struct fs_context *ctx) return ctx->ctx_vm_controller; } +static enum fs_status handle_event(struct fs_context *ctx, xpc_msg_t *msg) +{ + switch (msg->msg_event) { + case KERN_MSG_EVENT_CONNECTION: + kern_logf("received connection"); + break; + case KERN_MSG_EVENT_DISCONNECTION: { + struct fs_file *f + = fs_context_get_file(ctx, msg->msg_sender.e_port); + if (f) { + fs_context_close_file(ctx, f); + } + break; + } + default: + kern_logf("received unknown event"); + break; + } + + return FS_SUCCESS; +} + static enum fs_status handle_msg(struct fs_context *ctx) { xpc_msg_t msg; @@ -154,6 +176,10 @@ static enum fs_status handle_msg(struct fs_context *ctx) return FS_ERR_INTERNAL_FAILURE; } + if (msg.msg_type != KERN_MSG_TYPE_DATA) { + return handle_event(ctx, &msg); + } + switch (msg.msg_header.hdr_interface) { case INTERFACE_FS: status = fs_context_dispatch_msg(ctx, &msg); @@ -169,18 +195,43 @@ static enum fs_status handle_msg(struct fs_context *ctx) return FS_SUCCESS; } -static enum fs_status handle_page_request(struct fs_context *ctx) +static enum fs_status handle_page_request_detach( + struct fs_context *ctx, + equeue_packet_page_request_t *packet, + struct file_mapping *mapping) { - equeue_packet_page_request_t packet; - vm_controller_recv(ctx->ctx_vm_controller, &packet); - struct file_mapping *mapping = (struct file_mapping *)packet.req_vmo; - kern_tracef( - "received page request [%zx-%zx] for file %s", - packet.req_offset, - packet.req_offset + packet.req_length, + kern_logf( + "received page request (detach) for file %s", mapping->m_file->f_dent->d_name); - size_t length = packet.req_length; + struct fs_file *f = mapping->m_file; + switch (mapping->m_type) { + case FILE_MAPPING_PRIVATE: + queue_delete(&f->f_mappings, &mapping->m_entry); + break; + default: + break; + } + + kern_handle_close(mapping->m_vmo); + fs_context_free(ctx, mapping); + + fs_context_close_file(ctx, f); + return FS_SUCCESS; +} + +static enum fs_status handle_page_request_read( + struct fs_context *ctx, + equeue_packet_page_request_t *packet, + struct file_mapping *mapping) +{ + kern_tracef( + "received page request (read) [%zx-%zx] for file %s", + packet->req_offset, + packet->req_offset + packet->req_length, + mapping->m_file->f_dent->d_name); + + size_t length = packet->req_length; if (length > TEMP_OBJECT_SIZE) { length = TEMP_OBJECT_SIZE; } @@ -190,7 +241,7 @@ static enum fs_status handle_page_request(struct fs_context *ctx) enum fs_status status = fs_file_read_at( mapping->m_file, &buf, - packet.req_offset, + packet->req_offset, length); if (status != FS_SUCCESS) { kern_tracef("map-read failed with code %d", status); @@ -200,10 +251,34 @@ static enum fs_status handle_page_request(struct fs_context *ctx) vm_controller_supply_pages( ctx->ctx_vm_controller, mapping->m_vmo, - packet.req_offset, + packet->req_offset, ctx->ctx_temp_object, 0, - packet.req_length); + packet->req_length); + return FS_SUCCESS; +} + +static enum fs_status handle_page_request(struct fs_context *ctx) +{ + equeue_packet_page_request_t packet; + kern_status_t status + = vm_controller_recv(ctx->ctx_vm_controller, &packet); + + if (status != KERN_OK) { + return KERN_BAD_STATE; + } + + struct file_mapping *mapping = (struct file_mapping *)packet.req_vmo; + + switch (packet.req_type) { + case PAGE_REQUEST_READ: + return handle_page_request_read(ctx, &packet, mapping); + case PAGE_REQUEST_DETACH: + return handle_page_request_detach(ctx, &packet, mapping); + default: + kern_logf("unknown page request type %zx", packet.req_type); + break; + } return FS_SUCCESS; } @@ -262,6 +337,16 @@ struct fs_file *fs_context_get_file(struct fs_context *ctx, unsigned long id) void fs_context_close_file(struct fs_context *ctx, struct fs_file *f) { + if (f->f_ref > 1) { + kern_logf( + "reference to file '%s' has been closed", + f->f_dent->d_name); + f->f_ref--; + return; + } + + kern_logf("file '%s' has been closed", f->f_dent->d_name); + btree_delete(&ctx->ctx_filelist, &f->f_node); } static size_t get_first_path_component(const char *in, char *out, size_t max) diff --git a/lib/libfs/file.h b/lib/libfs/file.h index a6c425e..209f5be 100644 --- a/lib/libfs/file.h +++ b/lib/libfs/file.h @@ -9,6 +9,9 @@ #include struct fs_file { + /* reference count includes the file descriptor, and any vm-objects + * attached to the file */ + unsigned int f_ref; /* id of the open file, equal to the koid of the port being used to * access the file */ unsigned long f_id; diff --git a/lib/libfs/interface/map.c b/lib/libfs/interface/map.c index a0632b8..3962110 100644 --- a/lib/libfs/interface/map.c +++ b/lib/libfs/interface/map.c @@ -105,6 +105,7 @@ extern kern_status_t fs_msg_map( kern_handle_t vmo; kern_handle_duplicate(mapping->m_vmo, &vmo); + f->f_ref++; *out_err = SUCCESS; *out_vmo = vmo; diff --git a/lib/libfs/interface/open.c b/lib/libfs/interface/open.c index d149c12..adab772 100644 --- a/lib/libfs/interface/open.c +++ b/lib/libfs/interface/open.c @@ -45,6 +45,7 @@ extern kern_status_t fs_msg_open( return KERN_OK; } + f->f_ref = 1; f->f_seek = 0; f->f_dent = dent; f->f_inode = dent->d_inode;