]> Zhao Yanbai Git Server - minix.git/commitdiff
vm: Improve live update support. 91/3091/2
authorCristiano Giuffrida <giuffrida@cs.vu.nl>
Tue, 11 Mar 2014 23:13:37 +0000 (00:13 +0100)
committerDavid van Moolenbroek <david@minix3.org>
Wed, 16 Sep 2015 11:06:41 +0000 (11:06 +0000)
Change-Id: I02da3ea32cd05c4ed84a6e199236e5df6e25cb60

12 files changed:
minix/lib/libsys/vm_memctl.c
minix/servers/vm/exit.c
minix/servers/vm/glo.h
minix/servers/vm/main.c
minix/servers/vm/pagetable.c
minix/servers/vm/proto.h
minix/servers/vm/region.c
minix/servers/vm/region.h
minix/servers/vm/rs.c
minix/servers/vm/utility.c
minix/servers/vm/vm.h
minix/servers/vm/vmproc.h

index 0637476ccd592b16123ef00fc4fa18c130180176..35d9b171e08a7ce5e39e7312b2a834b7ac93eb87 100644 (file)
@@ -21,7 +21,7 @@ vm_memctl(endpoint_t ep, int req, void** addr, size_t *len)
        if(addr) {
                *addr = m.VM_RS_CTL_ADDR;
        }
-       if(addr) {
+       if(len) {
                *len = m.VM_RS_CTL_LEN;
        }
 
index a62a7d49091170cc04941e499202b1ef58eb3848..dd0ee6d630408bb9060fceb6f05ec383692ddb8c 100644 (file)
@@ -75,6 +75,10 @@ SANITYCHECK(SCL_FUNCTIONS);
                printf("VM: unannounced VM_EXIT %d\n", msg->VME_ENDPOINT);
                return EINVAL;
        }
+       if(vmp->vm_flags & VMF_VM_INSTANCE) {
+           vmp->vm_flags &= ~VMF_VM_INSTANCE;
+           num_vm_instances--;
+       }
 
        {
                /* Free pagetable and pages allocated by pt code. */
index d4c1e71b18f0f069acdee6ffeff9b588a0dd04dc..d808aa213d392cf90f88ab992b9d5a02b498281d 100644 (file)
@@ -40,3 +40,4 @@ EXTERN  mem_type_t mem_type_anon,       /* anonymous memory */
 
 /* total number of memory pages */
 EXTERN int total_pages;
+EXTERN int num_vm_instances;
index 0fd120372227ad696a6b1498e1182383d30c9dd4..3e20a2da70278308e0f7bc75f539578d451be67e 100644 (file)
@@ -515,6 +515,10 @@ void init_vm(void)
 
        /* Initialize the structures for queryexit */
        init_query_exit();
+
+       /* Mark VM instances. */
+       num_vm_instances = 1;
+       vmproc[VM_PROC_NR].vm_flags |= VMF_VM_INSTANCE;
 }
 
 /*===========================================================================*
index e0fe60af2759a5be16c0a8cb01afcf16590ef7fd..342774d379aeedba99ad4d656faa5a09b6fb1792 100644 (file)
@@ -83,8 +83,7 @@ static struct {
        phys_bytes phys;
 } sparepagedirs[SPAREPAGEDIRS];
 
-extern char _end;      
-#define is_staticaddr(v) ((vir_bytes) (v) < (vir_bytes) &_end)
+#define is_staticaddr(v) ((vir_bytes) (v) < VM_OWN_HEAPSTART)
 
 #define MAX_KERNMAPPINGS 10
 static struct {
@@ -154,10 +153,8 @@ static u32_t findhole(int pages)
        u32_t holev = NO_MEM;
        int holesize = -1;
 
-       vmin = (vir_bytes) (&_end); /* marks end of VM BSS */
-       vmin += 1024*1024*1024; /* reserve 1GB virtual address space for VM heap */
-       vmin &= ARCH_VM_ADDR_MASK; 
-       vmax = vmin + 100 * 1024 * 1024; /* allow 100MB of address space for VM */
+       vmin = VM_OWN_MMAPBASE;
+       vmax = VM_OWN_MMAPTOP;
 
        /* Input sanity check. */
        assert(vmin + VM_PAGE_SIZE >= vmin);
