From 2cbfa7d7d2ea1cf49c51e57225a18ae6213b1d33 Mon Sep 17 00:00:00 2001 From: Max Wash Date: Wed, 1 Apr 2026 18:33:24 +0100 Subject: [PATCH] vm: object: implement creating copy-on-write duplicates of vm-objects --- include/kernel/vm-object.h | 3 +++ vm/vm-object.c | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/include/kernel/vm-object.h b/include/kernel/vm-object.h index a74c14c..d921a0e 100644 --- a/include/kernel/vm-object.h +++ b/include/kernel/vm-object.h @@ -84,6 +84,9 @@ extern struct vm_object *vm_object_create_in_place( size_t data_len, vm_prot_t prot); +/* create a copy-on-write duplicate of a vm-object */ +extern struct vm_object *vm_object_duplicate_cow(struct vm_object *vmo); + extern struct vm_page *vm_object_get_page( struct vm_object *vo, off_t offset, diff --git a/vm/vm-object.c b/vm/vm-object.c index e7c90d7..4b7e0df 100644 --- a/vm/vm-object.c +++ b/vm/vm-object.c @@ -278,6 +278,43 @@ extern struct vm_object *vm_object_create_in_place( return vmo; } +struct vm_object *vm_object_duplicate_cow(struct vm_object *vmo) +{ + struct object *obj = object_create(&vm_object_type); + if (!obj) { + return NULL; + } + + struct vm_object *out = VM_OBJECT_CAST(obj); + + memcpy(out->vo_name, vmo->vo_name, sizeof out->vo_name); + out->vo_flags = vmo->vo_flags; + out->vo_ctrl = vmo->vo_ctrl; + out->vo_prot = vmo->vo_prot; + out->vo_size = vmo->vo_size; + memcpy(out->vo_name, vmo->vo_name, sizeof vmo->vo_name); + + struct btree_node *cur = btree_first(&vmo->vo_pages); + while (cur) { + struct vm_page *pg + = BTREE_CONTAINER(struct vm_page, p_bnode, cur); + int x = atomic_fetch_add(&pg->p_cow_ref, 1); + if (x == 0) { + /* this is the first cow-reference for this page, so + * the address-space it belongs to will need one too */ + atomic_fetch_add(&pg->p_cow_ref, 1); + } + + tracek("convert page %zx to cow %u", + vm_page_get_paddr(pg), + pg->p_cow_ref); + + cur = btree_next(cur); + } + + return out; +} + static struct vm_page *alloc_page(struct vm_object *vo, off_t offset) { struct vm_page *page = NULL;