]> Zhao Yanbai Git Server - minix.git/commitdiff
VM: abstract datastructures a bit
authorBen Gras <ben@minix3.org>
Tue, 18 Sep 2012 11:17:51 +0000 (13:17 +0200)
committerBen Gras <ben@minix3.org>
Tue, 18 Sep 2012 11:17:51 +0000 (13:17 +0200)
. a little less duplication in region.c

servers/vm/Makefile
servers/vm/pb.c [new file with mode: 0644]
servers/vm/proto.h
servers/vm/region.c

index e5f7c850fbd8d0c9fc30c97bd20a1c923cfde8af..48100bf5ee351864520383d9ee5928e21c52c1dd 100644 (file)
@@ -4,7 +4,7 @@
 PROG=  vm
 SRCS=  main.c alloc.c utility.c exit.c fork.c break.c \
        mmap.c slaballoc.c region.c pagefaults.c \
-       physravl.c rs.c queryexit.c yieldedavl.c regionavl.c
+       physravl.c rs.c queryexit.c yieldedavl.c regionavl.c pb.c
 
 DPADD+=        ${LIBSYS}
 LDADD+=        -lsys -lexec
diff --git a/servers/vm/pb.c b/servers/vm/pb.c
new file mode 100644 (file)
index 0000000..d0ef49f
--- /dev/null
@@ -0,0 +1,120 @@
+
+#define        _SYSTEM 1
+
+#include <minix/com.h>
+#include <minix/callnr.h>
+#include <minix/type.h>
+#include <minix/config.h>
+#include <minix/const.h>
+#include <minix/sysutil.h>
+#include <minix/syslib.h>
+#include <minix/debug.h>
+#include <minix/bitmap.h>
+#include <minix/hash.h>
+
+#include <sys/mman.h>
+
+#include <limits.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <stdint.h>
+#include <memory.h>
+#include <sys/param.h>
+
+#include "vm.h"
+#include "proto.h"
+#include "util.h"
+#include "glo.h"
+#include "region.h"
+#include "sanitycheck.h"
+#include "physravl.h"
+#include "memlist.h"
+
+struct phys_block *pb_new(phys_bytes phys)
+{
+       struct phys_block *newpb;
+
+       if(!SLABALLOC(newpb)) {
+               printf("vm: pb_new: couldn't allocate phys block\n");
+               return NULL;
+       }
+
+       assert(!(phys % VM_PAGE_SIZE));
+       assert(phys != MAP_NONE);
+       
+USE(newpb,
+       newpb->phys = phys;
+       newpb->refcount = 0;
+       newpb->firstregion = NULL;
+       );
+
+       return newpb;
+}
+
+struct phys_region *pb_reference(struct phys_block *newpb, vir_bytes offset, struct vir_region *region)
+{
+       struct phys_region *newphysr;
+
+       if(!SLABALLOC(newphysr)) {
+       printf("vm: pb_reference: couldn't allocate phys region\n");
+       return NULL;
+       }
+
+       /* New physical region. */
+USE(newphysr,
+       newphysr->offset = offset;
+       newphysr->ph = newpb;
+       newphysr->parent = region;
+       newphysr->next_ph_list = newpb->firstregion;
+       newpb->firstregion = newphysr;);
+
+       newpb->refcount++;
+       physr_insert(region->phys, newphysr);
+
+       return newphysr;
+}
+
+/*===========================================================================*
+ *                             pb_unreferenced                              *
+ *===========================================================================*/
+void pb_unreferenced(struct vir_region *region, struct phys_region *pr)
+{
+       struct phys_block *pb;
+
+       pb = pr->ph;
+       assert(pb->refcount > 0);
+       USE(pb, pb->refcount--;);
+       assert(pb->refcount >= 0);
+
+       if(pb->firstregion == pr) {
+               USE(pb, pb->firstregion = pr->next_ph_list;);
+       } else {
+               struct phys_region *others;
+
+               for(others = pb->firstregion; others;
+                       others = others->next_ph_list) {
+                       assert(others->ph == pb);
+                       if(others->next_ph_list == pr) {
+                               USE(others, others->next_ph_list = pr->next_ph_list;);
+                               break;
+                       }
+               }
+
+               assert(others); /* Otherwise, wasn't on the list. */
+       }
+
+       if(pb->refcount == 0) {
+               assert(!pb->firstregion);
+               if(region->flags & VR_ANON) {
+                       free_mem(ABS2CLICK(pb->phys), 1);
+               } else if(region->flags & VR_DIRECT) {
+                       ; /* No action required. */
+               } else {
+                       panic("strange phys flags");
+               }
+               SLABFREE(pb);
+       }
+
+       physr_remove(region->phys, pr->offset);
+}
index eb1f58f1a110ed858e1f46e287771ae003a6f2c5..09ac90bf07e99b88c4989fdfdd1ea3f1f7bef3af 100644 (file)
@@ -184,3 +184,9 @@ int do_query_exit(message *m);
 int do_watch_exit(message *m);
 int do_notify_sig(message *m);
 void init_query_exit(void);
