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
size = atol(argv[1])*KFACTOR;
if(size <= 0) {
fprintf(stderr, "size should be positive.\n");
if(size < 0) {
fprintf(stderr, "size should be non-negative.\n");
return 1;
}

View file

@ -2,8 +2,8 @@
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 \
((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)
*/
#include <assert.h>
#include <minix/drivers.h>
#include <minix/chardriver.h>
#include <minix/blockdriver.h>
@ -100,6 +101,7 @@ static char dev_zero[ZERO_BUF_SIZE];
static void sef_local_startup(void);
static int sef_cb_init_fresh(int type, sef_init_info_t *info);
/*===========================================================================*
* main *
*===========================================================================*/
@ -528,30 +530,6 @@ static int m_block_close(dev_t 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);
}
@ -569,15 +547,20 @@ static int m_block_ioctl(dev_t minor, unsigned int request, endpoint_t endpt,
u32_t ramdev_size;
int s;
void *mem;
int is_imgrd = 0;
if (request != MIOCRAMSIZE)
return EINVAL;
if(minor == IMGRD_DEV)
is_imgrd = 1;
/* 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.
*/
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);
return EINVAL;
}
@ -587,6 +570,8 @@ static int m_block_ioctl(dev_t minor, unsigned int request, endpoint_t endpt,
sizeof(ramdev_size));
if (s != OK)
return s;
if(is_imgrd)
ramdev_size = 0;
if(m_vaddrs[minor] && !cmp64(dv->dv_size, cvul64(ramdev_size))) {
return(OK);
}
@ -597,21 +582,37 @@ static int m_block_ioctl(dev_t minor, unsigned int request, endpoint_t endpt,
return(EBUSY);
}
if(m_vaddrs[minor]) {
u32_t size;
u32_t a, o;
u64_t size;
int r;
if(ex64hi(dv->dv_size)) {
panic("huge old ramdisk");
}
size = ex64lo(dv->dv_size);
minix_munmap((void *) m_vaddrs[minor], size);
size = dv->dv_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;
dv->dv_size = 0;
}
#if DEBUG
printf("MEM:%d: allocating ramdisk of size 0x%x\n", minor, ramdev_size);
#endif
mem = NULL;
/* 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) {
printf("MEM: failed to get memory for ramdisk\n");
return(ENOMEM);

7
etc/rc
View file

@ -121,9 +121,6 @@ start)
printroot >/etc/mtab # /etc/mtab keeps track of mounts
>/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?
if [ "`sysenv bin_img`" = 1 ]
then
@ -149,6 +146,10 @@ start)
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
if [ "`sysenv skip_boot_config`" != 1 ]
then

View file

@ -984,8 +984,6 @@
# define VMUM_ADDR m1_p1
# define VMUM_LEN m1_i1
#define VM_MUNMAP_TEXT (VM_RQ_BASE+19)
/* To VM: forget all my yielded blocks. */
#define VM_FORGETBLOCKS (VM_RQ_BASE+22)
@ -1090,7 +1088,7 @@
/* Basic vm calls allowed to every process. */
#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
/*===========================================================================*

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_for(endpoint_t, void *, size_t, int, int, int, off_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_ro(int d, int s, void *da, void *sa, size_t si);
int vm_unmap(int endpt, void *addr);

View file

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

View file

@ -12,7 +12,6 @@ __weak_alias(vm_getphys, _vm_getphys)
__weak_alias(vm_getrefcount, _vm_getrefcount)
__weak_alias(minix_mmap, _minix_mmap)
__weak_alias(minix_munmap, _minix_munmap)
__weak_alias(minix_munmap_text, _minix_munmap_text)
#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,
endpoint_t s,
void *da,

View file

@ -7,10 +7,8 @@
#include "inc.h"
#define minix_munmap _minix_munmap
#define minix_munmap_text _minix_munmap_text
#include <sys/mman.h>
#undef minix_munmap
#undef minix_munmap_text
int unmap_ok = 0;
@ -24,14 +22,3 @@ int minix_munmap(void *addrstart, vir_bytes 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. */
CALLMAP(VM_MMAP, do_mmap);
CALLMAP(VM_MUNMAP, do_munmap);
CALLMAP(VM_MUNMAP_TEXT, do_munmap);
CALLMAP(VM_MAP_PHYS, do_map_phys);
CALLMAP(VM_UNMAP_PHYS, do_unmap_phys);

View file

