diff --git a/include/kernel/vm-object.h b/include/kernel/vm-object.h index 093ebf9..ab20a06 100644 --- a/include/kernel/vm-object.h +++ b/include/kernel/vm-object.h @@ -85,6 +85,13 @@ extern kern_status_t vm_object_copy( off_t src_offset, size_t count, size_t *nr_copied); +extern kern_status_t vm_object_transfer( + struct vm_object *dst, + off_t dst_offset, + struct vm_object *src, + off_t src_offset, + size_t count, + size_t *nr_moved); DEFINE_OBJECT_LOCK_FUNCTION(vm_object, vo_base) diff --git a/vm/vm-object.c b/vm/vm-object.c index b09e1c3..2e07763 100644 --- a/vm/vm-object.c +++ b/vm/vm-object.c @@ -780,3 +780,50 @@ kern_status_t vm_object_copy( return KERN_OK; } + +kern_status_t vm_object_transfer( + struct vm_object *dst, + off_t dst_offset, + struct vm_object *src, + off_t src_offset, + size_t count, + size_t *nr_moved) +{ + dst_offset &= ~VM_PAGE_MASK; + src_offset &= ~VM_PAGE_MASK; + + if (count & VM_PAGE_MASK) { + count &= ~VM_PAGE_MASK; + count += VM_PAGE_SIZE; + } + + size_t moved = 0; + for (size_t i = 0; i < count; i += VM_PAGE_SIZE) { + struct vm_page *src_pg + = vm_object_get_page(src, src_offset + i); + if (!src_pg) { + continue; + } + + btree_delete(&src->vo_pages, &src_pg->p_bnode); + + struct vm_page *dst_pg + = vm_object_get_page(src, dst_offset + i); + if (dst_pg) { + vm_page_free(src_pg); + continue; + } + + put_page(dst, src_pg, dst_offset + i); + moved += VM_PAGE_SIZE; + } + + /* TODO evict all page table entries that reference the transferred + * pages in `src` */ + + if (nr_moved) { + *nr_moved = moved; + } + + return KERN_OK; +}