+
+/* pb.c */
+struct phys_block *pb_new(phys_bytes phys);
+struct phys_region *pb_reference(struct phys_block *newpb,
+       vir_bytes offset, struct vir_region *region);
+void pb_unreferenced(struct vir_region *region, struct phys_region *pr);
index bc4a085e75118c3bd6a68337c0cfec9377ee00a1..58aca9d37302643c8d380284e250591c92d2d072 100644 (file)
@@ -342,7 +342,7 @@ void blockstats(void)
        LRUCHECK;
 
        for(list = lru_youngest; list; list = list->older) {
-               mem += list->len;
+               mem += VM_PAGE_SIZE;
                blocks++;
        }
 
@@ -512,6 +512,37 @@ static vir_bytes region_find_slot(struct vmproc *vmp,
        return region_find_slot_range(vmp, minv, maxv, length);
 }
 
+struct vir_region *region_new(struct vmproc *vmp, vir_bytes startv, vir_bytes length, int flags)
+{
+       physr_avl *phavl;
+       struct vir_region *newregion;
+
+       if(!(SLABALLOC(newregion))) {
+               printf("vm: region_new: could not allocate\n");
+               return NULL;
+       }
+
+       /* Fill in node details. */
+USE(newregion,
+       newregion->vaddr = startv;
+       newregion->length = length;
+       newregion->flags = flags;
+       newregion->tag = VRT_NONE;
+       newregion->lower = newregion->higher = NULL;
+       newregion->parent = vmp;);
+
+       SLABALLOC(phavl);
+       if(!phavl) {
+               printf("VM: region_new: allocating phys avl failed\n");
+               SLABFREE(newregion);
+               return NULL;
+       }
+       USE(newregion, newregion->phys = phavl;);
+       physr_init(newregion->phys);
+
+       return newregion;
+}
+
 /*===========================================================================*
  *                             map_page_region                              *
  *===========================================================================*/