@@ -678,8 +675,7 @@ int pt_map_in_range(struct vmproc *src_vmp, struct vmproc *dst_vmp,
 int pt_ptmap(struct vmproc *src_vmp, struct vmproc *dst_vmp)
 {
 /* Transfer mappings to page dir and page tables from source process and
- * destination process. Make sure all the mappings are above the stack, not
- * to corrupt valid mappings in the data segment of the destination process.
+ * destination process.
  */
        int pde, r;
        phys_bytes physaddr;
index b96c31e2763db29a7715090346fc8796c4a5c08e..79d3ac4c6902f83e07190dbb8c89e35b00cbc41d 100644 (file)
@@ -47,7 +47,9 @@ int vm_isokendpt(endpoint_t ep, int *proc);
 int get_stack_ptr(int proc_nr, vir_bytes *sp);
 int do_info(message *);
 int swap_proc_slot(struct vmproc *src_vmp, struct vmproc *dst_vmp);
-int swap_proc_dyn_data(struct vmproc *src_vmp, struct vmproc *dst_vmp);
+int swap_proc_dyn_data(struct vmproc *src_vmp, struct vmproc *dst_vmp,
+    int sys_upd_flags);
+void adjust_proc_refs(void);
 int do_getrusage(message *m);
 
 /* exit.c */
@@ -149,8 +151,8 @@ int map_unmap_region(struct vmproc *vmp, struct vir_region *vr,
 int map_unmap_range(struct vmproc *vmp, vir_bytes, vir_bytes);
 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
-       vir_region *start_src_vr);
+int map_proc_copy_range(struct vmproc *dst, struct vmproc *src, struct
+       vir_region *start_src_vr, struct vir_region *end_src_vr);
 struct vir_region *map_lookup(struct vmproc *vmp, vir_bytes addr,
        struct phys_region **pr);
 int map_pf(struct vmproc *vmp, struct vir_region *region, vir_bytes
@@ -172,10 +174,7 @@ void physblock_set(struct vir_region *region, vir_bytes offset,
 int map_ph_writept(struct vmproc *vmp, struct vir_region *vr,
         struct phys_region *pr);
 
-struct vir_region * map_region_lookup_tag(struct vmproc *vmp, u32_t
-       tag);
-void map_region_set_tag(struct vir_region *vr, u32_t tag);
-u32_t map_region_get_tag(struct vir_region *vr);
+struct vir_region* map_region_lookup_type(struct vmproc *vmp, u32_t flags);
 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);
 unsigned int physregions(struct vir_region *vr);
index 84b308698a16128caa3d4dd9145c6cf29dacafdd..5816b747c47358d87e356af260fdb6e1e9d2926c 100644 (file)
@@ -933,28 +933,30 @@ int map_proc_copy(struct vmproc *dst, struct vmproc *src)
 /* Copy all the memory regions from the src process to the dst process. */
        region_init(&dst->vm_regions_avl);
 
-       return map_proc_copy_from(dst, src, NULL);
+       return map_proc_copy_range(dst, src, NULL, NULL);
 }
 
 /*========================================================================*
- *                          map_proc_copy_from                           *
+ *                          map_proc_copy_range                                  *
  *========================================================================*/
-int map_proc_copy_from(struct vmproc *dst, struct vmproc *src,
-       struct vir_region *start_src_vr)
+int map_proc_copy_range(struct vmproc *dst, struct vmproc *src,
+       struct vir_region *start_src_vr, struct vir_region *end_src_vr)
 {
        struct vir_region *vr;
        region_iter v_iter;
 
        if(!start_src_vr)
                start_src_vr = region_search_least(&src->vm_regions_avl);
+       if(!end_src_vr)
+               end_src_vr = region_search_greatest(&src->vm_regions_avl);
 
-       assert(start_src_vr);
+       assert(start_src_vr && end_src_vr);
        assert(start_src_vr->parent == src);
        region_start_iter(&src->vm_regions_avl, &v_iter,
                start_src_vr->vaddr, AVL_EQUAL);
        assert(region_get_iter(&v_iter) == start_src_vr);
 
-       /* Copy source regions after the destination's last region (if any). */
+       /* Copy source regions into the destination. */
 
        SANITYCHECK(SCL_FUNCTIONS);
 
@@ -982,6 +984,9 @@ int map_proc_copy_from(struct vmproc *dst, struct vmproc *src,
                }
        }
 #endif
+               if(vr == end_src_vr) {
+                       break;
+               }
                region_incr_iter(&v_iter);
        }
 
@@ -1290,6 +1295,26 @@ int map_unmap_range(struct vmproc *vmp, vir_bytes unmap_start, vir_bytes length)
 
 }
 
