VM: full munmap

complete munmap implementation; single-page references made
a general munmap() implementation possible to write cleanly.

	. memory: let the MIOCRAMSIZE ioctl set the imgrd device
	  size (but only to 0)
	. let the ramdisk command set sizes to 0
	. use this command to set /dev/imgrd to 0 after mounting /usr
	  in /etc/rc, so the boot time ramdisk is freed (about 4MB
	  currently)
This commit is contained in:
Ben Gras 2012-09-18 13:17:52 +02:00
parent 16c3870b2e
commit ed1af3c86c
15 changed files with 116 additions and 134 deletions

View file

@ -28,8 +28,8 @@ main(int argc, char *argv[])
#define KFACTOR 1024 #define KFACTOR 1024
size = atol(argv[1])*KFACTOR; size = atol(argv[1])*KFACTOR;
if(size <= 0) { if(size < 0) {
fprintf(stderr, "size should be positive.\n"); fprintf(stderr, "size should be non-negative.\n");
return 1; return 1;
} }

View file

@ -2,8 +2,8 @@
local defines and declarations local defines and declarations
*/ */
extern unsigned char _binary_imgrd_mfs_start[], *_binary_imgrd_mfs_end; extern unsigned char _binary_imgrd_mfs_start, _binary_imgrd_mfs_end;
#define imgrd _binary_imgrd_mfs_start #define imgrd &_binary_imgrd_mfs_start
#define imgrd_size \ #define imgrd_size \
((size_t)(_binary_imgrd_mfs_end - _binary_imgrd_mfs_start)) (((size_t) &_binary_imgrd_mfs_end - (size_t)&_binary_imgrd_mfs_start))

View file