@@ -527,7 +558,6 @@ int mapflags;
 {
        struct vir_region *newregion;
        vir_bytes startv;
-       physr_avl *phavl;
 
        assert(!(length % VM_PAGE_SIZE));
 
@@ -543,29 +573,11 @@ int mapflags;
                return NULL;
 
        /* Now we want a new region. */
-       if(!SLABALLOC(newregion)) {
+       if(!(newregion = region_new(vmp, startv, length, flags))) {
                printf("VM: map_page_region: allocating region failed\n");
                return NULL;
        }
 
-       /* Fill in node details. */
-USE(newregion,
-       newregion->vaddr = startv;
-       newregion->length = length;
-       newregion->flags = flags;
-       newregion->tag = VRT_NONE;
-       newregion->parent = vmp;);
-
-       SLABALLOC(phavl);
-       if(!phavl) {
-               printf("VM: map_page_region: allocating phys avl failed\n");
-               SLABFREE(newregion);
-               return NULL;
-       }
-       USE(newregion, newregion->phys = phavl;);
-
-       physr_init(newregion->phys);
-
        /* If we know what we're going to map to, map it right away. */
        if(what != MAP_NONE) {
                assert(!(what % VM_PAGE_SIZE));
@@ -614,48 +626,6 @@ USE(newregion,
        return newregion;
 }
 
-/*===========================================================================*
- *                             pb_unreferenced                              *
- *===========================================================================*/
-void pb_unreferenced(struct vir_region *region, struct phys_region *pr)
-{
-       struct phys_block *pb;
-
-       pb = pr->ph;
-       assert(pb->refcount > 0);
-       USE(pb, pb->refcount--;);
-       assert(pb->refcount >= 0);
-
-       if(pb->firstregion == pr) {
-               USE(pb, pb->firstregion = pr->next_ph_list;);
-       } else {
-               struct phys_region *others;
-
-               for(others = pb->firstregion; others;
-                       others = others->next_ph_list) {
-                       assert(others->ph == pb);
-                       if(others->next_ph_list == pr) {
-                               USE(others, others->next_ph_list = pr->next_ph_list;);
-                               break;
-                       }
-               }
-
-               assert(others); /* Otherwise, wasn't on the list. */
-       }
-
-       if(pb->refcount == 0) {
-               assert(!pb->firstregion);
-               if(region->flags & VR_ANON) {
-                       free_mem(ABS2CLICK(pb->phys), 1);
-               } else if(region->flags & VR_DIRECT) {
-                       ; /* No action required. */
-               } else {
-                       panic("strange phys flags");
-               }
-               SLABFREE(pb);
-       }
-}
-
 static struct phys_region *reset_physr_iter(struct vir_region *region,
        physr_iter *iter, vir_bytes offset)
 {
@@ -672,8 +642,7 @@ static struct phys_region *reset_physr_iter(struct vir_region *region,
 /*===========================================================================*
  *                             map_subfree                                  *
  *===========================================================================*/
-static int map_subfree(struct vmproc *vmp,
-       struct vir_region *region, vir_bytes len)
+static int map_subfree(struct vir_region *region, vir_bytes len)
 {
        struct phys_region *pr;
        physr_iter iter;
@@ -706,7 +675,6 @@ static int map_subfree(struct vmproc *vmp,
                        break;
                if(pr->offset + VM_PAGE_SIZE <= len) {
                        pb_unreferenced(region, pr);
-                       physr_remove(region->phys, pr->offset);
                        physr_start_iter_least(region->phys, &iter);
                        SLABFREE(pr);
                }
@@ -718,11 +686,11 @@ static int map_subfree(struct vmproc *vmp,
 /*===========================================================================*
  *                             map_free                                     *
  *===========================================================================*/
-static int map_free(struct vmproc *vmp, struct vir_region *region)
+static int map_free(struct vir_region *region)
 {
        int r;
 
-       if((r=map_subfree(vmp, region, region->length)) != OK) {
+       if((r=map_subfree(region, region->length)) != OK) {
                printf("%d\n", __LINE__);
                return r;
        }
@@ -874,7 +842,7 @@ struct vmproc *vmp;
                nocheck++;
 #endif
                region_remove(&vmp->vm_regions_avl, r->vaddr); /* For sanity checks. */
-               map_free(vmp, r);
+               map_free(r);
 #if SANITYCHECKS
                nocheck--;
 #endif
@@ -989,7 +957,8 @@ int written;
                struct phys_block *newpb = NULL;
 
                /* Allocate things necessary for this chunk of memory. */
-               if(!SLABALLOC(newphysr) || !SLABALLOC(newpb)) {
+               if(!(newpb = pb_new(ml->phys)) ||
+                  !(newphysr = pb_reference(newpb, offset, region))) {
                        printf("map_new_physblock: no memory for the ph slabs\n");
                        if(newphysr) SLABFREE(newphysr);
                        if(newpb) SLABFREE(newpb);
@@ -997,27 +966,6 @@ int written;
                        break;
                }
 
-               assert(!(ml->phys % VM_PAGE_SIZE));
-
-               assert(ml->phys != MAP_NONE);
-
-               USE(newpb,
-               newpb->phys = ml->phys;
-               newpb->refcount = 1;
-               newpb->firstregion = newphysr;);
-
-               /* New physical region. */
-               USE(newphysr,
-               newphysr->offset = offset;
-               newphysr->ph = newpb;
-               newphysr->parent = region;
-               /* No other references to this block. */
-               newphysr->next_ph_list = NULL;);
-
-#if SANITYCHECKS
-               USE(newphysr, newphysr->written = written;);
-#endif
-
                /* Update pagetable. */
                if(map_ph_writept(vmp, region, newphysr) != OK) {
                        printf("map_new_physblock: map_ph_writept failed\n");
@@ -1025,8 +973,6 @@ int written;
                        break;
                }
        
-               physr_insert(region->phys, newphysr);
-
                offset += VM_PAGE_SIZE;
                mapped += VM_PAGE_SIZE;
        }
@@ -1040,7 +986,6 @@ int written;
                                AVL_EQUAL))) {
                                assert(physr->ph->refcount == 1);
                                pb_unreferenced(region, physr);
-                               physr_remove(region->phys, physr->offset);
                                SLABFREE(physr);
                        }
                        offset += VM_PAGE_SIZE;
@@ -1080,7 +1025,7 @@ physr_iter *iter;
 
        /* Warning: this function will free the passed
         * phys_region *ph and replace it (in the same offset)
-        * with one or more others! So both the pointer to it
+        * with another! So both the pointer to it
         * and any iterators over the phys_regions in the vir_region
         * will be invalid on successful return. (Iterators over
         * the vir_region could be invalid on unsuccessful return too.)
@@ -1109,7 +1054,6 @@ physr_iter *iter;
        assert(ph->ph->refcount > 1);
        pb_unreferenced(region, ph);
        assert(ph->ph->refcount >= 1);
-       physr_remove(region->phys, offset);
        SLABFREE(ph);
 
        SANITYCHECK(SCL_DETAIL);
@@ -1400,44 +1344,22 @@ static struct vir_region *map_copy_region(struct vmproc *vmp, struct vir_region
        struct vir_region *newvr;
        struct phys_region *ph;
        physr_iter iter;
-       physr_avl *phavl;
 #if SANITYCHECKS
        int cr;
        cr = count_phys_regions(vr);
 #endif
 
-       if(!SLABALLOC(newvr))
-               return NULL;
-       SLABALLOC(phavl);
-       if(!phavl) {
-               SLABFREE(newvr);
+       if(!(newvr = region_new(vr->parent, vr->vaddr, vr->length, vr->flags)))
                return NULL;
-       }
-       USE(newvr,
-               *newvr = *vr;
-               newvr->lower = newvr->higher = NULL;
-               newvr->phys = phavl;
-       );
-
-       physr_init(newvr->phys);
 
        physr_start_iter_least(vr->phys, &iter);
        while((ph = physr_get_iter(&iter))) {
-               struct phys_region *newph;
-               if(!SLABALLOC(newph)) {
-                       map_free(vmp, newvr);
-                       return NULL;
-               }
-               USE(newph,
-               newph->ph = ph->ph;
-               newph->next_ph_list = NULL;
-               newph->parent = newvr;
-               newph->offset = ph->offset;);
+               struct phys_region *newph = pb_reference(ph->ph, ph->offset, newvr);
+
+               if(!newph) { map_free(newvr); return NULL; }
+
 #if SANITYCHECKS
                USE(newph, newph->written = 0;);
-#endif
-               physr_insert(newvr->phys, newph);
-#if SANITYCHECKS
                assert(count_phys_regions(vr) == cr);
 #endif
                physr_incr_iter(&iter);
@@ -1591,17 +1513,7 @@ struct vir_region *start_src_vr;
                        assert(orig_ph);
                        assert(orig_ph != new_ph);
                        pb = orig_ph->ph;
-                       assert(pb == new_ph->ph);
-
-                       /* Link in new physregion. */
-                       assert(!new_ph->next_ph_list);
-                       USE(new_ph, new_ph->next_ph_list = pb->firstregion;);
-                       USE(pb, pb->firstregion = new_ph;);
-
-                       /* Increase phys block refcount */
-                       assert(pb->refcount > 0);
-                       USE(pb, pb->refcount++;);
-                       assert(pb->refcount > 1);
+                       assert(orig_ph->ph == new_ph->ph);
 
                        /* If the phys block has been shared as SMAP,
                         * do the regular copy. */
@@ -1766,7 +1678,7 @@ int map_unmap_region(struct vmproc *vmp, struct vir_region *r,
                SANITYCHECK(SCL_DETAIL);
                /* Whole region disappears. Unlink and free it. */
                region_remove(&vmp->vm_regions_avl, r->vaddr);
-               map_free(vmp, r);
+               map_free(r);
        } else {
                struct phys_region *pr;
                physr_iter iter;
@@ -1774,7 +1686,7 @@ int map_unmap_region(struct vmproc *vmp, struct vir_region *r,
                 * and then shrink the region.
                 */
                SANITYCHECK(SCL_DETAIL);
-               map_subfree(vmp, r, len);
+               map_subfree(r, len);
                USE(r,
                r->vaddr += len;
                r->length -= len;);
@@ -1855,11 +1767,6 @@ int map_remap(struct vmproc *dvmp, vir_bytes da, size_t size,
 
        physr_start_iter_least(vr->phys, &iter);
        while((ph = physr_get_iter(&iter))) {
-               struct phys_block *pb = ph->ph;
-               assert(!ph->next_ph_list);
-               USE(ph, ph->next_ph_list = pb->firstregion;);
-               USE(pb, pb->firstregion = ph;);
-               USE(pb, pb->refcount++;);
                if(map_ph_writept(dvmp, vr, ph) != OK) {
                        panic("map_remap: map_ph_writept failed");
                }
@@ -2096,18 +2003,9 @@ static int do_map_memory(struct vmproc *vms, struct vmproc *vmd,
                 }
 
                 /* Allocate a new phys region. */
-                if(!SLABALLOC(newphysr))
+                if(!(newphysr = pb_reference(pb, offset_d, vrd)))
                         return ENOMEM;
 
-                /* Set and link the new phys region to the block. */
-                newphysr->ph = pb;
-                newphysr->offset = offset_d;
-                newphysr->parent = vrd;
-                newphysr->next_ph_list = pb->firstregion;
-                pb->firstregion = newphysr;
-                physr_insert(newphysr->parent->phys, newphysr);
-                pb->refcount++;
-
                 /* If a COW share was requested but the phys block has already
                  * been shared as SMAP, give up on COW and copy the block for
                  * the destination phys region now.
@@ -2207,7 +2105,6 @@ static void rm_phys_regions(struct vir_region *region,
         physr_start_iter(region->phys, &iter, begin, AVL_GREATER_EQUAL);
         while((pr = physr_get_iter(&iter)) && pr->offset < begin + length) {
                 pb_unreferenced(region, pr);
-                physr_remove(region->phys, pr->offset);
                 physr_start_iter(region->phys, &iter, begin,
                         AVL_GREATER_EQUAL);
                 SLABFREE(pr);