From 7fd1493d39b495b3bc869c5f9a6b52831bdcff3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Jasiak?= Date: Sun, 4 Apr 2021 01:06:11 +0200 Subject: [PATCH 1/7] UVM: basic implementation of amap * Add missing PAGE_SHIFT definition in vm_param for AArch64 & mips. * Add definition of uvm_amap. * Add interface for uvm_amap. * Add definition of uvm_aref. * Add simple test for uvm_amap. It's based on NetBSD implementation [1] described by Cranor [2]. [1] https://nxr.netbsd.org/xref/src/sys/uvm/uvm_amap.c [2] https://chuck.cranor.org/p/diss.pdf --- include/aarch64/vm_param.h | 1 + include/mips/vm_param.h | 1 + include/sys/uvm_amap.h | 61 ++++++++++++++ sys/kern/Makefile | 1 + sys/kern/uvm_amap.c | 157 +++++++++++++++++++++++++++++++++++++ sys/tests/Makefile | 1 + sys/tests/uvm_amap.c | 56 +++++++++++++ 7 files changed, 278 insertions(+) create mode 100644 include/sys/uvm_amap.h create mode 100644 sys/kern/uvm_amap.c create mode 100644 sys/tests/uvm_amap.c diff --git a/include/aarch64/vm_param.h b/include/aarch64/vm_param.h index 379002031d..380d483780 100644 --- a/include/aarch64/vm_param.h +++ b/include/aarch64/vm_param.h @@ -3,6 +3,7 @@ #define PAGESIZE 4096 #define SUPERPAGESIZE (1 << 21) /* 2 MB */ +#define PAGE_SHIFT 12 #define KERNEL_SPACE_BEGIN 0xffff000000000000L #define KERNEL_SPACE_END 0xffffffffffffffffL diff --git a/include/mips/vm_param.h b/include/mips/vm_param.h index a5e3fe49fc..06665a5fb3 100644 --- a/include/mips/vm_param.h +++ b/include/mips/vm_param.h @@ -12,6 +12,7 @@ #define PAGESIZE 4096 #define SUPERPAGESIZE (1 << 22) /* 4 MB */ +#define PAGE_SHIFT 12 #define VM_PHYSSEG_NMAX 16 diff --git a/include/sys/uvm_amap.h b/include/sys/uvm_amap.h new file mode 100644 index 0000000000..b51812f1a0 --- /dev/null +++ b/include/sys/uvm_amap.h @@ -0,0 +1,61 @@ +#ifndef _SYS_UVM_AMAP_H_ +#define _SYS_UVM_AMAP_H_ + +#ifndef _KERNEL +#error "Do not use this header file outside kernel code!" +#endif + +#include + +typedef struct uvm_anon uvm_anon_t; +typedef struct uvm_aref uvm_aref_t; +typedef struct uvm_amap uvm_amap_t; + +struct uvm_aref { + int ar_pageoff; /* page offset into amap we start */ + uvm_amap_t *ar_amap; /* pointer to amap */ +}; + +/* + * The upper layer of UVM’s two-layer mapping scheme. + * A uvm_amap describes an area of anonymous memory. + * + * Field markings and the corresponding locks: + * (@) uvm_amap::am_lock + */ +struct uvm_amap { + mtx_t am_lock; + int am_ref; /* (@) reference counter */ + int am_nslot; /* (@) number of allocated slots */ + int am_nused; /* (@) number of used slots */ + int *am_slot; /* (@) slots of used anons - refers to am_bckptr */ + int *am_bckptr; /* (@) stack of used anons - refers to am_anon & am_slots */ + uvm_anon_t **am_anon; /* (@) anons in that map */ +}; + +/* + * amap interface + */ + +/* Allocate a new amap. */ +uvm_amap_t *uvm_amap_alloc(void); +/* Acquire amap->am_lock. */ +void uvm_amap_lock(uvm_amap_t *amap); +/* Release amap->am_lock. */ +void uvm_amap_unlock(uvm_amap_t *amap); +/* Increase reference counter. */ +void uvm_amap_hold(uvm_amap_t *amap); +/* Decrement reference counter and destroy amap if it has reached 0. */ +void uvm_amap_drop(uvm_amap_t *amap); +/* Lookup an anon at offset in amap. */ +uvm_anon_t *uvm_amap_lookup(uvm_aref_t *aref, vaddr_t offset); +/* Add an annon at offset in amap. */ +void uvm_amap_add(uvm_aref_t *aref, uvm_anon_t *anon, vaddr_t offset); +/* Remove an annon from an amap. */ +void uvm_amap_remove(uvm_aref_t *aref, vaddr_t offset); + +/* TODO: ppref */ + +/* TODO: aref interface */ + +#endif /* !_SYS_UVM_AMAP_H_ */ diff --git a/sys/kern/Makefile b/sys/kern/Makefile index 525434d323..76fceaae0d 100644 --- a/sys/kern/Makefile +++ b/sys/kern/Makefile @@ -68,6 +68,7 @@ SOURCES = \ uart_tty.c \ uio.c \ ustack.c \ + uvm_amap.c \ vfs.c \ vfs_name.c \ vfs_readdir.c \ diff --git a/sys/kern/uvm_amap.c b/sys/kern/uvm_amap.c new file mode 100644 index 0000000000..69aec8ede4 --- /dev/null +++ b/sys/kern/uvm_amap.c @@ -0,0 +1,157 @@ +#define KL_LOG KL_VM +#include +#include +#include +#include +#include +#include + +#define AMAP_SLOT_EMPTY (-1) + +static POOL_DEFINE(P_AMAP, "uvm_amap", sizeof(uvm_amap_t)); + +static inline int uvm_amap_slot(uvm_aref_t *aref, vaddr_t offset) { + assert(offset % PAGESIZE == 0); + return (int)(aref->ar_pageoff + (offset >> PAGE_SHIFT)); +} + +uvm_amap_t *uvm_amap_alloc(void) { + uvm_amap_t *amap = pool_alloc(P_AMAP, M_ZERO); + return amap; +} + +void uvm_amap_lock(uvm_amap_t *amap) { + mtx_lock(&amap->am_lock); +} + +void uvm_amap_unlock(uvm_amap_t *amap) { + mtx_unlock(&amap->am_lock); +} + +void uvm_amap_hold(uvm_amap_t *amap) { + assert(mtx_owned(&amap->am_lock)); + amap->am_ref++; +} + +/* TODO: revisit after uvm_anon implementation. */ +static void uvm_anon_free(uvm_anon_t *anon) { + assert(anon != NULL); +} + +static void uvm_amap_free(uvm_amap_t *amap) { + mtx_unlock(&amap->am_lock); + + for (int i = 0; i < amap->am_nused; ++i) { + int slot = amap->am_bckptr[i]; + uvm_anon_free(amap->am_anon[slot]); + } + + kfree(M_TEMP, amap->am_slot); + kfree(M_TEMP, amap->am_bckptr); + kfree(M_TEMP, amap->am_anon); + + pool_free(P_AMAP, amap); +} + +void uvm_amap_drop(uvm_amap_t *amap) { + assert(mtx_owned(&amap->am_lock)); + amap->am_ref--; + + if (amap->am_ref == 0) + uvm_amap_free(amap); +} + +static uvm_anon_t *uvm_amap_lookup_nolock(uvm_amap_t *amap, int slot) { + if (amap->am_nslot <= slot) + return NULL; + return amap->am_anon[slot]; +} + +uvm_anon_t *uvm_amap_lookup(uvm_aref_t *aref, vaddr_t offset) { + uvm_amap_t *amap = aref->ar_amap; + int slot = uvm_amap_slot(aref, offset); + + SCOPED_MTX_LOCK(&amap->am_lock); + return uvm_amap_lookup_nolock(amap, slot); +} + +static void __uvm_amap_extend(uvm_amap_t *amap, int size) { + /* new entries in slot & bckptr will be set to AMAP_SLOT_EMPTY */ + int *slot = kmalloc(M_TEMP, sizeof(int) * size, 0); + int *bckptr = kmalloc(M_TEMP, sizeof(int) * size, 0); + /* new entries in anon will be set to NULL */ + uvm_anon_t **anon = kmalloc(M_TEMP, sizeof(uvm_anon_t *) * size, M_ZERO); + + /* old unused entires will be set to AMAP_SLOT_EMPTY */ + memcpy(slot, amap->am_slot, sizeof(int) * amap->am_nslot); + memcpy(bckptr, amap->am_bckptr, sizeof(int) * amap->am_nslot); + + /* copy pointers only for allocated anons */ + for (int i = 0; i < amap->am_nused; ++i) { + int bslot = amap->am_bckptr[i]; + anon[bslot] = amap->am_anon[bslot]; + } + + /* set new entries to AMAP_SLOT_EMPTY */ + for (int i = amap->am_nslot; i < size; ++i) { + slot[i] = AMAP_SLOT_EMPTY; + bckptr[i] = AMAP_SLOT_EMPTY; + } + + kfree(M_TEMP, amap->am_slot); + kfree(M_TEMP, amap->am_bckptr); + kfree(M_TEMP, amap->am_anon); + + amap->am_slot = slot; + amap->am_bckptr = bckptr; + amap->am_anon = anon; + + amap->am_nslot = size; +} + +static void uvm_amap_extend(uvm_amap_t *amap, int size) { + int capacity = max(amap->am_nslot, 1); + while (capacity < size) + capacity *= 2; + __uvm_amap_extend(amap, capacity); +} + +static void uvm_amap_add_nolock(uvm_amap_t *amap, uvm_anon_t *anon, int slot) { + if (slot >= amap->am_nslot) + uvm_amap_extend(amap, slot); + + assert(amap->am_anon[slot] == NULL); + amap->am_anon[slot] = anon; + amap->am_slot[slot] = amap->am_nused; + amap->am_bckptr[amap->am_nused++] = slot; +} + +void uvm_amap_add(uvm_aref_t *aref, uvm_anon_t *anon, vaddr_t offset) { + uvm_amap_t *amap = aref->ar_amap; + int slot = uvm_amap_slot(aref, offset); + + SCOPED_MTX_LOCK(&amap->am_lock); + uvm_amap_add_nolock(amap, anon, slot); +} + +static void uvm_amap_remove_nolock(uvm_amap_t *amap, int slot) { + assert(amap->am_nslot > slot); + assert(amap->am_anon[slot] != NULL); + + uvm_anon_free(amap->am_anon[slot]); + amap->am_anon[slot] = NULL; + + int bslot = amap->am_slot[slot]; + amap->am_slot[slot] = AMAP_SLOT_EMPTY; + amap->am_bckptr[bslot] = AMAP_SLOT_EMPTY; + swap(amap->am_bckptr[bslot], amap->am_bckptr[amap->am_nused - 1]); + amap->am_nused--; +} + +void uvm_amap_remove(uvm_aref_t *aref, vaddr_t offset) { + uvm_amap_t *amap = aref->ar_amap; + int slot = uvm_amap_slot(aref, offset); + + SCOPED_MTX_LOCK(&amap->am_lock); + uvm_amap_remove_nolock(amap, slot); +} diff --git a/sys/tests/Makefile b/sys/tests/Makefile index 11b37a6a6d..d2a0cedf51 100644 --- a/sys/tests/Makefile +++ b/sys/tests/Makefile @@ -30,6 +30,7 @@ SOURCES = \ turnstile_propagate_many.c \ uiomove.c \ utest.c \ + uvm_amap.c \ vm_map.c \ devclass.c \ vfs.c \ diff --git a/sys/tests/uvm_amap.c b/sys/tests/uvm_amap.c new file mode 100644 index 0000000000..e65bdb9849 --- /dev/null +++ b/sys/tests/uvm_amap.c @@ -0,0 +1,56 @@ +#include +#include +#include +#include +#include +#include + +/* Test internal state of amap. */ +static int test_amap_simple(void) { + uvm_amap_t *amap = uvm_amap_alloc(); + assert(amap != NULL); + + uvm_aref_t aref = {.ar_pageoff = 0, .ar_amap = amap}; + + uvm_amap_add(&aref, (uvm_anon_t *)1, 3 * PAGESIZE); + uvm_amap_add(&aref, (uvm_anon_t *)2, 7 * PAGESIZE); + uvm_amap_add(&aref, (uvm_anon_t *)3, 2 * PAGESIZE); + uvm_amap_add(&aref, (uvm_anon_t *)4, 14 * PAGESIZE); + + uvm_amap_lock(amap); + assert(amap->am_nslot == 16); + assert(amap->am_nused == 4); + + assert(amap->am_anon[3] == (uvm_anon_t *)1); + assert(amap->am_anon[7] == (uvm_anon_t *)2); + assert(amap->am_anon[2] == (uvm_anon_t *)3); + assert(amap->am_anon[14] == (uvm_anon_t *)4); + + assert(amap->am_bckptr[0] == 3); + assert(amap->am_bckptr[1] == 7); + assert(amap->am_bckptr[2] == 2); + assert(amap->am_bckptr[3] == 14); + + assert(amap->am_slot[3] == 0); + assert(amap->am_slot[7] == 1); + assert(amap->am_slot[2] == 2); + assert(amap->am_slot[14] == 3); + uvm_amap_unlock(amap); + + assert(uvm_amap_lookup(&aref, 7 * PAGESIZE) == (uvm_anon_t *)2); + uvm_amap_remove(&aref, 7 * PAGESIZE); + assert(amap->am_nused == 3); + assert(uvm_amap_lookup(&aref, 7 * PAGESIZE) == NULL); + + uvm_amap_lock(amap); + assert(amap->am_slot[7] == -1); + assert(amap->am_bckptr[1] == 14); + assert(amap->am_bckptr[3] == -1); + assert(amap->am_anon[7] == NULL); + + uvm_amap_drop(amap); + + return KTEST_SUCCESS; +} + +KTEST_ADD(uvm_amap_simple, test_amap_simple, 0); From 381a23a1015b42d16e9b47ef3259751e4157ca4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Jasiak?= Date: Tue, 6 Apr 2021 12:46:50 +0200 Subject: [PATCH 2/7] uvm/amap: add missing initialization of mutex --- sys/kern/uvm_amap.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sys/kern/uvm_amap.c b/sys/kern/uvm_amap.c index 69aec8ede4..f169228e8f 100644 --- a/sys/kern/uvm_amap.c +++ b/sys/kern/uvm_amap.c @@ -17,6 +17,7 @@ static inline int uvm_amap_slot(uvm_aref_t *aref, vaddr_t offset) { uvm_amap_t *uvm_amap_alloc(void) { uvm_amap_t *amap = pool_alloc(P_AMAP, M_ZERO); + mtx_init(&amap->am_lock, 0); return amap; } From 8e1a5dd05b00e5bc37e3c588f1e1552870f22de0 Mon Sep 17 00:00:00 2001 From: Franciszek Zdobylak Date: Sun, 11 Apr 2021 11:08:55 +0200 Subject: [PATCH 3/7] Fix locking and add comments --- include/sys/uvm_amap.h | 11 +++++++++-- sys/kern/uvm_amap.c | 3 +-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/include/sys/uvm_amap.h b/include/sys/uvm_amap.h index b51812f1a0..2ce7c2f9e0 100644 --- a/include/sys/uvm_amap.h +++ b/include/sys/uvm_amap.h @@ -43,9 +43,16 @@ uvm_amap_t *uvm_amap_alloc(void); void uvm_amap_lock(uvm_amap_t *amap); /* Release amap->am_lock. */ void uvm_amap_unlock(uvm_amap_t *amap); -/* Increase reference counter. */ + +/* Increase reference counter. + * + * Must be called with amap:am_lock held. */ void uvm_amap_hold(uvm_amap_t *amap); -/* Decrement reference counter and destroy amap if it has reached 0. */ + +/* Decrement reference counter and destroy amap if it has reached 0. + * + * Must be called with amap:am_lock held. + * Releases amap:am_lock. */ void uvm_amap_drop(uvm_amap_t *amap); /* Lookup an anon at offset in amap. */ uvm_anon_t *uvm_amap_lookup(uvm_aref_t *aref, vaddr_t offset); diff --git a/sys/kern/uvm_amap.c b/sys/kern/uvm_amap.c index f169228e8f..94c367eba2 100644 --- a/sys/kern/uvm_amap.c +++ b/sys/kern/uvm_amap.c @@ -40,8 +40,6 @@ static void uvm_anon_free(uvm_anon_t *anon) { } static void uvm_amap_free(uvm_amap_t *amap) { - mtx_unlock(&amap->am_lock); - for (int i = 0; i < amap->am_nused; ++i) { int slot = amap->am_bckptr[i]; uvm_anon_free(amap->am_anon[slot]); @@ -58,6 +56,7 @@ void uvm_amap_drop(uvm_amap_t *amap) { assert(mtx_owned(&amap->am_lock)); amap->am_ref--; + uvm_amap_unlock(amap); if (amap->am_ref == 0) uvm_amap_free(amap); } From d74ca97f31fd2c1734213c7daf3a24ddd495f4dc Mon Sep 17 00:00:00 2001 From: Franciszek Zdobylak Date: Thu, 22 Apr 2021 17:55:16 +0200 Subject: [PATCH 4/7] Rename uvm -> vm (amap) --- include/sys/{uvm_amap.h => vm_amap.h} | 34 ++++++------- sys/kern/{uvm_amap.c => vm_amap.c} | 72 +++++++++++++-------------- sys/tests/uvm_amap.c | 56 --------------------- sys/tests/vm_amap.c | 56 +++++++++++++++++++++ 4 files changed, 109 insertions(+), 109 deletions(-) rename include/sys/{uvm_amap.h => vm_amap.h} (62%) rename sys/kern/{uvm_amap.c => vm_amap.c} (59%) delete mode 100644 sys/tests/uvm_amap.c create mode 100644 sys/tests/vm_amap.c diff --git a/include/sys/uvm_amap.h b/include/sys/vm_amap.h similarity index 62% rename from include/sys/uvm_amap.h rename to include/sys/vm_amap.h index 2ce7c2f9e0..b6bcb9c333 100644 --- a/include/sys/uvm_amap.h +++ b/include/sys/vm_amap.h @@ -7,30 +7,30 @@ #include -typedef struct uvm_anon uvm_anon_t; -typedef struct uvm_aref uvm_aref_t; -typedef struct uvm_amap uvm_amap_t; +typedef struct vm_anon vm_anon_t; +typedef struct vm_aref vm_aref_t; +typedef struct vm_amap vm_amap_t; -struct uvm_aref { +struct vm_aref { int ar_pageoff; /* page offset into amap we start */ - uvm_amap_t *ar_amap; /* pointer to amap */ + vm_amap_t *ar_amap; /* pointer to amap */ }; /* * The upper layer of UVM’s two-layer mapping scheme. - * A uvm_amap describes an area of anonymous memory. + * A vm_amap describes an area of anonymous memory. * * Field markings and the corresponding locks: - * (@) uvm_amap::am_lock + * (@) vm_amap::am_lock */ -struct uvm_amap { +struct vm_amap { mtx_t am_lock; int am_ref; /* (@) reference counter */ int am_nslot; /* (@) number of allocated slots */ int am_nused; /* (@) number of used slots */ int *am_slot; /* (@) slots of used anons - refers to am_bckptr */ int *am_bckptr; /* (@) stack of used anons - refers to am_anon & am_slots */ - uvm_anon_t **am_anon; /* (@) anons in that map */ + vm_anon_t **am_anon; /* (@) anons in that map */ }; /* @@ -38,28 +38,28 @@ struct uvm_amap { */ /* Allocate a new amap. */ -uvm_amap_t *uvm_amap_alloc(void); +vm_amap_t *vm_amap_alloc(void); /* Acquire amap->am_lock. */ -void uvm_amap_lock(uvm_amap_t *amap); +void vm_amap_lock(vm_amap_t *amap); /* Release amap->am_lock. */ -void uvm_amap_unlock(uvm_amap_t *amap); +void vm_amap_unlock(vm_amap_t *amap); /* Increase reference counter. * * Must be called with amap:am_lock held. */ -void uvm_amap_hold(uvm_amap_t *amap); +void vm_amap_hold(vm_amap_t *amap); /* Decrement reference counter and destroy amap if it has reached 0. * * Must be called with amap:am_lock held. * Releases amap:am_lock. */ -void uvm_amap_drop(uvm_amap_t *amap); +void vm_amap_drop(vm_amap_t *amap); /* Lookup an anon at offset in amap. */ -uvm_anon_t *uvm_amap_lookup(uvm_aref_t *aref, vaddr_t offset); +vm_anon_t *vm_amap_lookup(vm_aref_t *aref, vaddr_t offset); /* Add an annon at offset in amap. */ -void uvm_amap_add(uvm_aref_t *aref, uvm_anon_t *anon, vaddr_t offset); +void vm_amap_add(vm_aref_t *aref, vm_anon_t *anon, vaddr_t offset); /* Remove an annon from an amap. */ -void uvm_amap_remove(uvm_aref_t *aref, vaddr_t offset); +void vm_amap_remove(vm_aref_t *aref, vaddr_t offset); /* TODO: ppref */ diff --git a/sys/kern/uvm_amap.c b/sys/kern/vm_amap.c similarity index 59% rename from sys/kern/uvm_amap.c rename to sys/kern/vm_amap.c index 94c367eba2..6195b561bc 100644 --- a/sys/kern/uvm_amap.c +++ b/sys/kern/vm_amap.c @@ -4,45 +4,45 @@ #include #include #include -#include +#include #define AMAP_SLOT_EMPTY (-1) -static POOL_DEFINE(P_AMAP, "uvm_amap", sizeof(uvm_amap_t)); +static POOL_DEFINE(P_AMAP, "vm_amap", sizeof(vm_amap_t)); -static inline int uvm_amap_slot(uvm_aref_t *aref, vaddr_t offset) { +static inline int vm_amap_slot(vm_aref_t *aref, vaddr_t offset) { assert(offset % PAGESIZE == 0); return (int)(aref->ar_pageoff + (offset >> PAGE_SHIFT)); } -uvm_amap_t *uvm_amap_alloc(void) { - uvm_amap_t *amap = pool_alloc(P_AMAP, M_ZERO); +vm_amap_t *vm_amap_alloc(void) { + vm_amap_t *amap = pool_alloc(P_AMAP, M_ZERO); mtx_init(&amap->am_lock, 0); return amap; } -void uvm_amap_lock(uvm_amap_t *amap) { +void vm_amap_lock(vm_amap_t *amap) { mtx_lock(&amap->am_lock); } -void uvm_amap_unlock(uvm_amap_t *amap) { +void vm_amap_unlock(vm_amap_t *amap) { mtx_unlock(&amap->am_lock); } -void uvm_amap_hold(uvm_amap_t *amap) { +void vm_amap_hold(vm_amap_t *amap) { assert(mtx_owned(&amap->am_lock)); amap->am_ref++; } -/* TODO: revisit after uvm_anon implementation. */ -static void uvm_anon_free(uvm_anon_t *anon) { +/* TODO: revisit after vm_anon implementation. */ +static void vm_anon_free(vm_anon_t *anon) { assert(anon != NULL); } -static void uvm_amap_free(uvm_amap_t *amap) { +static void vm_amap_free(vm_amap_t *amap) { for (int i = 0; i < amap->am_nused; ++i) { int slot = amap->am_bckptr[i]; - uvm_anon_free(amap->am_anon[slot]); + vm_anon_free(amap->am_anon[slot]); } kfree(M_TEMP, amap->am_slot); @@ -52,35 +52,35 @@ static void uvm_amap_free(uvm_amap_t *amap) { pool_free(P_AMAP, amap); } -void uvm_amap_drop(uvm_amap_t *amap) { +void vm_amap_drop(vm_amap_t *amap) { assert(mtx_owned(&amap->am_lock)); amap->am_ref--; - uvm_amap_unlock(amap); + vm_amap_unlock(amap); if (amap->am_ref == 0) - uvm_amap_free(amap); + vm_amap_free(amap); } -static uvm_anon_t *uvm_amap_lookup_nolock(uvm_amap_t *amap, int slot) { +static vm_anon_t *vm_amap_lookup_nolock(vm_amap_t *amap, int slot) { if (amap->am_nslot <= slot) return NULL; return amap->am_anon[slot]; } -uvm_anon_t *uvm_amap_lookup(uvm_aref_t *aref, vaddr_t offset) { - uvm_amap_t *amap = aref->ar_amap; - int slot = uvm_amap_slot(aref, offset); +vm_anon_t *vm_amap_lookup(vm_aref_t *aref, vaddr_t offset) { + vm_amap_t *amap = aref->ar_amap; + int slot = vm_amap_slot(aref, offset); SCOPED_MTX_LOCK(&amap->am_lock); - return uvm_amap_lookup_nolock(amap, slot); + return vm_amap_lookup_nolock(amap, slot); } -static void __uvm_amap_extend(uvm_amap_t *amap, int size) { +static void __vm_amap_extend(vm_amap_t *amap, int size) { /* new entries in slot & bckptr will be set to AMAP_SLOT_EMPTY */ int *slot = kmalloc(M_TEMP, sizeof(int) * size, 0); int *bckptr = kmalloc(M_TEMP, sizeof(int) * size, 0); /* new entries in anon will be set to NULL */ - uvm_anon_t **anon = kmalloc(M_TEMP, sizeof(uvm_anon_t *) * size, M_ZERO); + vm_anon_t **anon = kmalloc(M_TEMP, sizeof(vm_anon_t *) * size, M_ZERO); /* old unused entires will be set to AMAP_SLOT_EMPTY */ memcpy(slot, amap->am_slot, sizeof(int) * amap->am_nslot); @@ -109,16 +109,16 @@ static void __uvm_amap_extend(uvm_amap_t *amap, int size) { amap->am_nslot = size; } -static void uvm_amap_extend(uvm_amap_t *amap, int size) { +static void vm_amap_extend(vm_amap_t *amap, int size) { int capacity = max(amap->am_nslot, 1); while (capacity < size) capacity *= 2; - __uvm_amap_extend(amap, capacity); + __vm_amap_extend(amap, capacity); } -static void uvm_amap_add_nolock(uvm_amap_t *amap, uvm_anon_t *anon, int slot) { +static void vm_amap_add_nolock(vm_amap_t *amap, vm_anon_t *anon, int slot) { if (slot >= amap->am_nslot) - uvm_amap_extend(amap, slot); + vm_amap_extend(amap, slot); assert(amap->am_anon[slot] == NULL); amap->am_anon[slot] = anon; @@ -126,19 +126,19 @@ static void uvm_amap_add_nolock(uvm_amap_t *amap, uvm_anon_t *anon, int slot) { amap->am_bckptr[amap->am_nused++] = slot; } -void uvm_amap_add(uvm_aref_t *aref, uvm_anon_t *anon, vaddr_t offset) { - uvm_amap_t *amap = aref->ar_amap; - int slot = uvm_amap_slot(aref, offset); +void vm_amap_add(vm_aref_t *aref, vm_anon_t *anon, vaddr_t offset) { + vm_amap_t *amap = aref->ar_amap; + int slot = vm_amap_slot(aref, offset); SCOPED_MTX_LOCK(&amap->am_lock); - uvm_amap_add_nolock(amap, anon, slot); + vm_amap_add_nolock(amap, anon, slot); } -static void uvm_amap_remove_nolock(uvm_amap_t *amap, int slot) { +static void vm_amap_remove_nolock(vm_amap_t *amap, int slot) { assert(amap->am_nslot > slot); assert(amap->am_anon[slot] != NULL); - uvm_anon_free(amap->am_anon[slot]); + vm_anon_free(amap->am_anon[slot]); amap->am_anon[slot] = NULL; int bslot = amap->am_slot[slot]; @@ -148,10 +148,10 @@ static void uvm_amap_remove_nolock(uvm_amap_t *amap, int slot) { amap->am_nused--; } -void uvm_amap_remove(uvm_aref_t *aref, vaddr_t offset) { - uvm_amap_t *amap = aref->ar_amap; - int slot = uvm_amap_slot(aref, offset); +void vm_amap_remove(vm_aref_t *aref, vaddr_t offset) { + vm_amap_t *amap = aref->ar_amap; + int slot = vm_amap_slot(aref, offset); SCOPED_MTX_LOCK(&amap->am_lock); - uvm_amap_remove_nolock(amap, slot); + vm_amap_remove_nolock(amap, slot); } diff --git a/sys/tests/uvm_amap.c b/sys/tests/uvm_amap.c deleted file mode 100644 index e65bdb9849..0000000000 --- a/sys/tests/uvm_amap.c +++ /dev/null @@ -1,56 +0,0 @@ -#include -#include -#include -#include -#include -#include - -/* Test internal state of amap. */ -static int test_amap_simple(void) { - uvm_amap_t *amap = uvm_amap_alloc(); - assert(amap != NULL); - - uvm_aref_t aref = {.ar_pageoff = 0, .ar_amap = amap}; - - uvm_amap_add(&aref, (uvm_anon_t *)1, 3 * PAGESIZE); - uvm_amap_add(&aref, (uvm_anon_t *)2, 7 * PAGESIZE); - uvm_amap_add(&aref, (uvm_anon_t *)3, 2 * PAGESIZE); - uvm_amap_add(&aref, (uvm_anon_t *)4, 14 * PAGESIZE); - - uvm_amap_lock(amap); - assert(amap->am_nslot == 16); - assert(amap->am_nused == 4); - - assert(amap->am_anon[3] == (uvm_anon_t *)1); - assert(amap->am_anon[7] == (uvm_anon_t *)2); - assert(amap->am_anon[2] == (uvm_anon_t *)3); - assert(amap->am_anon[14] == (uvm_anon_t *)4); - - assert(amap->am_bckptr[0] == 3); - assert(amap->am_bckptr[1] == 7); - assert(amap->am_bckptr[2] == 2); - assert(amap->am_bckptr[3] == 14); - - assert(amap->am_slot[3] == 0); - assert(amap->am_slot[7] == 1); - assert(amap->am_slot[2] == 2); - assert(amap->am_slot[14] == 3); - uvm_amap_unlock(amap); - - assert(uvm_amap_lookup(&aref, 7 * PAGESIZE) == (uvm_anon_t *)2); - uvm_amap_remove(&aref, 7 * PAGESIZE); - assert(amap->am_nused == 3); - assert(uvm_amap_lookup(&aref, 7 * PAGESIZE) == NULL); - - uvm_amap_lock(amap); - assert(amap->am_slot[7] == -1); - assert(amap->am_bckptr[1] == 14); - assert(amap->am_bckptr[3] == -1); - assert(amap->am_anon[7] == NULL); - - uvm_amap_drop(amap); - - return KTEST_SUCCESS; -} - -KTEST_ADD(uvm_amap_simple, test_amap_simple, 0); diff --git a/sys/tests/vm_amap.c b/sys/tests/vm_amap.c new file mode 100644 index 0000000000..95672cc0a3 --- /dev/null +++ b/sys/tests/vm_amap.c @@ -0,0 +1,56 @@ +#include +#include +#include +#include +#include +#include + +/* Test internal state of amap. */ +static int test_amap_simple(void) { + vm_amap_t *amap = vm_amap_alloc(); + assert(amap != NULL); + + vm_aref_t aref = {.ar_pageoff = 0, .ar_amap = amap}; + + vm_amap_add(&aref, (vm_anon_t *)1, 3 * PAGESIZE); + vm_amap_add(&aref, (vm_anon_t *)2, 7 * PAGESIZE); + vm_amap_add(&aref, (vm_anon_t *)3, 2 * PAGESIZE); + vm_amap_add(&aref, (vm_anon_t *)4, 14 * PAGESIZE); + + vm_amap_lock(amap); + assert(amap->am_nslot == 16); + assert(amap->am_nused == 4); + + assert(amap->am_anon[3] == (vm_anon_t *)1); + assert(amap->am_anon[7] == (vm_anon_t *)2); + assert(amap->am_anon[2] == (vm_anon_t *)3); + assert(amap->am_anon[14] == (vm_anon_t *)4); + + assert(amap->am_bckptr[0] == 3); + assert(amap->am_bckptr[1] == 7); + assert(amap->am_bckptr[2] == 2); + assert(amap->am_bckptr[3] == 14); + + assert(amap->am_slot[3] == 0); + assert(amap->am_slot[7] == 1); + assert(amap->am_slot[2] == 2); + assert(amap->am_slot[14] == 3); + vm_amap_unlock(amap); + + assert(vm_amap_lookup(&aref, 7 * PAGESIZE) == (vm_anon_t *)2); + vm_amap_remove(&aref, 7 * PAGESIZE); + assert(amap->am_nused == 3); + assert(vm_amap_lookup(&aref, 7 * PAGESIZE) == NULL); + + vm_amap_lock(amap); + assert(amap->am_slot[7] == -1); + assert(amap->am_bckptr[1] == 14); + assert(amap->am_bckptr[3] == -1); + assert(amap->am_anon[7] == NULL); + + vm_amap_drop(amap); + + return KTEST_SUCCESS; +} + +KTEST_ADD(vm_amap_simple, test_amap_simple, 0); From d24d6399c7391e70924361cb5c7cb18f9bb335a0 Mon Sep 17 00:00:00 2001 From: Franciszek Zdobylak Date: Thu, 22 Apr 2021 18:53:23 +0200 Subject: [PATCH 5/7] fixes --- include/sys/vm_amap.h | 2 +- sys/kern/Makefile | 2 +- sys/tests/Makefile | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/sys/vm_amap.h b/include/sys/vm_amap.h index b6bcb9c333..9bd7f33528 100644 --- a/include/sys/vm_amap.h +++ b/include/sys/vm_amap.h @@ -12,7 +12,7 @@ typedef struct vm_aref vm_aref_t; typedef struct vm_amap vm_amap_t; struct vm_aref { - int ar_pageoff; /* page offset into amap we start */ + int ar_pageoff; /* page offset into amap we start */ vm_amap_t *ar_amap; /* pointer to amap */ }; diff --git a/sys/kern/Makefile b/sys/kern/Makefile index 76fceaae0d..cef36571e7 100644 --- a/sys/kern/Makefile +++ b/sys/kern/Makefile @@ -68,7 +68,7 @@ SOURCES = \ uart_tty.c \ uio.c \ ustack.c \ - uvm_amap.c \ + vm_amap.c \ vfs.c \ vfs_name.c \ vfs_readdir.c \ diff --git a/sys/tests/Makefile b/sys/tests/Makefile index d2a0cedf51..1ea43dc04e 100644 --- a/sys/tests/Makefile +++ b/sys/tests/Makefile @@ -30,7 +30,7 @@ SOURCES = \ turnstile_propagate_many.c \ uiomove.c \ utest.c \ - uvm_amap.c \ + vm_amap.c \ vm_map.c \ devclass.c \ vfs.c \ From d318b04e6f0b6e2bf7b98c5f8e3ce93d3b3fe974 Mon Sep 17 00:00:00 2001 From: Franciszek Zdobylak Date: Fri, 23 Apr 2021 09:53:14 +0200 Subject: [PATCH 6/7] Add amap splitting --- include/sys/vm_amap.h | 3 +++ sys/kern/vm_amap.c | 11 +++++++++++ sys/tests/vm_amap.c | 30 ++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/include/sys/vm_amap.h b/include/sys/vm_amap.h index 9bd7f33528..3661523689 100644 --- a/include/sys/vm_amap.h +++ b/include/sys/vm_amap.h @@ -61,6 +61,9 @@ void vm_amap_add(vm_aref_t *aref, vm_anon_t *anon, vaddr_t offset); /* Remove an annon from an amap. */ void vm_amap_remove(vm_aref_t *aref, vaddr_t offset); +/* Returns aref to second part of amap. */ +vm_aref_t vm_amap_split(vm_aref_t *aref, vaddr_t offset); + /* TODO: ppref */ /* TODO: aref interface */ diff --git a/sys/kern/vm_amap.c b/sys/kern/vm_amap.c index 6195b561bc..8cebe2f6e2 100644 --- a/sys/kern/vm_amap.c +++ b/sys/kern/vm_amap.c @@ -155,3 +155,14 @@ void vm_amap_remove(vm_aref_t *aref, vaddr_t offset) { SCOPED_MTX_LOCK(&amap->am_lock); vm_amap_remove_nolock(amap, slot); } + +vm_aref_t vm_amap_split(vm_aref_t *aref, vaddr_t offset) { + vm_amap_t *amap = aref->ar_amap; + + vm_aref_t new_aref = {.ar_amap = amap, + .ar_pageoff = vm_amap_slot(aref, offset)}; + + WITH_MTX_LOCK (&amap->am_lock) + vm_amap_hold(amap); + return new_aref; +} diff --git a/sys/tests/vm_amap.c b/sys/tests/vm_amap.c index 95672cc0a3..fb24d468bf 100644 --- a/sys/tests/vm_amap.c +++ b/sys/tests/vm_amap.c @@ -11,6 +11,9 @@ static int test_amap_simple(void) { assert(amap != NULL); vm_aref_t aref = {.ar_pageoff = 0, .ar_amap = amap}; + vm_amap_lock(amap); + vm_amap_hold(amap); + vm_amap_unlock(amap); vm_amap_add(&aref, (vm_anon_t *)1, 3 * PAGESIZE); vm_amap_add(&aref, (vm_anon_t *)2, 7 * PAGESIZE); @@ -47,7 +50,34 @@ static int test_amap_simple(void) { assert(amap->am_bckptr[1] == 14); assert(amap->am_bckptr[3] == -1); assert(amap->am_anon[7] == NULL); + vm_amap_unlock(amap); + + vm_aref_t new_aref = vm_amap_split(&aref, 5 * PAGESIZE); + vm_amap_lock(amap); + assert(amap->am_ref == 2); + vm_amap_unlock(amap); + vm_amap_add(&aref, (vm_anon_t *)5, 1 * PAGESIZE); + vm_amap_add(&new_aref, (vm_anon_t *)6, 1 * PAGESIZE); + + vm_amap_lock(amap); + assert(amap->am_nused == 5); + assert(amap->am_anon[1] == (vm_anon_t *)5); + assert(amap->am_anon[6] == (vm_anon_t *)6); + assert(amap->am_bckptr[3] == 1); + assert(amap->am_bckptr[4] == 6); + vm_amap_unlock(amap); + + assert(vm_amap_lookup(&aref, 1 * PAGESIZE) == (vm_anon_t *)5); + assert(vm_amap_lookup(&new_aref, 1 * PAGESIZE) == (vm_anon_t *)6); + assert(vm_amap_lookup(&new_aref, (14 - 5) * PAGESIZE) == (vm_anon_t *)4); + + /* we have to drop amap twice becouse we have two refs now */ + vm_amap_lock(amap); + vm_amap_drop(amap); + + vm_amap_lock(amap); + assert(amap->am_ref == 1); vm_amap_drop(amap); return KTEST_SUCCESS; From eeecda0906c1982e97e7fc39ce164eabf7b0e2d1 Mon Sep 17 00:00:00 2001 From: Franciszek Zdobylak Date: Sun, 25 Apr 2021 14:34:40 +0200 Subject: [PATCH 7/7] Revert "Add amap splitting" This reverts commit d318b04e6f0b6e2bf7b98c5f8e3ce93d3b3fe974. --- include/sys/vm_amap.h | 3 --- sys/kern/vm_amap.c | 11 ----------- sys/tests/vm_amap.c | 30 ------------------------------ 3 files changed, 44 deletions(-) diff --git a/include/sys/vm_amap.h b/include/sys/vm_amap.h index 3661523689..9bd7f33528 100644 --- a/include/sys/vm_amap.h +++ b/include/sys/vm_amap.h @@ -61,9 +61,6 @@ void vm_amap_add(vm_aref_t *aref, vm_anon_t *anon, vaddr_t offset); /* Remove an annon from an amap. */ void vm_amap_remove(vm_aref_t *aref, vaddr_t offset); -/* Returns aref to second part of amap. */ -vm_aref_t vm_amap_split(vm_aref_t *aref, vaddr_t offset); - /* TODO: ppref */ /* TODO: aref interface */ diff --git a/sys/kern/vm_amap.c b/sys/kern/vm_amap.c index 8cebe2f6e2..6195b561bc 100644 --- a/sys/kern/vm_amap.c +++ b/sys/kern/vm_amap.c @@ -155,14 +155,3 @@ void vm_amap_remove(vm_aref_t *aref, vaddr_t offset) { SCOPED_MTX_LOCK(&amap->am_lock); vm_amap_remove_nolock(amap, slot); } - -vm_aref_t vm_amap_split(vm_aref_t *aref, vaddr_t offset) { - vm_amap_t *amap = aref->ar_amap; - - vm_aref_t new_aref = {.ar_amap = amap, - .ar_pageoff = vm_amap_slot(aref, offset)}; - - WITH_MTX_LOCK (&amap->am_lock) - vm_amap_hold(amap); - return new_aref; -} diff --git a/sys/tests/vm_amap.c b/sys/tests/vm_amap.c index fb24d468bf..95672cc0a3 100644 --- a/sys/tests/vm_amap.c +++ b/sys/tests/vm_amap.c @@ -11,9 +11,6 @@ static int test_amap_simple(void) { assert(amap != NULL); vm_aref_t aref = {.ar_pageoff = 0, .ar_amap = amap}; - vm_amap_lock(amap); - vm_amap_hold(amap); - vm_amap_unlock(amap); vm_amap_add(&aref, (vm_anon_t *)1, 3 * PAGESIZE); vm_amap_add(&aref, (vm_anon_t *)2, 7 * PAGESIZE); @@ -50,34 +47,7 @@ static int test_amap_simple(void) { assert(amap->am_bckptr[1] == 14); assert(amap->am_bckptr[3] == -1); assert(amap->am_anon[7] == NULL); - vm_amap_unlock(amap); - - vm_aref_t new_aref = vm_amap_split(&aref, 5 * PAGESIZE); - vm_amap_lock(amap); - assert(amap->am_ref == 2); - vm_amap_unlock(amap); - vm_amap_add(&aref, (vm_anon_t *)5, 1 * PAGESIZE); - vm_amap_add(&new_aref, (vm_anon_t *)6, 1 * PAGESIZE); - - vm_amap_lock(amap); - assert(amap->am_nused == 5); - assert(amap->am_anon[1] == (vm_anon_t *)5); - assert(amap->am_anon[6] == (vm_anon_t *)6); - assert(amap->am_bckptr[3] == 1); - assert(amap->am_bckptr[4] == 6); - vm_amap_unlock(amap); - - assert(vm_amap_lookup(&aref, 1 * PAGESIZE) == (vm_anon_t *)5); - assert(vm_amap_lookup(&new_aref, 1 * PAGESIZE) == (vm_anon_t *)6); - assert(vm_amap_lookup(&new_aref, (14 - 5) * PAGESIZE) == (vm_anon_t *)4); - - /* we have to drop amap twice becouse we have two refs now */ - vm_amap_lock(amap); - vm_amap_drop(amap); - - vm_amap_lock(amap); - assert(amap->am_ref == 1); vm_amap_drop(amap); return KTEST_SUCCESS;