[IA64] Change vCPU initialization to avoid domVTi privregs memory leak
authorawilliam@xenbuild2.aw <awilliam@xenbuild2.aw>
Tue, 16 Jan 2007 17:40:37 +0000 (10:40 -0700)
committerawilliam@xenbuild2.aw <awilliam@xenbuild2.aw>
Tue, 16 Jan 2007 17:40:37 +0000 (10:40 -0700)
1) This patch moved some processing from vcpu_initialise() and
   added a new function vcpu_late_initialise().
   It executes the following initializations for VCPU of
   dom0/domU.
    - Allocate the VHPT
    - Allocate the privregs area and assign these pages into
      guest pseudo physical address space.
    - Set the tlbflush_timestamp.

   It is executed in the following sequence.

   dom0:
     start_kernel()
       ->domain_create()
       ->alloc_vcpu(VCPU0)
         ->alloc_vcpu_struct(VCPU0)
         ->vcpu_initialise(VCPU0)
       ->vcpu_late_initialise(VCPU0)

       ->construct_dom0
         ->alloc_vcpu(othe VCPUs)
           ->alloc_vcpu_struct(other VCPUs)
           ->vcpu_initialise(other VCPUs)

     ia64_hypercall(FW_HYPERCALL_IPI)
       ->fw_hypercall_ipi(XEN_SAL_BOOT_RENDEZ_VEC)
         ->arch_set_info_guest(other VCPUs)
           ->vcpu_late_initialise(other VCPUs)

   domU:
     do_domctl(XEN_DOMCTL_createdomain)
       ->domain_create()

     do_domctl(XEN_DOMCTL_max_vcpus)
       ->alloc_vcpu(all VCPUs)
         ->alloc_vcpu_struct(all VCPUs)
         ->vcpu_initialise(all VCPUs)

     do_domctl(XEN_DOMCTL_setvcpucontext)
       ->set_info_guest(VCPU0)
         ->arch_set_info_guest(VCPU0)
           ->vcpu_late_initialise(VCPU0)

     ia64_hypercall(FW_HYPERCALL_IPI)
       ->fw_hypercall_ipi(XEN_SAL_BOOT_RENDEZ_VEC)
         ->arch_set_info_guest(other VCPUs)
           ->vcpu_late_initialise(other VCPUs)

2) This patch modified the domain_set_shared_info_va().
   Currently, initialization of arch.privregs->interrupt_mask_addr
   of all VCPUs is executed in domain_set_shared_info_va().
   However, allocation of privregs area is late by modified of 1).
   Therefore, this patch modified initialization of
   arch.privregs->interrupt_mask_addr to the following sequence.

   dom0 and domU:
     ia64_hypercall(FW_HYPERCALL_SET_SHARED_INFO_VA)
       ->domain_set_shared_info_va()
         Initialize interrupt_mask_addr of VCPU0

     ia64_hypercall(FW_HYPERCALL_IPI)
       ->fw_hypercall_ipi(XEN_SAL_BOOT_RENDEZ_VEC)
         ->arch_set_info_guest(other VCPUs)
           ->vcpu_late_initialise(other VCPUs)
           Initialize interrupt_mask_addr of other VCPUs

Signed-off-by: Masaki Kanno <kanno.masaki@jp.fujitsu.com>
xen/arch/ia64/xen/dom0_ops.c
xen/arch/ia64/xen/domain.c
xen/arch/ia64/xen/xensetup.c
xen/include/asm-ia64/domain.h

index 2ee0a935a9e97190c0146b32f253ee3680d9ae28..a2c0903ed6fe367442c6ca01137291195991f685 100644 (file)
@@ -103,16 +103,6 @@ long arch_do_domctl(xen_domctl_t *op, XEN_GUEST_HANDLE(xen_domctl_t) u_domctl)
                     ret = -EINVAL;
                     break;
                 }
-                if (!d->arch.is_vti) {
-                    struct vcpu *v;
-                    for_each_vcpu(d, v) {
-                        BUG_ON(v->arch.privregs == NULL);
-                        free_domheap_pages(virt_to_page(v->arch.privregs),
-                                      get_order_from_shift(XMAPPEDREGS_SHIFT));
-                        v->arch.privregs = NULL;
-                        relinquish_vcpu_resources(v);
-                    }
-                }
                 d->arch.is_vti = 1;
                 vmx_setup_platform(d);
             }