@ -15,6 +15,7 @@
* Apr 20, 1992 device dependent/independent split (Kees J. Bot) * Apr 20, 1992 device dependent/independent split (Kees J. Bot)
*/ */
#include <assert.h>
#include <minix/drivers.h> #include <minix/drivers.h>
#include <minix/chardriver.h> #include <minix/chardriver.h>
#include <minix/blockdriver.h> #include <minix/blockdriver.h>
@ -100,6 +101,7 @@ static char dev_zero[ZERO_BUF_SIZE];
static void sef_local_startup(void); static void sef_local_startup(void);
static int sef_cb_init_fresh(int type, sef_init_info_t *info); static int sef_cb_init_fresh(int type, sef_init_info_t *info);
/*===========================================================================* /*===========================================================================*
* main * * main *
*===========================================================================*/ *===========================================================================*/
@ -528,30 +530,6 @@ static int m_block_close(dev_t minor)
} }
openct[minor]--; openct[minor]--;
#if 0
/* Special case: free initial ramdisk after it's been unmounted once. */
if(minor == IMGRD_DEV && openct[minor] == 0 && m_vaddrs[IMGRD_DEV]) {
vir_bytes vaddr, vlen;
vaddr = m_vaddrs[IMGRD_DEV];
vlen = imgrd_size;
/* Align `inwards' so as to not unmap more than the initial
* ramdisk image.
*/
if(vaddr % PAGE_SIZE) {
vir_bytes o = PAGE_SIZE - (vaddr % PAGE_SIZE);
vlen -= o;
vaddr += o;
}
if(vlen % PAGE_SIZE) {
vlen -= vlen % PAGE_SIZE;
}
minix_munmap((void *) vaddr, vlen);
m_geom[IMGRD_DEV].dv_base= cvul64(0);
m_geom[IMGRD_DEV].dv_size= cvul64(0);
m_vaddrs[IMGRD_DEV] = 0;
}
#endif
return(OK); return(OK);
} }
@ -569,15 +547,20 @@ static int m_block_ioctl(dev_t minor, unsigned int request, endpoint_t endpt,
u32_t ramdev_size; u32_t ramdev_size;
int s; int s;
void *mem; void *mem;
int is_imgrd = 0;
if (request != MIOCRAMSIZE) if (request != MIOCRAMSIZE)
return EINVAL; return EINVAL;
if(minor == IMGRD_DEV)
is_imgrd = 1;
/* Someone wants to create a new RAM disk with the given size. /* Someone wants to create a new RAM disk with the given size.
* A ramdisk can be created only once, and only on RAM disk device. * A ramdisk can be created only once, and only on RAM disk device.
*/ */
if ((dv = m_block_part(minor)) == NULL) return ENXIO; if ((dv = m_block_part(minor)) == NULL) return ENXIO;
if((minor < RAM_DEV_FIRST || minor > RAM_DEV_LAST) && minor != RAM_DEV_OLD) { if((minor < RAM_DEV_FIRST || minor > RAM_DEV_LAST) &&
minor != RAM_DEV_OLD && !is_imgrd) {
printf("MEM: MIOCRAMSIZE: %d not a ramdisk\n", minor); printf("MEM: MIOCRAMSIZE: %d not a ramdisk\n", minor);
return EINVAL; return EINVAL;
} }
@ -587,6 +570,8 @@ static int m_block_ioctl(dev_t minor, unsigned int request, endpoint_t endpt,
sizeof(ramdev_size)); sizeof(ramdev_size));
if (s != OK) if (s != OK)
return s; return s;
if(is_imgrd)
ramdev_size = 0;
if(m_vaddrs[minor] && !cmp64(dv->dv_size, cvul64(ramdev_size))) { if(m_vaddrs[minor] && !cmp64(dv->dv_size, cvul64(ramdev_size))) {
return(OK); return(OK);
} }
@ -597,21 +582,37 @@ static int m_block_ioctl(dev_t minor, unsigned int request, endpoint_t endpt,
return(EBUSY); return(EBUSY);
} }
if(m_vaddrs[minor]) { if(m_vaddrs[minor]) {
u32_t size; u32_t a, o;
u64_t size;
int r;
if(ex64hi(dv->dv_size)) { if(ex64hi(dv->dv_size)) {
panic("huge old ramdisk"); panic("huge old ramdisk");
} }
size = ex64lo(dv->dv_size); size = dv->dv_size;
minix_munmap((void *) m_vaddrs[minor], size); a = m_vaddrs[minor];
if((o = a % PAGE_SIZE)) {
vir_bytes l = PAGE_SIZE - o;
a += l;
size -= l;
}
size = rounddown(size, PAGE_SIZE);
r = minix_munmap((void *) a, size);
if(r != OK) {
printf("memory: WARNING: munmap failed: %d\n", r);
}
m_vaddrs[minor] = (vir_bytes) NULL; m_vaddrs[minor] = (vir_bytes) NULL;
dv->dv_size = 0;
} }
#if DEBUG #if DEBUG
printf("MEM:%d: allocating ramdisk of size 0x%x\n", minor, ramdev_size); printf("MEM:%d: allocating ramdisk of size 0x%x\n", minor, ramdev_size);
#endif #endif
mem = NULL;
/* Try to allocate a piece of memory for the RAM disk. */ /* Try to allocate a piece of memory for the RAM disk. */
if((mem = minix_mmap(NULL, ramdev_size, PROT_READ|PROT_WRITE, if(ramdev_size > 0 &&
(mem = minix_mmap(NULL, ramdev_size, PROT_READ|PROT_WRITE,
MAP_PREALLOC|MAP_ANON, -1, 0)) == MAP_FAILED) { MAP_PREALLOC|MAP_ANON, -1, 0)) == MAP_FAILED) {
printf("MEM: failed to get memory for ramdisk\n"); printf("MEM: failed to get memory for ramdisk\n");
return(ENOMEM); return(ENOMEM);

7
etc/rc
View file

@ -121,9 +121,6 @@ start)
printroot >/etc/mtab # /etc/mtab keeps track of mounts printroot >/etc/mtab # /etc/mtab keeps track of mounts
>/etc/utmp # /etc/utmp keeps track of logins >/etc/utmp # /etc/utmp keeps track of logins
# Unmount now defunct ramdisk
umount /dev/imgrd > /dev/null || echo "Failed to unmount boot ramdisk"
# Use MFS binary only from kernel image? # Use MFS binary only from kernel image?
if [ "`sysenv bin_img`" = 1 ] if [ "`sysenv bin_img`" = 1 ]
then then
@ -149,6 +146,10 @@ start)
fi fi
fi fi
# Unmount and free now defunct ramdisk
umount /dev/imgrd > /dev/null || echo "Failed to unmount boot ramdisk"
ramdisk 0 /dev/imgrd || echo "Failed to free boot ramdisk"
# Edit settings for boot system services # Edit settings for boot system services
if [ "`sysenv skip_boot_config`" != 1 ] if [ "`sysenv skip_boot_config`" != 1 ]
then then

