From: Ben Gras Date: Tue, 18 Sep 2012 11:17:51 +0000 (+0200) Subject: VM: abstract datastructures a bit X-Git-Tag: v3.2.1~324 X-Git-Url: http://zhaoyanbai.com/repos/%22http:/www.isc.org/icons/ddns-confgen.html?a=commitdiff_plain;h=16c3870b2e78ac249ec966294b4a97849dadc80d;p=minix.git VM: abstract datastructures a bit . a little less duplication in region.c --- diff --git a/servers/vm/Makefile b/servers/vm/Makefile index e5f7c850f..48100bf5e 100644 --- a/servers/vm/Makefile +++ b/servers/vm/Makefile @@ -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 index 000000000..d0ef49f96 --- /dev/null +++ b/servers/vm/pb.c @@ -0,0 +1,120 @@ + +#define _SYSTEM 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#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); +} diff --git a/servers/vm/proto.h b/servers/vm/proto.h index eb1f58f1a..09ac90bf0 100644 --- a/servers/vm/proto.h +++ b/servers/vm/proto.h @@ -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); diff --git a/servers/vm/region.c b/servers/vm/region.c index bc4a085e7..58aca9d37 100644 --- a/servers/vm/region.c +++ b/servers/vm/region.c @@ -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);