index ed1a6519a080eed2bf9e9442a37dd07e26881e47..f28d2040e03bcdcc646b1207f644ba6871858ec7 100644 (file)
@@ -305,24 +305,14 @@ void hlt_timer_fn(void *data)
 
 void relinquish_vcpu_resources(struct vcpu *v)
 {
-    if (HAS_PERVCPU_VHPT(v->domain))
-        pervcpu_vhpt_free(v);
-    if (v->arch.privregs != NULL) {
-        // this might be called by arch_do_domctl() with XEN_DOMCTL_arch_setup()
-        // for domVTi.
-        if (!(atomic_read(&v->domain->refcnt) & DOMAIN_DESTROYED)) {
-            unsigned long i;
-            for (i = 0; i < XMAPPEDREGS_SIZE; i += PAGE_SIZE)
-                guest_physmap_remove_page(v->domain,
-                    IA64_XMAPPEDREGS_PADDR(v->vcpu_id) + i,
-                    virt_to_maddr(v->arch.privregs + i));
-        }
-
-        free_xenheap_pages(v->arch.privregs,
-                           get_order_from_shift(XMAPPEDREGS_SHIFT));
-        v->arch.privregs = NULL;
-    }
-    kill_timer(&v->arch.hlt_timer);
+       if (HAS_PERVCPU_VHPT(v->domain))
+               pervcpu_vhpt_free(v);
+       if (v->arch.privregs != NULL) {
+               free_xenheap_pages(v->arch.privregs,
+                                  get_order_from_shift(XMAPPEDREGS_SHIFT));
+               v->arch.privregs = NULL;
+       }
+       kill_timer(&v->arch.hlt_timer);
 }
 
 struct vcpu *alloc_vcpu_struct(void)