View file

@ -984,8 +984,6 @@
# define VMUM_ADDR m1_p1 # define VMUM_ADDR m1_p1
# define VMUM_LEN m1_i1 # define VMUM_LEN m1_i1
#define VM_MUNMAP_TEXT (VM_RQ_BASE+19)
/* To VM: forget all my yielded blocks. */ /* To VM: forget all my yielded blocks. */
#define VM_FORGETBLOCKS (VM_RQ_BASE+22) #define VM_FORGETBLOCKS (VM_RQ_BASE+22)
@ -1090,7 +1088,7 @@
/* Basic vm calls allowed to every process. */ /* Basic vm calls allowed to every process. */
#define VM_BASIC_CALLS \ #define VM_BASIC_CALLS \
VM_MMAP, VM_MUNMAP, VM_MUNMAP_TEXT, VM_MAP_PHYS, VM_UNMAP_PHYS, \ VM_MMAP, VM_MUNMAP, VM_MAP_PHYS, VM_UNMAP_PHYS, \
VM_FORGETBLOCKS, VM_FORGETBLOCK, VM_YIELDBLOCKGETBLOCK, VM_INFO VM_FORGETBLOCKS, VM_FORGETBLOCK, VM_YIELDBLOCKGETBLOCK, VM_INFO
/*===========================================================================* /*===========================================================================*

View file

@ -76,7 +76,6 @@ int munmap(void *, size_t);
void * minix_mmap(void *, size_t, int, int, int, off_t); void * minix_mmap(void *, size_t, int, int, int, off_t);
void * minix_mmap_for(endpoint_t, void *, size_t, int, int, int, off_t); void * minix_mmap_for(endpoint_t, void *, size_t, int, int, int, off_t);
int minix_munmap(void *, size_t); int minix_munmap(void *, size_t);
int minix_munmap_text(void *, size_t);
void * vm_remap(int d, int s, void *da, void *sa, size_t si); void * vm_remap(int d, int s, void *da, void *sa, size_t si);
void * vm_remap_ro(int d, int s, void *da, void *sa, size_t si); void * vm_remap_ro(int d, int s, void *da, void *sa, size_t si);
int vm_unmap(int endpt, void *addr); int vm_unmap(int endpt, void *addr);

View file

@ -923,7 +923,6 @@
#define writev _writev #define writev _writev
#define minix_mmap _minix_mmap #define minix_mmap _minix_mmap
#define minix_munmap _minix_munmap #define minix_munmap _minix_munmap
#define minix_munmap_text _minix_munmap_text
#define vfork __vfork14 #define vfork __vfork14
#endif /* __minix */ #endif /* __minix */

View file