+/*========================================================================*
+ *                       map_region_lookup_type                          *
+ *========================================================================*/
+struct vir_region* map_region_lookup_type(struct vmproc *vmp, u32_t type)
+{
+       struct vir_region *vr;
+       struct phys_region *pr;
+       vir_bytes used = 0, weighted = 0;
+       region_iter v_iter;
+       region_start_iter_least(&vmp->vm_regions_avl, &v_iter);
+
+       while((vr = region_get_iter(&v_iter))) {
+               region_incr_iter(&v_iter);
+               if(vr->flags & type)
+                       return vr;
+       }
+
+       return NULL;
+}
+
 /*========================================================================*
  *                             map_get_phys                              *
  *========================================================================*/
index 29982abbd4ff5f0bea8d4fad71cb7e7eb2493005..934ec79b6b9e676da7aeca0f8ead0227b0d60233 100644 (file)
@@ -76,9 +76,10 @@ typedef struct vir_region {
 /* Mapping type: */
 #define VR_ANON                0x100   /* Memory to be cleared and allocated */
 #define VR_DIRECT      0x200   /* Mapped, but not managed by VM */
+#define VR_PREALLOC_MAP        0x400   /* Preallocated map. */
 
-/* map_page_region flags */
-#define MF_PREALLOC    0x01
+/* map_page_region_flags */
+#define MF_PREALLOC    0x01
 
 #endif
 
index 3587e8617366c17258a53c428a790b0468db920f..067eb93318dd236a690d84a8e3d5ac2ae417e68e 100644 (file)
@@ -16,6 +16,8 @@
 #include <minix/bitmap.h>
 #include <minix/rs.h>
 
+#include <sys/mman.h>
+
 #include <errno.h>
 #include <string.h>
 #include <env.h>
@@ -77,6 +79,7 @@ int do_rs_update(message *m_ptr)
        src_e = m_ptr->m_lsys_vm_update.src;
        dst_e = m_ptr->m_lsys_vm_update.dst;
         sys_upd_flags = m_ptr->m_lsys_vm_update.flags;
+        reply_e = m_ptr->m_source;
 
        /* Lookup slots for source and destination process. */
        if(vm_isokendpt(src_e, &src_p) != OK) {
@@ -90,6 +93,14 @@ int do_rs_update(message *m_ptr)
        }
        dst_vmp = &vmproc[dst_p];
 
+       /* Check flags. */
+       if((sys_upd_flags & (SF_VM_ROLLBACK|SF_VM_NOMMAP)) == 0) {
+               /* Can't preallocate when transfering mmapped regions. */
+               if(map_region_lookup_type(dst_vmp, VR_PREALLOC_MAP)) {
+                       return ENOSYS;
+               }
+       }
+
        /* Let the kernel do the update first. */
        r = sys_update(src_e, dst_e,
            sys_upd_flags & SF_VM_ROLLBACK ? SYS_UPD_ROLLBACK : 0);
@@ -102,21 +113,22 @@ int do_rs_update(message *m_ptr)
        if(r != OK) {
                return r;
        }
-       r = swap_proc_dyn_data(src_vmp, dst_vmp);
+       r = swap_proc_dyn_data(src_vmp, dst_vmp, sys_upd_flags);
        if(r != OK) {
                return r;
        }
        pt_bind(&src_vmp->vm_pt, src_vmp);
        pt_bind(&dst_vmp->vm_pt, dst_vmp);
 
-       /* Reply, update-aware. */
-       reply_e = m_ptr->m_source;
-       if(reply_e == src_e) reply_e = dst_e;
-       else if(reply_e == dst_e) reply_e = src_e;
-       m_ptr->m_type = OK;
-       r = ipc_send(reply_e, m_ptr);
-       if(r != OK) {
-               panic("ipc_send() error");
+       /* Reply in case of external request, update-aware. */
+       if(reply_e != VM_PROC_NR) {
+            if(reply_e == src_e) reply_e = dst_e;
+            else if(reply_e == dst_e) reply_e = src_e;
+            m_ptr->m_type = OK;
+            r = ipc_send(reply_e, m_ptr);
+            if(r != OK) {
+                    panic("ipc_send() error");
+            }
        }
 
        return SUSPEND;
@@ -134,6 +146,17 @@ static int rs_memctl_make_vm_instance(struct vmproc *new_vm_vmp)
 
        this_vm_vmp = &vmproc[VM_PROC_NR];
 
+       /* Check if the operation is allowed. */
+       assert(num_vm_instances == 1 || num_vm_instances == 2);
+       if(num_vm_instances == 2) {
+               printf("VM can currently support no more than 2 VM instances at the time.");
+               return EPERM;
+       }
+
+       /* Copy settings from current VM. */
+       new_vm_vmp->vm_flags |= VMF_VM_INSTANCE;
+       num_vm_instances++;
+
        /* Pin memory for the new VM instance. */
        r = map_pin_memory(new_vm_vmp);
        if(r != OK) {
@@ -187,20 +210,26 @@ static int rs_memctl_heap_prealloc(struct vmproc *vmp,
 static int rs_memctl_map_prealloc(struct vmproc *vmp,
        vir_bytes *addr, size_t *len)
 {
-#if 0
        struct vir_region *vr;
+       vir_bytes base, top;
+       int is_vm;
+
        if(*len <= 0) {
                return EINVAL;
        }
        *len = CLICK_CEIL(*len);
 
-       if(!(vr = map_page_region(vmp, VM_DATATOP - *len, VM_DATATOP, *len,
-               MAP_NONE, VR_ANON|VR_WRITABLE|VR_CONTIG, MF_PREALLOC))) {
+       is_vm = (vmp->vm_endpoint == VM_PROC_NR);
+       base = is_vm ? VM_OWN_MMAPBASE : VM_MMAPBASE;
+       top = is_vm ? VM_OWN_MMAPTOP : VM_MMAPTOP;
+
+       if (!(vr = map_page_region(vmp, base, top, *len,
+           VR_ANON|VR_WRITABLE|VR_UNINITIALIZED, MF_PREALLOC,
+           &mem_type_anon))) {
                return ENOMEM;
        }
-       map_region_set_tag(vr, VRT_PREALLOC_MAP);
-       *addr = arch_map2vir(vmp, vr->vaddr);
-#endif
+       vr->flags |= VR_PREALLOC_MAP;
+       *addr = vr->vaddr;
        return OK;
 }
 
@@ -210,19 +239,17 @@ static int rs_memctl_map_prealloc(struct vmproc *vmp,
 static int rs_memctl_get_prealloc_map(struct vmproc *vmp,
        vir_bytes *addr, size_t *len)
 {
-#if 0
        struct vir_region *vr;
 
-       vr = map_region_lookup_tag(vmp, VRT_PREALLOC_MAP);
+       vr = map_region_lookup_type(vmp, VR_PREALLOC_MAP);
        if(!vr) {
                *addr = 0;
                *len = 0;
        }
        else {
-               *addr = arch_map2vir(vmp, vr->vaddr);
+               *addr = vr->vaddr;
                *len = vr->length;
        }
-#endif
        return OK;
 }
 
index 17edbe2c11c03840cf80c96deba54901dedc241f..63a6217ec615ce70a6f4a4f19f60cb9adc66ed55 100644 (file)
@@ -18,6 +18,7 @@
 #include <minix/syslib.h>
 #include <minix/type.h>
 #include <minix/bitmap.h>
+#include <minix/rs.h>
 #include <string.h>
 #include <errno.h>
 #include <env.h>
@@ -219,20 +220,22 @@ int swap_proc_slot(struct vmproc *src_vmp, struct vmproc *dst_vmp)
 /*===========================================================================*
  *                           swap_proc_dyn_data                             *
  *===========================================================================*/
-int swap_proc_dyn_data(struct vmproc *src_vmp, struct vmproc *dst_vmp)
+int swap_proc_dyn_data(struct vmproc *src_vmp, struct vmproc *dst_vmp,
+       int sys_upd_flags)
 {
        int is_vm;
        int r;
+       struct vir_region *start_vr, *end_vr;
 
        is_vm = (dst_vmp->vm_endpoint == VM_PROC_NR);
 
-        /* For VM, transfer memory regions above the stack first. */
+        /* For VM, transfer memory mapped regions first. */
         if(is_vm) {
 #if LU_DEBUG
-               printf("VM: swap_proc_dyn_data: tranferring regions above the stack from old VM (%d) to new VM (%d)\n",
+               printf("VM: swap_proc_dyn_data: tranferring memory mapped regions from old (%d) to new VM (%d)\n",
                        src_vmp->vm_endpoint, dst_vmp->vm_endpoint);
 #endif
-               r = pt_map_in_range(src_vmp, dst_vmp, VM_STACKTOP, 0);
+               r = pt_map_in_range(src_vmp, dst_vmp, VM_OWN_HEAPBASE, VM_OWN_MMAPTOP);
                if(r != OK) {
                        printf("swap_proc_dyn_data: pt_map_in_range failed\n");
                        return r;
@@ -249,23 +252,29 @@ int swap_proc_dyn_data(struct vmproc *src_vmp, struct vmproc *dst_vmp)
        map_setparent(src_vmp);
        map_setparent(dst_vmp);
 
-       /* For regular processes, transfer regions above the stack now.
-        * In case of rollback, we need to skip this step. To sandbox the
-        * new instance and prevent state corruption on rollback, we share all
-        * the regions between the two instances as COW.
+       /* Don't transfer mmapped regions if not required. */
+       if(is_vm || (sys_upd_flags & (SF_VM_ROLLBACK|SF_VM_NOMMAP))) {
+               return OK;
+       }
+
+       /* Make sure regions are consistent. */
+       assert(region_search_root(&src_vmp->vm_regions_avl) && region_search_root(&dst_vmp->vm_regions_avl));
+
+       /* Transfer memory mapped regions now. To sandbox the new instance and
+        * prevent state corruption on rollback, we share all the regions
+        * between the two instances as COW.
         */
-       if(!is_vm) {
-               struct vir_region *vr;
-               vr = map_lookup(dst_vmp, VM_STACKTOP, NULL);
-               if(vr && !map_lookup(src_vmp, VM_STACKTOP, NULL)) {
+       start_vr = region_search(&dst_vmp->vm_regions_avl, VM_MMAPBASE, AVL_GREATER_EQUAL);
+       end_vr = region_search(&dst_vmp->vm_regions_avl, VM_MMAPTOP, AVL_LESS);
+       if(start_vr) {
 #if LU_DEBUG
-                       printf("VM: swap_proc_dyn_data: tranferring regions above the stack from %d to %d\n",
-                               src_vmp->vm_endpoint, dst_vmp->vm_endpoint);
+               printf("VM: swap_proc_dyn_data: tranferring memory mapped regions from %d to %d\n",
+                       dst_vmp->vm_endpoint, src_vmp->vm_endpoint);
 #endif
-                       r = map_proc_copy_from(src_vmp, dst_vmp, vr);
-                       if(r != OK) {
-                               return r;
-                       }
+               assert(end_vr);
+               r = map_proc_copy_range(src_vmp, dst_vmp, start_vr, end_vr);
+               if(r != OK) {
+                       return r;
                }
        }
 
@@ -355,3 +364,25 @@ int do_getrusage(message *m)
        return sys_datacopy(SELF, (vir_bytes) &r_usage, m->m_source,
                m->m_lc_vm_rusage.addr, (vir_bytes) sizeof(r_usage));
 }
+
+/*===========================================================================*
+ *                            adjust_proc_refs                              *
+ *===========================================================================*/
+void adjust_proc_refs()
+{
+       struct vmproc *vmp;
+       region_iter iter;
+
+       /* Fix up region parents. */
+       for(vmp = vmproc; vmp < &vmproc[VMP_NR]; vmp++) {
+               struct vir_region *vr;
+               if(!(vmp->vm_flags & VMF_INUSE))
+                       continue;
+               region_start_iter_least(&vmp->vm_regions_avl, &iter);
+               while((vr = region_get_iter(&iter))) {
+                       USE(vr, vr->parent = vmp;);
+                       region_incr_iter(&iter);
+               }
+       }
+}
+
index 3a6e56accf1b2d59ec38eb51bb9fdea71c62acee..751e7a819450e1e61b8132d4c151c37233043721 100644 (file)
 #define VM_MMAPBASE    VM_PAGE_SIZE
 #endif
 
+extern char _end;
+#define VM_OWN_HEAPSTART ((vir_bytes) (&_end))
+#define VM_OWN_HEAPBASE   roundup(VM_OWN_HEAPSTART, VM_PAGE_SIZE)
+#define VM_OWN_MMAPBASE (VM_OWN_HEAPBASE+1024*1024*1024)
+#define VM_OWN_MMAPTOP   (VM_OWN_MMAPBASE+100 * 1024 * 1024)
+
 #endif
index a174714a40fa8223c04744bc56d5ee5413830f70..0ec2a8219d5429eb35476e7e975f65425681a7b0 100644 (file)
@@ -35,5 +35,6 @@ struct vmproc {
 #define VMF_INUSE      0x001   /* slot contains a process */
 #define VMF_EXITING    0x002   /* PM is cleaning up this process */
 #define VMF_WATCHEXIT  0x008   /* Store in queryexit table */
+#define VMF_VM_INSTANCE 0x010   /* This is a VM process instance */
 
 #endif