minix/servers/vm/pb.c
Ben Gras 7421728360 VM: memtype fix
Memory types in VM are described by methods. Each mapped region has
a type, and all pages instantiated get that type on creation.
Individual page types has to be able to change though. This commit
changes the code to use the memory types of the individual pages,
where appropriate, instead of just the higher-level region, in case
it has changed. This is needed to e.g. support future copy-on-write
MAP_PRIVATE mmap modes.

Change-Id: I5523db14ac036ec774a54392fb67f9acb8725731
2013-04-24 10:18:15 +00:00

132 lines
2.7 KiB
C

#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 <sys/param.h>
#include "vm.h"
#include "proto.h"
#include "util.h"
#include "glo.h"
#include "region.h"
#include "sanitycheck.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;
}
if(phys != MAP_NONE)
assert(!(phys % VM_PAGE_SIZE));
USE(newpb,
newpb->phys = phys;
newpb->refcount = 0;
newpb->firstregion = NULL;
);
return newpb;
}
void pb_free(struct phys_block *pb)
{
if(pb->phys != MAP_NONE)
free_mem(ABS2CLICK(pb->phys), 1);
SLABFREE(pb);
}
void pb_link(struct phys_region *newphysr, struct phys_block *newpb,
vir_bytes offset, struct vir_region *parent)
{
USE(newphysr,
newphysr->offset = offset;
newphysr->ph = newpb;
newphysr->parent = parent;
newphysr->next_ph_list = newpb->firstregion;
newphysr->memtype = parent->def_memtype;
newpb->firstregion = newphysr;);
newpb->refcount++;
}
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. */
pb_link(newphysr, newpb, offset, region);
physblock_set(region, offset, newphysr);
return newphysr;
}
/*===========================================================================*
* pb_unreferenced *
*===========================================================================*/
void pb_unreferenced(struct vir_region *region, struct phys_region *pr, int rm)
{
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);
int r;
if((r = region->def_memtype->ev_unreference(pr)) != OK)
panic("unref failed, %d", r);
SLABFREE(pb);
}
pr->ph = NULL;
if(rm) physblock_set(region, pr->offset, NULL);
}