@ -12,7 +12,6 @@ __weak_alias(vm_getphys, _vm_getphys)
__weak_alias(vm_getrefcount, _vm_getrefcount) __weak_alias(vm_getrefcount, _vm_getrefcount)
__weak_alias(minix_mmap, _minix_mmap) __weak_alias(minix_mmap, _minix_mmap)
__weak_alias(minix_munmap, _minix_munmap) __weak_alias(minix_munmap, _minix_munmap)
__weak_alias(minix_munmap_text, _minix_munmap_text)
#endif #endif
@ -65,16 +64,6 @@ int minix_munmap(void *addr, size_t len)
} }
int minix_munmap_text(void *addr, size_t len)
{
message m;
m.VMUM_ADDR = addr;
m.VMUM_LEN = len;
return _syscall(VM_PROC_NR, VM_MUNMAP_TEXT, &m);
}
void *vm_remap(endpoint_t d, void *vm_remap(endpoint_t d,
endpoint_t s, endpoint_t s,
void *da, void *da,

View file

@ -7,10 +7,8 @@
#include "inc.h" #include "inc.h"
#define minix_munmap _minix_munmap #define minix_munmap _minix_munmap
#define minix_munmap_text _minix_munmap_text
#include <sys/mman.h> #include <sys/mman.h>
#undef minix_munmap #undef minix_munmap
#undef minix_munmap_text
int unmap_ok = 0; int unmap_ok = 0;
@ -24,14 +22,3 @@ int minix_munmap(void *addrstart, vir_bytes len)
return _minix_munmap(addrstart, len); return _minix_munmap(addrstart, len);
} }
/*===========================================================================*
* minix_munmap_text *
*===========================================================================*/
int minix_munmap_text(void *addrstart, vir_bytes len)
{
if(!unmap_ok)
return ENOSYS;
return _minix_munmap_text(addrstart, len);
}

View file

@ -381,7 +381,6 @@ void init_vm(void)
/* Basic VM calls. */ /* Basic VM calls. */
CALLMAP(VM_MMAP, do_mmap); CALLMAP(VM_MMAP, do_mmap);
CALLMAP(VM_MUNMAP, do_munmap); CALLMAP(VM_MUNMAP, do_munmap);
CALLMAP(VM_MUNMAP_TEXT, do_munmap);
CALLMAP(VM_MAP_PHYS, do_map_phys); CALLMAP(VM_MAP_PHYS, do_map_phys);
CALLMAP(VM_UNMAP_PHYS, do_unmap_phys); CALLMAP(VM_UNMAP_PHYS, do_unmap_phys);

View file

