From: Ben Gras Date: Tue, 18 Sep 2012 11:17:52 +0000 (+0200) Subject: VM: full munmap X-Git-Tag: v3.2.1~323 X-Git-Url: http://zhaoyanbai.com/repos/%22http:/www.isc.org/icons/migration?a=commitdiff_plain;h=ed1af3c86c88c1a39dd9b6f189f66dc30e3ed7c5;p=minix.git 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) --- diff --git a/commands/ramdisk/ramdisk.c b/commands/ramdisk/ramdisk.c index cab1b38b9..d46bbca88 100644 --- a/commands/ramdisk/ramdisk.c +++ b/commands/ramdisk/ramdisk.c @@ -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; } diff --git a/drivers/memory/local.h b/drivers/memory/local.h index 498ef2757..eb9e706f7 100644 --- a/drivers/memory/local.h +++ b/drivers/memory/local.h @@ -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)) diff --git a/drivers/memory/memory.c b/drivers/memory/memory.c index e1bfec0c9..a5f3a6cea 100644 --- a/drivers/memory/memory.c +++ b/drivers/memory/memory.c @@ -15,6 +15,7 @@ * Apr 20, 1992 device dependent/independent split (Kees J. Bot) */ +#include #include #include #include @@ -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); diff --git a/etc/rc b/etc/rc index 3900c9abd..597fa0948 100755 --- a/etc/rc +++ b/etc/rc @@ -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 diff --git a/include/minix/com.h b/include/minix/com.h index 1383d0eb8..525e4bbc2 100644 --- a/include/minix/com.h +++ b/include/minix/com.h @@ -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 /*===========================================================================* diff --git a/include/sys/mman.h b/include/sys/mman.h index 7ef464bc0..dc8b1cb4d 100644 --- a/include/sys/mman.h +++ b/include/sys/mman.h @@ -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); diff --git a/lib/libc/include/namespace.h b/lib/libc/include/namespace.h index 077b2a89d..6c876c322 100644 --- a/lib/libc/include/namespace.h +++ b/lib/libc/include/namespace.h @@ -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 */ diff --git a/lib/libc/sys-minix/mmap.c b/lib/libc/sys-minix/mmap.c index 0fb444345..a84034e92 100644 --- a/lib/libc/sys-minix/mmap.c +++ b/lib/libc/sys-minix/mmap.c @@ -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, diff --git a/servers/rs/memory.c b/servers/rs/memory.c index 76bfc99dc..b21d86199 100644 --- a/servers/rs/memory.c +++ b/servers/rs/memory.c @@ -7,10 +7,8 @@ #include "inc.h" #define minix_munmap _minix_munmap -#define minix_munmap_text _minix_munmap_text #include #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); -} diff --git a/servers/vm/main.c b/servers/vm/main.c index a381089aa..25a0b862d 100644 --- a/servers/vm/main.c +++ b/servers/vm/main.c @@ -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); diff --git a/servers/vm/mmap.c b/servers/vm/mmap.c index a54f9b2b4..97fffb040 100644 --- a/servers/vm/mmap.c +++ b/servers/vm/mmap.c @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -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(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, len) != OK) + 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); -} - diff --git a/servers/vm/pb.c b/servers/vm/pb.c index d0ef49f96..b7434c2e0 100644 --- a/servers/vm/pb.c +++ b/servers/vm/pb.c @@ -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); } diff --git a/servers/vm/proto.h b/servers/vm/proto.h index 09ac90bf0..eb5be9f21 100644 --- a/servers/vm/proto.h +++ b/servers/vm/proto.h @@ -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); diff --git a/servers/vm/region.c b/servers/vm/region.c index 58aca9d37..c4379667a 100644 --- a/servers/vm/region.c +++ b/servers/vm/region.c @@ -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); diff --git a/servers/vm/slaballoc.c b/servers/vm/slaballoc.c index e7c149311..e7f1d6586 100644 --- a/servers/vm/slaballoc.c +++ b/servers/vm/slaballoc.c @@ -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);