vm: implement lazy-attach cow-duplication of vm-objects attached to a controller
This commit is contained in:
@@ -47,6 +47,12 @@ static const virt_addr_t syscall_table[] = {
|
||||
SYSCALL_TABLE_ENTRY(
|
||||
VM_CONTROLLER_CREATE_OBJECT,
|
||||
vm_controller_create_object),
|
||||
SYSCALL_TABLE_ENTRY(
|
||||
VM_CONTROLLER_PREPARE_ATTACH,
|
||||
vm_controller_prepare_attach),
|
||||
SYSCALL_TABLE_ENTRY(
|
||||
VM_CONTROLLER_FINISH_ATTACH,
|
||||
vm_controller_finish_attach),
|
||||
SYSCALL_TABLE_ENTRY(
|
||||
VM_CONTROLLER_DETACH_OBJECT,
|
||||
vm_controller_detach_object),
|
||||
|
||||
+2
-1
@@ -506,8 +506,9 @@ kern_status_t sys_task_duplicate(
|
||||
struct task *new_task = task_create(
|
||||
self->t_name,
|
||||
strlen(self->t_name),
|
||||
NULL);
|
||||
child_handle_table);
|
||||
if (!new_task) {
|
||||
handle_table_destroy(child_handle_table);
|
||||
put_current_task(self);
|
||||
return KERN_NO_MEMORY;
|
||||
}
|
||||
|
||||
+119
-1
@@ -32,7 +32,7 @@ kern_status_t sys_vm_controller_create(kern_handle_t *out)
|
||||
|
||||
kern_status_t sys_vm_controller_recv(
|
||||
kern_handle_t ctrl_handle,
|
||||
equeue_packet_page_request_t *out)
|
||||
equeue_packet_vm_request_t *out)
|
||||
{
|
||||
struct task *self = get_current_task();
|
||||
|
||||
@@ -209,6 +209,116 @@ kern_status_t sys_vm_controller_create_object(
|
||||
return KERN_OK;
|
||||
}
|
||||
|
||||
kern_status_t sys_vm_controller_prepare_attach(
|
||||
kern_handle_t ctrl_handle,
|
||||
uint64_t req_id,
|
||||
kern_handle_t *out_vmo)
|
||||
{
|
||||
struct task *self = get_current_task();
|
||||
if (!out_vmo || !validate_access_w(self, out_vmo, sizeof *out_vmo)) {
|
||||
return KERN_MEMORY_FAULT;
|
||||
}
|
||||
|
||||
kern_status_t status = KERN_OK;
|
||||
unsigned long flags;
|
||||
task_lock_irqsave(self, &flags);
|
||||
|
||||
struct object *ctrl_obj = NULL;
|
||||
handle_flags_t ctrl_flags = 0;
|
||||
status = task_resolve_handle(self, ctrl_handle, &ctrl_obj, &ctrl_flags);
|
||||
if (status != KERN_OK) {
|
||||
task_unlock_irqrestore(self, flags);
|
||||
put_current_task(self);
|
||||
return status;
|
||||
}
|
||||
|
||||
struct handle *out_slot = NULL;
|
||||
kern_handle_t out_handle = KERN_HANDLE_INVALID;
|
||||
status = handle_table_alloc_handle(
|
||||
self->t_handles,
|
||||
KERN_HANDLE_INVALID,
|
||||
&out_slot,
|
||||
&out_handle);
|
||||
if (status != KERN_OK) {
|
||||
object_unref(ctrl_obj);
|
||||
task_unlock_irqrestore(self, flags);
|
||||
put_current_task(self);
|
||||
return status;
|
||||
}
|
||||
|
||||
struct vm_controller *ctrl = vm_controller_cast(ctrl_obj);
|
||||
task_unlock_irqrestore(self, flags);
|
||||
|
||||
if (!ctrl) {
|
||||
object_unref(ctrl_obj);
|
||||
return KERN_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
vm_controller_lock_irqsave(ctrl, &flags);
|
||||
|
||||
struct vm_object *vmo = NULL;
|
||||
status = vm_controller_prepare_attach(ctrl, req_id, &vmo);
|
||||
vm_controller_unlock_irqrestore(ctrl, flags);
|
||||
|
||||
object_unref(ctrl_obj);
|
||||
if (status != KERN_OK) {
|
||||
task_lock_irqsave(self, &flags);
|
||||
handle_table_free_handle(self->t_handles, out_handle);
|
||||
task_unlock_irqrestore(self, flags);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
out_slot->h_object = &vmo->vo_base;
|
||||
put_current_task(self);
|
||||
|
||||
*out_vmo = out_handle;
|
||||
|
||||
return KERN_OK;
|
||||
}
|
||||
|
||||
kern_status_t sys_vm_controller_finish_attach(
|
||||
kern_handle_t ctrl_handle,
|
||||
uint64_t req_id,
|
||||
equeue_key_t new_key)
|
||||
{
|
||||
struct task *self = get_current_task();
|
||||
|
||||
kern_status_t status = KERN_OK;
|
||||
unsigned long flags;
|
||||
task_lock_irqsave(self, &flags);
|
||||
|
||||
struct object *ctrl_obj = NULL;
|
||||
handle_flags_t ctrl_flags = 0;
|
||||
status = task_resolve_handle(self, ctrl_handle, &ctrl_obj, &ctrl_flags);
|
||||
if (status != KERN_OK) {
|
||||
task_unlock_irqrestore(self, flags);
|
||||
put_current_task(self);
|
||||
return status;
|
||||
}
|
||||
|
||||
struct vm_controller *ctrl = vm_controller_cast(ctrl_obj);
|
||||
task_unlock_irqrestore(self, flags);
|
||||
put_current_task(self);
|
||||
|
||||
if (!ctrl) {
|
||||
object_unref(ctrl_obj);
|
||||
return KERN_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
vm_controller_lock_irqsave(ctrl, &flags);
|
||||
|
||||
status = vm_controller_finish_attach(ctrl, req_id, new_key);
|
||||
vm_controller_unlock_irqrestore(ctrl, flags);
|
||||
|
||||
object_unref(ctrl_obj);
|
||||
if (status != KERN_OK) {
|
||||
return status;
|
||||
}
|
||||
|
||||
return KERN_OK;
|
||||
}
|
||||
|
||||
kern_status_t sys_vm_controller_detach_object(
|
||||
kern_handle_t ctrl_handle,
|
||||
kern_handle_t vmo_handle)
|
||||
@@ -315,6 +425,8 @@ kern_status_t sys_vm_controller_supply_pages(
|
||||
|
||||
vm_controller_lock_irqsave(ctrl, &flags);
|
||||
vm_object_lock_pair(src, dst);
|
||||
equeue_key_t requester_key = dst->vo_key;
|
||||
|
||||
status = vm_controller_supply_pages(
|
||||
ctrl,
|
||||
dst,
|
||||
@@ -323,6 +435,12 @@ kern_status_t sys_vm_controller_supply_pages(
|
||||
src_offset,
|
||||
count);
|
||||
vm_object_unlock_pair(src, dst);
|
||||
vm_controller_fulfill_requests(
|
||||
ctrl,
|
||||
requester_key,
|
||||
dst_offset,
|
||||
count,
|
||||
status);
|
||||
vm_controller_unlock_irqrestore(ctrl, flags);
|
||||
|
||||
object_unref(ctrl_obj);
|
||||
|
||||
Reference in New Issue
Block a user