@ -18,6 +18,7 @@
#include <minix/debug.h> #include <minix/debug.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/param.h>
#include <errno.h> #include <errno.h>
#include <assert.h> #include <assert.h>
@ -234,7 +235,7 @@ int do_unmap_phys(message *m)
return EINVAL; return EINVAL;
} }
if(map_unmap_region(vmp, region, region->length) != OK) { if(map_unmap_region(vmp, region, 0, region->length) != OK) {
return EINVAL; return EINVAL;
} }
@ -345,7 +346,7 @@ int do_shared_unmap(message *m)
return EFAULT; return EFAULT;
} }
if(map_unmap_region(vmp, vr, vr->length) != OK) if(map_unmap_region(vmp, vr, 0, vr->length) != OK)
panic("do_shared_unmap: map_unmap_region failed"); panic("do_shared_unmap: map_unmap_region failed");
return OK; return OK;
@ -408,38 +409,38 @@ int do_munmap(message *m)
{ {
int r, n; int r, n;
struct vmproc *vmp; struct vmproc *vmp;
vir_bytes addr, len; vir_bytes addr, len, offset;
struct vir_region *vr; struct vir_region *vr;
if((r=vm_isokendpt(m->m_source, &n)) != OK) { if((r=vm_isokendpt(m->m_source, &n)) != OK) {
panic("do_mmap: message from strange source: %d", m->m_source); panic("do_mmap: message from strange source: %d", m->m_source);
} }
vmp = &vmproc[n]; vmp = &vmproc[n];
if(m->m_type == VM_MUNMAP) { assert(m->m_type == VM_MUNMAP);
addr = (vir_bytes) (vir_bytes) m->VMUM_ADDR; addr = (vir_bytes) (vir_bytes) m->VMUM_ADDR;
} else if(m->m_type == VM_MUNMAP_TEXT) {
addr = (vir_bytes) (vir_bytes) m->VMUM_ADDR;
} else {
panic("do_munmap: strange type");
}
if(!(vr = map_lookup(vmp, addr))) { if(!(vr = map_lookup(vmp, addr))) {
printf("VM: unmap: virtual address %p not found in %d\n", printf("VM: unmap: virtual address %p not found in %d\n",
m->VMUM_ADDR, vmp->vm_endpoint); m->VMUM_ADDR, vmp->vm_endpoint);
return EFAULT; return EFAULT;
} }
if(addr % VM_PAGE_SIZE)
return EFAULT;
len = m->VMUM_LEN; len = roundup(m->VMUM_LEN, VM_PAGE_SIZE);
if (len % VM_PAGE_SIZE)
len += VM_PAGE_SIZE - (len % VM_PAGE_SIZE);
if(addr != vr->vaddr || len > vr->length || len < VM_PAGE_SIZE) { offset = addr - vr->vaddr;
return EFAULT;
}
if(map_unmap_region(vmp, vr, len) != OK) if(offset + len > vr->length) {
printf("munmap: addr 0x%lx len 0x%lx spills out of region\n",
addr, len);
return EFAULT;
}
if(map_unmap_region(vmp, vr, offset, len) != OK)
panic("do_munmap: map_unmap_region failed"); panic("do_munmap: map_unmap_region failed");
return OK; return OK;
@ -483,15 +484,3 @@ int minix_munmap(void *addr, size_t len)
return munmap_lin(laddr, len); return munmap_lin(laddr, len);
} }
/*===========================================================================*
* munmap_text (override for VM) *
*===========================================================================*/
int minix_munmap_text(void *addr, size_t len)
{
vir_bytes laddr;
if(!unmap_ok)
return ENOSYS;
laddr = (vir_bytes) addr;
return munmap_lin(laddr, len);
}

View file

@ -78,7 +78,7 @@ USE(newphysr,
/*===========================================================================* /*===========================================================================*
* pb_unreferenced * * pb_unreferenced *
*===========================================================================*/ *===========================================================================*/
void pb_unreferenced(struct vir_region *region, struct phys_region *pr) void pb_unreferenced(struct vir_region *region, struct phys_region *pr, int rm)
{ {
struct phys_block *pb; struct phys_block *pb;
@ -116,5 +116,5 @@ void pb_unreferenced(struct vir_region *region, struct phys_region *pr)
SLABFREE(pb); SLABFREE(pb);
} }
physr_remove(region->phys, pr->offset); if(rm) physr_remove(region->phys, pr->offset);
} }

View file

