diff --git a/include/kernel/vm-object.h b/include/kernel/vm-object.h index 30a98f8..a74c14c 100644 --- a/include/kernel/vm-object.h +++ b/include/kernel/vm-object.h @@ -89,6 +89,10 @@ extern struct vm_page *vm_object_get_page( off_t offset, enum vm_object_flags flags, unsigned long *irq_flags); +extern kern_status_t vm_object_put_page( + struct vm_object *vo, + off_t offset, + struct vm_page *pg); extern kern_status_t vm_object_read( struct vm_object *vo, diff --git a/vm/vm-object.c b/vm/vm-object.c index 84b08d2..e7c90d7 100644 --- a/vm/vm-object.c +++ b/vm/vm-object.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -342,6 +343,54 @@ static struct vm_page *alloc_page(struct vm_object *vo, off_t offset) return NULL; } +kern_status_t vm_object_put_page( + struct vm_object *vo, + off_t offset, + struct vm_page *pg) +{ + struct btree_node *cur = vo->vo_pages.b_root; + if (!vo->vo_pages.b_root) { + vo->vo_pages.b_root = &pg->p_bnode; + return KERN_OK; + } + + while (cur) { + struct vm_page *page + = BTREE_CONTAINER(struct vm_page, p_bnode, cur); + struct btree_node *next = NULL; + + off_t base = page->p_vmo_offset; + off_t limit = base + vm_page_get_size_bytes(page); + if (offset < base) { + next = btree_left(cur); + } else if (offset >= limit) { + next = btree_right(cur); + } else { + panic("vm_object_put_page: page already exists"); + return KERN_NAME_EXISTS; + } + + if (next) { + cur = next; + continue; + } + + pg->p_vmo_offset = offset; + + if (offset < base) { + btree_put_left(cur, &pg->p_bnode); + } else { + btree_put_right(cur, &pg->p_bnode); + } + + btree_insert_fixup(&vo->vo_pages, &pg->p_bnode); + + return KERN_OK; + } + + return KERN_FATAL_ERROR; +} + static struct vm_page *get_page(struct vm_object *vo, off_t offset) { struct btree_node *cur = vo->vo_pages.b_root;