|
|
|
|
@@ -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)
|
|
|
|
|
|