@ -132,7 +132,7 @@ int map_region_extend(struct vmproc *vmp, struct vir_region *vr,
int map_region_extend_upto_v(struct vmproc *vmp, vir_bytes vir); int map_region_extend_upto_v(struct vmproc *vmp, vir_bytes vir);
int map_region_shrink(struct vir_region *vr, vir_bytes delta); int map_region_shrink(struct vir_region *vr, vir_bytes delta);
int map_unmap_region(struct vmproc *vmp, struct vir_region *vr, int map_unmap_region(struct vmproc *vmp, struct vir_region *vr,
vir_bytes len); vir_bytes offset, vir_bytes len);
int map_free_proc(struct vmproc *vmp); int map_free_proc(struct vmproc *vmp);
int map_proc_copy(struct vmproc *dst, struct vmproc *src); int map_proc_copy(struct vmproc *dst, struct vmproc *src);
int map_proc_copy_from(struct vmproc *dst, struct vmproc *src, struct int map_proc_copy_from(struct vmproc *dst, struct vmproc *src, struct
@ -158,7 +158,6 @@ int map_remap(struct vmproc *dvmp, vir_bytes da, size_t size, struct
int map_get_phys(struct vmproc *vmp, vir_bytes addr, phys_bytes *r); int map_get_phys(struct vmproc *vmp, vir_bytes addr, phys_bytes *r);
int map_get_ref(struct vmproc *vmp, vir_bytes addr, u8_t *cnt); int map_get_ref(struct vmproc *vmp, vir_bytes addr, u8_t *cnt);
void pb_unreferenced(struct vir_region *region, struct phys_region *pr);
void get_stats_info(struct vm_stats_info *vsi); void get_stats_info(struct vm_stats_info *vsi);
void get_usage_info(struct vmproc *vmp, struct vm_usage_info *vui); void get_usage_info(struct vmproc *vmp, struct vm_usage_info *vui);
int get_region_info(struct vmproc *vmp, struct vm_region_info *vri, int int get_region_info(struct vmproc *vmp, struct vm_region_info *vri, int
@ -189,4 +188,4 @@ void init_query_exit(void);
struct phys_block *pb_new(phys_bytes phys); struct phys_block *pb_new(phys_bytes phys);
struct phys_region *pb_reference(struct phys_block *newpb, struct phys_region *pb_reference(struct phys_block *newpb,
vir_bytes offset, struct vir_region *region); vir_bytes offset, struct vir_region *region);
void pb_unreferenced(struct vir_region *region, struct phys_region *pr); void pb_unreferenced(struct vir_region *region, struct phys_region *pr, int rm);

View file

@ -429,8 +429,11 @@ static vir_bytes region_find_slot_range(struct vmproc *vmp,
printf("VM: 1 minv: 0x%lx maxv: 0x%lx length: 0x%lx\n", printf("VM: 1 minv: 0x%lx maxv: 0x%lx length: 0x%lx\n",
minv, maxv, length); minv, maxv, length);
} }
assert(minv < maxv); assert(minv < maxv);
assert(minv + length <= maxv);
if(minv + length > maxv)
return SLOT_FAIL;
#define FREEVRANGE_TRY(rangestart, rangeend) { \ #define FREEVRANGE_TRY(rangestart, rangeend) { \
vir_bytes frstart = (rangestart), frend = (rangeend); \ vir_bytes frstart = (rangestart), frend = (rangeend); \
@ -642,11 +645,14 @@ static struct phys_region *reset_physr_iter(struct vir_region *region,
/*===========================================================================* /*===========================================================================*
* map_subfree * * map_subfree *
*===========================================================================*/ *===========================================================================*/
static int map_subfree(struct vir_region *region, vir_bytes len) static int map_subfree(struct vir_region *region,
vir_bytes start, vir_bytes len)
{ {
struct phys_region *pr; struct phys_region *pr;
physr_iter iter; physr_iter iter;
vir_bytes end = start+len;
int full = 0;
#if SANITYCHECKS #if SANITYCHECKS
{ {
@ -668,18 +674,25 @@ static int map_subfree(struct vir_region *region, vir_bytes len)
} }
#endif #endif
physr_start_iter_least(region->phys, &iter); if(start == 0 && len == region->length)
full = 1;
physr_start_iter(region->phys, &iter, start, AVL_GREATER_EQUAL);
while((pr = physr_get_iter(&iter))) { while((pr = physr_get_iter(&iter))) {
physr_incr_iter(&iter); physr_incr_iter(&iter);
if(pr->offset >= len) if(pr->offset >= end)
break; break;
if(pr->offset + VM_PAGE_SIZE <= len) { pb_unreferenced(region, pr, !full);
pb_unreferenced(region, pr); if(!full) {
physr_start_iter_least(region->phys, &iter); physr_start_iter(region->phys, &iter,
SLABFREE(pr); pr->offset, AVL_GREATER_EQUAL);
} }
SLABFREE(pr);
} }
if(full)
physr_init(region->phys);
return OK; return OK;
} }
@ -690,7 +703,7 @@ static int map_free(struct vir_region *region)
{ {
int r; int r;
if((r=map_subfree(region, region->length)) != OK) { if((r=map_subfree(region, 0, region->length)) != OK) {
printf("%d\n", __LINE__); printf("%d\n", __LINE__);
return r; return r;
} }
@ -985,7 +998,7 @@ int written;
if((physr = physr_search(region->phys, offset, if((physr = physr_search(region->phys, offset,
AVL_EQUAL))) { AVL_EQUAL))) {
assert(physr->ph->refcount == 1); assert(physr->ph->refcount == 1);
pb_unreferenced(region, physr); pb_unreferenced(region, physr, 1);
SLABFREE(physr); SLABFREE(physr);
} }
offset += VM_PAGE_SIZE; offset += VM_PAGE_SIZE;
@ -1052,7 +1065,7 @@ physr_iter *iter;
SLABSANE(ph); SLABSANE(ph);
SLABSANE(ph->ph); SLABSANE(ph->ph);
assert(ph->ph->refcount > 1); assert(ph->ph->refcount > 1);
pb_unreferenced(region, ph); pb_unreferenced(region, ph, 1);
assert(ph->ph->refcount >= 1); assert(ph->ph->refcount >= 1);
SLABFREE(ph); SLABFREE(ph);
@ -1653,7 +1666,7 @@ u32_t map_region_get_tag(struct vir_region *vr)
* map_unmap_region * * map_unmap_region *
*========================================================================*/ *========================================================================*/
int map_unmap_region(struct vmproc *vmp, struct vir_region *r, int map_unmap_region(struct vmproc *vmp, struct vir_region *r,
vir_bytes len) vir_bytes offset, vir_bytes len)
{ {
/* Shrink the region by 'len' bytes, from the start. Unreference /* Shrink the region by 'len' bytes, from the start. Unreference
* memory it used to reference if any. * memory it used to reference if any.
@ -1662,7 +1675,7 @@ int map_unmap_region(struct vmproc *vmp, struct vir_region *r,
SANITYCHECK(SCL_FUNCTIONS); SANITYCHECK(SCL_FUNCTIONS);
if(len > r->length || (len % VM_PAGE_SIZE)) { if(offset+len > r->length || (len % VM_PAGE_SIZE)) {
printf("VM: bogus length 0x%lx\n", len); printf("VM: bogus length 0x%lx\n", len);
return EINVAL; return EINVAL;
} }
@ -1672,35 +1685,44 @@ int map_unmap_region(struct vmproc *vmp, struct vir_region *r,
return EINVAL; return EINVAL;
} }
regionstart = r->vaddr; regionstart = r->vaddr + offset;
if(len == r->length) { /* unreference its memory */
SANITYCHECK(SCL_DETAIL); map_subfree(r, offset, len);
/* Whole region disappears. Unlink and free it. */
region_remove(&vmp->vm_regions_avl, r->vaddr); /* if unmap was at start/end of this region, it actually shrinks */
map_free(r); if(offset == 0) {
} else {
struct phys_region *pr; struct phys_region *pr;
physr_iter iter; physr_iter iter;
/* Region shrinks. First unreference its memory
* and then shrink the region. region_remove(&vmp->vm_regions_avl, r->vaddr);
*/
SANITYCHECK(SCL_DETAIL);
map_subfree(r, len);
USE(r, USE(r,
r->vaddr += len; r->vaddr += len;
r->length -= len;); r->length -= len;);
physr_start_iter_least(r->phys, &iter);
region_insert(&vmp->vm_regions_avl, r);
/* vaddr has increased; to make all the phys_regions /* vaddr has increased; to make all the phys_regions
* point to the same addresses, make them shrink by the * point to the same addresses, make them shrink by the
* same amount. * same amount.
*/ */
physr_start_iter(r->phys, &iter, offset, AVL_GREATER_EQUAL);
while((pr = physr_get_iter(&iter))) { while((pr = physr_get_iter(&iter))) {
assert(pr->offset >= len); assert(pr->offset >= offset);
USE(pr, pr->offset -= len;); USE(pr, pr->offset -= len;);
physr_incr_iter(&iter); physr_incr_iter(&iter);
} }
} else if(offset + len == r->length) {
assert(len <= r->length);
r->length -= len;
}
if(r->length == 0) {
/* Whole region disappears. Unlink and free it. */
region_remove(&vmp->vm_regions_avl, r->vaddr);
map_free(r);
} }
SANITYCHECK(SCL_DETAIL); SANITYCHECK(SCL_DETAIL);
@ -2104,7 +2126,7 @@ static void rm_phys_regions(struct vir_region *region,
physr_start_iter(region->phys, &iter, begin, AVL_GREATER_EQUAL); physr_start_iter(region->phys, &iter, begin, AVL_GREATER_EQUAL);
while((pr = physr_get_iter(&iter)) && pr->offset < begin + length) { while((pr = physr_get_iter(&iter)) && pr->offset < begin + length) {
pb_unreferenced(region, pr); pb_unreferenced(region, pr, 1);
physr_start_iter(region->phys, &iter, begin, physr_start_iter(region->phys, &iter, begin,
AVL_GREATER_EQUAL); AVL_GREATER_EQUAL);
SLABFREE(pr); SLABFREE(pr);

View file

@ -205,12 +205,11 @@ static int checklist(char *file, int line,
MYASSERT(n->sdh.magic1 == MAGIC1); MYASSERT(n->sdh.magic1 == MAGIC1);
MYASSERT(n->sdh.magic2 == MAGIC2); MYASSERT(n->sdh.magic2 == MAGIC2);
#endif #endif
MYASSERT(n->sdh.list == l);
MYASSERT(usedpages_add(n->sdh.phys, VM_PAGE_SIZE) == OK); MYASSERT(usedpages_add(n->sdh.phys, VM_PAGE_SIZE) == OK);
if(n->sdh.prev) if(n->sdh.prev)
MYASSERT(n->sdh.prev->sdh.next == n); MYASSERT(n->sdh.prev->sdh.next == n);
else else
MYASSERT(s->list_head[l] == n); MYASSERT(s->list_head == n);
if(n->sdh.next) MYASSERT(n->sdh.next->sdh.prev == n); if(n->sdh.next) MYASSERT(n->sdh.next->sdh.prev == n);
for(i = 0; i < USEELEMENTS*8; i++) for(i = 0; i < USEELEMENTS*8; i++)
if(i >= ITEMSPERPAGE(bytes)) if(i >= ITEMSPERPAGE(bytes))
@ -233,7 +232,6 @@ void slab_sanitycheck(char *file, int line)
{ {
int s; int s;
for(s = 0; s < SLABSIZES; s++) { for(s = 0; s < SLABSIZES; s++) {
int l;
checklist(file, line, &slabs[s], s + MINSIZE); checklist(file, line, &slabs[s], s + MINSIZE);
} }
} }
@ -247,6 +245,8 @@ int slabsane_f(char *file, int line, void *mem, int bytes)
struct slabdata *f; struct slabdata *f;
int i; int i;
bytes = roundup(bytes, OBJALIGN);
return (objstats(mem, bytes, &s, &f, &i) == OK); return (objstats(mem, bytes, &s, &f, &i) == OK);
} }
#endif #endif
@ -508,7 +508,6 @@ void slabstats(void)
n++; n++;
if(n%1000) return; if(n%1000) return;
for(s = 0; s < SLABSIZES; s++) { for(s = 0; s < SLABSIZES; s++) {
int l;
int b, t; int b, t;
b = s + MINSIZE; b = s + MINSIZE;
t = checklist(__FILE__, __LINE__, &slabs[s], b); t = checklist(__FILE__, __LINE__, &slabs[s], b);