@@ -361,36 +351,8 @@ void free_vcpu_struct(struct vcpu *v)
 int vcpu_initialise(struct vcpu *v)
 {
        struct domain *d = v->domain;
-       int rc, order, i;
 
        if (!is_idle_domain(d)) {
-           if (!d->arch.is_vti) {
-               if (HAS_PERVCPU_VHPT(d))
-                       if ((rc = pervcpu_vhpt_alloc(v)) != 0)
-                               return rc;
-
-               /* Create privregs page only if not VTi. */
-               order = get_order_from_shift(XMAPPEDREGS_SHIFT);
-               v->arch.privregs = alloc_xenheap_pages(order);
-               BUG_ON(v->arch.privregs == NULL);
-               memset(v->arch.privregs, 0, 1 << XMAPPEDREGS_SHIFT);
-               for (i = 0; i < (1 << order); i++)
-                   share_xen_page_with_guest(virt_to_page(v->arch.privregs) +
-                                             i, d, XENSHARE_writable);
-               /*
-                * XXX IA64_XMAPPEDREGS_PADDR
-                * assign these pages into guest pseudo physical address
-                * space for dom0 to map this page by gmfn.
-                * this is necessary for domain save, restore and dump-core.
-                */
-               for (i = 0; i < XMAPPEDREGS_SIZE; i += PAGE_SIZE)
-                   assign_domain_page(d, IA64_XMAPPEDREGS_PADDR(v->vcpu_id) + i,
-                                      virt_to_maddr(v->arch.privregs + i));
-
-               tlbflush_update_time(&v->arch.tlbflush_timestamp,
-                                    tlbflush_current_time());
-           }
-
            v->arch.metaphysical_rr0 = d->arch.metaphysical_rr0;
            v->arch.metaphysical_rr4 = d->arch.metaphysical_rr4;
            v->arch.metaphysical_saved_rr0 = d->arch.metaphysical_rr0;
@@ -420,6 +382,41 @@ int vcpu_initialise(struct vcpu *v)
        return 0;
 }
 
+int vcpu_late_initialise(struct vcpu *v)
+{
+       struct domain *d = v->domain;
+       int rc, order, i;
+
+       if (HAS_PERVCPU_VHPT(d)) {
+               rc = pervcpu_vhpt_alloc(v);
+               if (rc != 0)
+                       return rc;
+       }
+
+       /* Create privregs page. */
+       order = get_order_from_shift(XMAPPEDREGS_SHIFT);
+       v->arch.privregs = alloc_xenheap_pages(order);
+       BUG_ON(v->arch.privregs == NULL);
+       memset(v->arch.privregs, 0, 1 << XMAPPEDREGS_SHIFT);
+       for (i = 0; i < (1 << order); i++)
+               share_xen_page_with_guest(virt_to_page(v->arch.privregs) + i,
+                                         d, XENSHARE_writable);
+       /*
+        * XXX IA64_XMAPPEDREGS_PADDR
+        * assign these pages into guest pseudo physical address
+        * space for dom0 to map this page by gmfn.
+        * this is necessary for domain save, restore and dump-core.
+        */
+       for (i = 0; i < XMAPPEDREGS_SIZE; i += PAGE_SIZE)
+               assign_domain_page(d, IA64_XMAPPEDREGS_PADDR(v->vcpu_id) + i,
+                                  virt_to_maddr(v->arch.privregs + i));
+
+       tlbflush_update_time(&v->arch.tlbflush_timestamp,
+                            tlbflush_current_time());
+
+       return 0;
+}
+
 void vcpu_destroy(struct vcpu *v)
 {
        if (v->domain->arch.is_vti)
@@ -553,6 +550,7 @@ int arch_set_info_guest(struct vcpu *v, vcpu_guest_context_u c)
 {
        struct pt_regs *regs = vcpu_regs (v);
        struct domain *d = v->domain;
+       int rc;
        
        *regs = c.nat->user_regs;
        
@@ -582,16 +580,25 @@ int arch_set_info_guest(struct vcpu *v, vcpu_guest_context_u c)
                v->arch.event_callback_ip = er->event_callback_ip;
                v->arch.dcr = er->dcr;
                v->arch.iva = er->iva;
-       }
-       
-       if ( test_bit(_VCPUF_initialised, &v->vcpu_flags) )
-               return 0;
-       if (d->arch.is_vti)
-               vmx_final_setup_guest(v);
-       
-       /* This overrides some registers.  */
-       vcpu_init_regs(v);
-  
+       }
+
+       if (test_bit(_VCPUF_initialised, &v->vcpu_flags))
+               return 0;
+
+       if (d->arch.is_vti)
+               vmx_final_setup_guest(v);
+       else {
+               rc = vcpu_late_initialise(v);
+               if (rc != 0)
+                       return rc;
+               VCPU(v, interrupt_mask_addr) = 
+                       (unsigned char *) d->arch.shared_info_va +
+                       INT_ENABLE_OFFSET(v);
+       }
+
+       /* This overrides some registers. */
+       vcpu_init_regs(v);
+
        /* Don't redo final setup */
        set_bit(_VCPUF_initialised, &v->vcpu_flags);
        return 0;
@@ -683,7 +690,6 @@ domain_set_shared_info_va (unsigned long va)
 {
        struct vcpu *v = current;
        struct domain *d = v->domain;
-       struct vcpu *v1;
 
        /* Check virtual address:
           must belong to region 7,
@@ -699,10 +705,8 @@ domain_set_shared_info_va (unsigned long va)
        printk ("Domain set shared_info_va to 0x%016lx\n", va);
        d->arch.shared_info_va = va;
 
-       for_each_vcpu (d, v1) {
-               VCPU(v1, interrupt_mask_addr) = 
-                       (unsigned char *)va + INT_ENABLE_OFFSET(v1);
-       }
+       VCPU(v, interrupt_mask_addr) = (unsigned char *)va +
+                                      INT_ENABLE_OFFSET(v);
 
        __ia64_per_cpu_var(current_psr_ic_addr) = (int *)(va + XSI_PSR_IC_OFS);
 
@@ -1106,7 +1110,7 @@ int construct_dom0(struct domain *d,
        printk ("Dom0 max_vcpus=%d\n", dom0_max_vcpus);
        for ( i = 1; i < dom0_max_vcpus; i++ )
            if (alloc_vcpu(d, i, i) == NULL)
-               printk ("Cannot allocate dom0 vcpu %d\n", i);
+               panic("Cannot allocate dom0 vcpu %d\n", i);
 
        /* Copy the OS image. */
        loaddomainelfimage(d,image_start);
index 7833642fb42d896fbda0395072c6dfde571c8a44..0d1eaf23dda7de4d397a16b4f3aad95cbf9ab6d4 100644 (file)
@@ -249,6 +249,7 @@ void start_kernel(void)
     unsigned long dom0_initrd_start, dom0_initrd_size;
     unsigned long md_end, relo_start, relo_end, relo_size = 0;
     struct domain *idle_domain;
+    struct vcpu *dom0_vcpu0;
     efi_memory_desc_t *kern_md, *last_md, *md;
 #ifdef CONFIG_SMP
     int i;
@@ -503,8 +504,11 @@ printk("num_online_cpus=%d, max_cpus=%d\n",num_online_cpus(),max_cpus);
 
     /* Create initial domain 0. */
     dom0 = domain_create(0, 0);
-    if ( (dom0 == NULL) || (alloc_vcpu(dom0, 0, 0) == NULL) )
+    if (dom0 == NULL)
         panic("Error creating domain 0\n");
+    dom0_vcpu0 = alloc_vcpu(dom0, 0, 0);
+    if (dom0_vcpu0 == NULL || vcpu_late_initialise(dom0_vcpu0) != 0)
+        panic("Cannot allocate dom0 vcpu 0\n");
 
     dom0->is_privileged = 1;
 
index a09446d6b14cb03c3b4dec78eed0c5adf99dfc8f..2090908bf23e0f5d2b3cf95dd3d3b6e07195e1e7 100644 (file)
@@ -21,6 +21,7 @@ struct tlb_track;
 extern void domain_relinquish_resources(struct domain *);
 struct vcpu;
 extern void relinquish_vcpu_resources(struct vcpu *v);
+extern int vcpu_late_initialise(struct vcpu *v);
 
 /* given a current domain metaphysical address, return the physical address */
 extern unsigned long translate_domain_mpaddr(unsigned long mpaddr,