diff --git a/include/kernel/vm-object.h b/include/kernel/vm-object.h index 1d3f5c2..608aa9b 100644 --- a/include/kernel/vm-object.h +++ b/include/kernel/vm-object.h @@ -98,6 +98,16 @@ extern kern_status_t vm_object_attach_cow( struct vm_object *vmo, unsigned long *irq_flags); +/* prefetch any missing pages in the specified range of a vm-object. + * any lazy-allocated pages will be allocated. + * any missing pages will be requested from the vm-controller, if one is + * attached. */ +extern kern_status_t vm_object_prefetch( + struct vm_object *vo, + off_t offset, + size_t length, + unsigned long *irq_flags); + extern struct vm_page *vm_object_get_page( struct vm_object *vo, off_t offset, diff --git a/syscall/vm-object.c b/syscall/vm-object.c index 4101c5d..ea0f32a 100644 --- a/syscall/vm-object.c +++ b/syscall/vm-object.c @@ -58,20 +58,31 @@ kern_status_t sys_vm_object_read( struct object *obj = NULL; handle_flags_t flags = 0; + unsigned long irq_flags = 0; + task_lock_irqsave(self, &irq_flags); kern_status_t status = task_resolve_handle(self, object, &obj, &flags); + task_unlock_irqrestore(self, irq_flags); + put_current_task(self); + if (status != KERN_OK) { - put_current_task(self); return status; } struct vm_object *vmo = vm_object_cast(obj); if (!vmo) { - put_current_task(self); + object_unref(obj); return KERN_INVALID_ARGUMENT; } - status = vm_object_read(vmo, dst, offset, count, nr_read); - put_current_task(self); + vm_object_lock_irqsave(vmo, &irq_flags); + status = vm_object_prefetch(vmo, offset, count, &irq_flags); + if (status == KERN_OK) { + status = vm_object_read(vmo, dst, offset, count, nr_read); + } + + vm_object_unlock_irqrestore(vmo, irq_flags); + object_unref(obj); + return status; } @@ -97,20 +108,25 @@ kern_status_t sys_vm_object_write( struct object *obj = NULL; handle_flags_t flags = 0; + unsigned long irq_flags = 0; + task_lock_irqsave(self, &irq_flags); kern_status_t status = task_resolve_handle(self, object, &obj, &flags); + task_unlock_irqrestore(self, irq_flags); + put_current_task(self); + if (status != KERN_OK) { - put_current_task(self); return status; } struct vm_object *vmo = vm_object_cast(obj); if (!vmo) { - put_current_task(self); return KERN_INVALID_ARGUMENT; } + vm_object_lock_irqsave(vmo, &irq_flags); status = vm_object_write(vmo, src, offset, count, nr_written); - put_current_task(self); + vm_object_unlock_irqrestore(vmo, irq_flags); + return status; } @@ -162,13 +178,28 @@ kern_status_t sys_vm_object_copy( put_current_task(self); struct vm_object *dst_vmo = vm_object_cast(dst_obj); + if (!dst_vmo) { + return KERN_INVALID_ARGUMENT; + } + struct vm_object *src_vmo = vm_object_cast(src_obj); - if (!dst_vmo || !src_vmo) { - object_unref(src_obj); + if (!src_vmo) { object_unref(dst_obj); return KERN_INVALID_ARGUMENT; } + unsigned long irq_flags = 0; + vm_object_lock_irqsave(src_vmo, &irq_flags); + status = vm_object_prefetch(src_vmo, src_offset, count, &irq_flags); + vm_object_unlock_irqrestore(src_vmo, irq_flags); + + if (status != KERN_OK) { + object_unref(src_obj); + object_unref(dst_obj); + return status; + } + + vm_object_lock_pair_irqsave(src_vmo, dst_vmo, &irq_flags); status = vm_object_copy( dst_vmo, dst_offset, @@ -176,6 +207,7 @@ kern_status_t sys_vm_object_copy( src_offset, count, nr_copied); + vm_object_unlock_pair_irqrestore(src_vmo, dst_vmo, irq_flags); object_unref(src_obj); object_unref(dst_obj); diff --git a/vm/vm-object.c b/vm/vm-object.c index c898125..4d11c98 100644 --- a/vm/vm-object.c +++ b/vm/vm-object.c @@ -516,6 +516,33 @@ static kern_status_t request_page( return status; } +kern_status_t vm_object_prefetch( + struct vm_object *vo, + off_t offset, + size_t length, + unsigned long *irq_flags) +{ + offset &= ~VM_PAGE_MASK; + if (length & VM_PAGE_MASK) { + length &= ~VM_PAGE_MASK; + length += VM_PAGE_SIZE; + } + + for (off_t i = offset; i < offset + length; i += VM_PAGE_SIZE) { + struct vm_page *pg = vm_object_get_page( + vo, + i, + VMO_ALLOCATE_MISSING_PAGE | VMO_REQUEST_MISSING_PAGE, + irq_flags); + if (!pg) { + /* TODO get error code from vm_object_get_page */ + return KERN_NO_MEMORY; + } + } + + return KERN_OK; +} + struct vm_page *vm_object_get_page( struct vm_object *vo, off_t offset,