summaryrefslogtreecommitdiff
path: root/kernel/kalloc.c
diff options
context:
space:
mode:
authorMole Shang <[email protected]>2024-02-13 19:39:56 +0800
committerMole Shang <[email protected]>2024-02-13 19:39:56 +0800
commit89ef6f717ed4b3e702e5f6f906f58fe1ea27d366 (patch)
tree760cce316675479a6cca77551438e8d2cc5fe9ae /kernel/kalloc.c
parentcfae93475dfb4cb5cfe264f4c029136e1447c262 (diff)
parent4a6593f1a6f666c618d303a4858c4c6d31b41c63 (diff)
downloadxv6-labs-89ef6f717ed4b3e702e5f6f906f58fe1ea27d366.tar.gz
xv6-labs-89ef6f717ed4b3e702e5f6f906f58fe1ea27d366.tar.bz2
xv6-labs-89ef6f717ed4b3e702e5f6f906f58fe1ea27d366.zip
Merge branch 'cow' into net
Conflicts: .gitignore Makefile conf/lab.mk kernel/defs.h kernel/syscall.c kernel/vm.c user/pingpong.c user/user.h user/usys.pl
Diffstat (limited to 'kernel/kalloc.c')
-rw-r--r--kernel/kalloc.c57
1 files changed, 56 insertions, 1 deletions
diff --git a/kernel/kalloc.c b/kernel/kalloc.c
index 0699e7e..581f0f6 100644
--- a/kernel/kalloc.c
+++ b/kernel/kalloc.c
@@ -23,10 +23,41 @@ struct {
struct run *freelist;
} kmem;
+int phypg_refcnt[PHYSTOP/PGSIZE];
+
+// Increase the refcnt
+int
+refcnt_inc(uint64 pa)
+{
+ acquire(&kmem.lock);
+ int *prefcnt = &phypg_refcnt[pa/PGSIZE];
+ if(pa > PHYSTOP || *prefcnt < 1)
+ panic("increase refcnt");
+ (*prefcnt)++;
+ release(&kmem.lock);
+ return *prefcnt;
+}
+
+// Decrease the refcnt
+int
+refcnt_dec(uint64 pa)
+{
+ acquire(&kmem.lock);
+ int *prefcnt = &phypg_refcnt[pa/PGSIZE];
+ if(pa > PHYSTOP || *prefcnt < 1)
+ panic("decrease refcnt");
+ (*prefcnt)--;
+ release(&kmem.lock);
+ return *prefcnt;
+}
+
void
kinit()
{
initlock(&kmem.lock, "kmem");
+ // init all refcnt to 1, which would later be freed to 0 by kfree()
+ for(uint64 p = PGROUNDUP((uint64)end); p + PGSIZE <= PHYSTOP; p += PGSIZE)
+ phypg_refcnt[p/PGSIZE] = 1;
freerange(end, (void*)PHYSTOP);
}
@@ -51,6 +82,12 @@ kfree(void *pa)
if(((uint64)pa % PGSIZE) != 0 || (char*)pa < end || (uint64)pa >= PHYSTOP)
panic("kfree");
+ refcnt_dec((uint64)pa);
+
+ if(phypg_refcnt[(uint64)pa/PGSIZE] > 0)
+ // We still have refs to this phy page, do not actually free it
+ return;
+
// Fill with junk to catch dangling refs.
memset(pa, 1, PGSIZE);
@@ -72,11 +109,29 @@ kalloc(void)
acquire(&kmem.lock);
r = kmem.freelist;
- if(r)
+ if(r){
+ if(phypg_refcnt[(uint64)r/PGSIZE])
+ panic("kalloc: invalid refcnt");
+ phypg_refcnt[(uint64)r/PGSIZE] = 1;
kmem.freelist = r->next;
+ }
release(&kmem.lock);
if(r)
memset((char*)r, 5, PGSIZE); // fill with junk
return (void*)r;
}
+
+int
+get_freemem(void)
+{
+ int n;
+ struct run *r;
+
+ acquire(&kmem.lock);
+ for (n = 0, r = kmem.freelist; r; r = r->next)
+ n++;
+ release(&kmem.lock);
+
+ return n * PGSIZE;
+}