@ -18,6 +18,7 @@
#include <minix/debug.h>
#include <sys/mman.h>
#include <sys/param.h>
#include <errno.h>
#include <assert.h>
@ -234,7 +235,7 @@ int do_unmap_phys(message *m)
return EINVAL;
}
if(map_unmap_region(vmp, region, region->length) != OK) {
if(map_unmap_region(vmp, region, 0, region->length) != OK) {
return EINVAL;
}
@ -345,7 +346,7 @@ int do_shared_unmap(message *m)
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");
return OK;
@ -408,38 +409,38 @@ int do_munmap(message *m)
{
int r, n;
struct vmproc *vmp;
vir_bytes addr, len;
vir_bytes addr, len, offset;
struct vir_region *vr;
if((r=vm_isokendpt(m->m_source, &n)) != OK) {
panic("do_mmap: message from strange source: %d", m->m_source);
}
vmp = &vmproc[n];
if(m->m_type == VM_MUNMAP) {
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");
}
assert(m->m_type == VM_MUNMAP);
addr = (vir_bytes) (vir_bytes) m->VMUM_ADDR;
if(!(vr = map_lookup(vmp, addr))) {
printf("VM: unmap: virtual address %p not found in %d\n",
m->VMUM_ADDR, vmp->vm_endpoint);
return EFAULT;
}
if(addr % VM_PAGE_SIZE)
return EFAULT;
len = m->VMUM_LEN;
if (len % VM_PAGE_SIZE)
len += VM_PAGE_SIZE - (len % VM_PAGE_SIZE);
len = roundup(m->VMUM_LEN, VM_PAGE_SIZE);
if(addr != vr->vaddr || len > vr->length || len < VM_PAGE_SIZE) {
return EFAULT;
}
offset = addr - vr->vaddr;
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");
return OK;
@ -483,15 +484,3 @@ int minix_munmap(void *addr, size_t 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 *
*===========================================================================*/
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;
@ -116,5 +116,5 @@ void pb_unreferenced(struct vir_region *region, struct phys_region *pr)
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_shrink(struct vir_region *vr, vir_bytes delta);
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_proc_copy(struct vmproc *dst, struct vmproc *src);
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_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_usage_info(struct vmproc *vmp, struct vm_usage_info *vui);
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_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);
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",
minv, maxv, length);
}
assert(minv < maxv);
assert(minv + length <= maxv);
if(minv + length > maxv)
return SLOT_FAIL;
#define FREEVRANGE_TRY(rangestart, rangeend) { \
vir_bytes frstart = (rangestart), frend = (rangeend); \
@ -642,11 +645,14 @@ static struct phys_region *reset_physr_iter(struct vir_region *region,
/*===========================================================================*
* 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;
physr_iter iter;
vir_bytes end = start+len;
int full = 0;
#if SANITYCHECKS
{
@ -668,18 +674,25 @@ static int map_subfree(struct vir_region *region, vir_bytes len)
}
#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))) {
physr_incr_iter(&iter);
if(pr->offset >= len)
if(pr->offset >= end)
break;
if(pr->offset + VM_PAGE_SIZE <= len) {
pb_unreferenced(region, pr);
physr_start_iter_least(region->phys, &iter);
SLABFREE(pr);
pb_unreferenced(region, pr, !full);
if(!full) {
physr_start_iter(region->phys, &iter,
pr->offset, AVL_GREATER_EQUAL);
}
SLABFREE(pr);
}
if(full)
physr_init(region->phys);
return OK;
}
@ -690,7 +703,7 @@ static int map_free(struct vir_region *region)
{
int r;
if((r=map_subfree(region, region->length)) != OK) {
if((r=map_subfree(region, 0, region->length)) != OK) {
printf("%d\n", __LINE__);
return r;
}
@ -985,7 +998,7 @@ int written;
if((physr = physr_search(region->phys, offset,
AVL_EQUAL))) {
assert(physr->ph->refcount == 1);
pb_unreferenced(region, physr);
pb_unreferenced(region, physr, 1);
SLABFREE(physr);
}
offset += VM_PAGE_SIZE;
@ -1052,7 +1065,7 @@ physr_iter *iter;
SLABSANE(ph);
SLABSANE(ph->ph);
assert(ph->ph->refcount > 1);
pb_unreferenced(region, ph);
pb_unreferenced(region, ph, 1);
assert(ph->ph->refcount >= 1);
SLABFREE(ph);
@ -1653,7 +1666,7 @@ u32_t map_region_get_tag(struct vir_region *vr)
* map_unmap_region *
*========================================================================*/
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
* 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);
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);
return EINVAL;
}
@ -1672,35 +1685,44 @@ int map_unmap_region(struct vmproc *vmp, struct vir_region *r,
return EINVAL;
}
regionstart = r->vaddr;
regionstart = r->vaddr + offset;
if(len == r->length) {
SANITYCHECK(SCL_DETAIL);
/* Whole region disappears. Unlink and free it. */
region_remove(&vmp->vm_regions_avl, r->vaddr);
map_free(r);
} else {
/* unreference its memory */
map_subfree(r, offset, len);
/* if unmap was at start/end of this region, it actually shrinks */
if(offset == 0) {
struct phys_region *pr;
physr_iter iter;
/* Region shrinks. First unreference its memory
* and then shrink the region.
*/
SANITYCHECK(SCL_DETAIL);
map_subfree(r, len);
region_remove(&vmp->vm_regions_avl, r->vaddr);
USE(r,
r->vaddr += 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
* point to the same addresses, make them shrink by the
* same amount.
*/
physr_start_iter(r->phys, &iter, offset, AVL_GREATER_EQUAL);
while((pr = physr_get_iter(&iter))) {
assert(pr->offset >= len);
assert(pr->offset >= offset);
USE(pr, pr->offset -= len;);
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);
@ -2104,7 +2126,7 @@ 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);
pb_unreferenced(region, pr, 1);
physr_start_iter(region->phys, &iter, begin,
AVL_GREATER_EQUAL);
SLABFREE(pr);

View file

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