New memory hypercall 'populate_physmap'. Accepts a list of
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Fri, 27 Jan 2006 11:49:47 +0000 (12:49 +0100)
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Fri, 27 Jan 2006 11:49:47 +0000 (12:49 +0100)
pseudophys frame numbers to be populated with memory.

Signed-off-by: Keir Fraser <keir@xensource.com>
linux-2.6-xen-sparse/arch/xen/i386/mm/hypervisor.c
linux-2.6-xen-sparse/drivers/xen/balloon/balloon.c
xen/common/memory.c
xen/include/public/memory.h

index 7fde02f245544f78253243e3248e6632650cef98..e1a477bc00157b4188dd66cbb0ef4d3fa2d1ea2f 100644 (file)
@@ -315,9 +315,9 @@ int xen_create_contiguous_region(
        pud_t         *pud; 
        pmd_t         *pmd;
        pte_t         *pte;
-       unsigned long  mfn, i, flags;
+       unsigned long  frame, i, flags;
        struct xen_memory_reservation reservation = {
-               .extent_start = &mfn,
+               .extent_start = &frame,
                .nr_extents   = 1,
                .extent_order = 0,
                .domid        = DOMID_SELF
@@ -333,7 +333,7 @@ int xen_create_contiguous_region(
                pud = pud_offset(pgd, (vstart + (i*PAGE_SIZE)));
                pmd = pmd_offset(pud, (vstart + (i*PAGE_SIZE)));
                pte = pte_offset_kernel(pmd, (vstart + (i*PAGE_SIZE)));
-               mfn = pte_mfn(*pte);
+               frame = pte_mfn(*pte);
                BUG_ON(HYPERVISOR_update_va_mapping(
                        vstart + (i*PAGE_SIZE), __pte_ma(0), 0));
                set_phys_to_machine((__pa(vstart)>>PAGE_SHIFT)+i,
@@ -345,7 +345,8 @@ int xen_create_contiguous_region(
        /* 2. Get a new contiguous memory extent. */
        reservation.extent_order = order;
        reservation.address_bits = address_bits;
-       if (HYPERVISOR_memory_op(XENMEM_increase_reservation,
+       frame = __pa(vstart) >> PAGE_SHIFT;
+       if (HYPERVISOR_memory_op(XENMEM_populate_physmap,
                                 &reservation) != 1)
                goto fail;
 
@@ -353,9 +354,8 @@ int xen_create_contiguous_region(
        for (i = 0; i < (1<<order); i++) {
                BUG_ON(HYPERVISOR_update_va_mapping(
                        vstart + (i*PAGE_SIZE),
-                       pfn_pte_ma(mfn+i, PAGE_KERNEL), 0));
-               xen_machphys_update(mfn+i, (__pa(vstart)>>PAGE_SHIFT)+i);
-               set_phys_to_machine((__pa(vstart)>>PAGE_SHIFT)+i, mfn+i);
+                       pfn_pte_ma(frame+i, PAGE_KERNEL), 0));
+               set_phys_to_machine((__pa(vstart)>>PAGE_SHIFT)+i, frame+i);
        }
 
        flush_tlb_all();
@@ -371,13 +371,13 @@ int xen_create_contiguous_region(
        reservation.address_bits = 0;
 
        for (i = 0; i < (1<<order); i++) {
+               frame = (__pa(vstart) >> PAGE_SHIFT) + i;
                BUG_ON(HYPERVISOR_memory_op(
-                       XENMEM_increase_reservation, &reservation) != 1);
+                       XENMEM_populate_physmap, &reservation) != 1);
                BUG_ON(HYPERVISOR_update_va_mapping(
                        vstart + (i*PAGE_SIZE),
-                       pfn_pte_ma(mfn, PAGE_KERNEL), 0));
-               xen_machphys_update(mfn, (__pa(vstart)>>PAGE_SHIFT)+i);
-               set_phys_to_machine((__pa(vstart)>>PAGE_SHIFT)+i, mfn);
+                       pfn_pte_ma(frame, PAGE_KERNEL), 0));
+               set_phys_to_machine((__pa(vstart)>>PAGE_SHIFT)+i, frame);
        }
 
        flush_tlb_all();
@@ -393,9 +393,9 @@ void xen_destroy_contiguous_region(unsigned long vstart, unsigned int order)
        pud_t         *pud; 
        pmd_t         *pmd;
        pte_t         *pte;
-       unsigned long  mfn, i, flags;
+       unsigned long  frame, i, flags;
        struct xen_memory_reservation reservation = {
-               .extent_start = &mfn,
+               .extent_start = &frame,
                .nr_extents   = 1,
                .extent_order = 0,
                .domid        = DOMID_SELF
@@ -413,7 +413,7 @@ void xen_destroy_contiguous_region(unsigned long vstart, unsigned int order)
                pud = pud_offset(pgd, (vstart + (i*PAGE_SIZE)));
                pmd = pmd_offset(pud, (vstart + (i*PAGE_SIZE)));
                pte = pte_offset_kernel(pmd, (vstart + (i*PAGE_SIZE)));
-               mfn = pte_mfn(*pte);
+               frame = pte_mfn(*pte);
                BUG_ON(HYPERVISOR_update_va_mapping(
                        vstart + (i*PAGE_SIZE), __pte_ma(0), 0));
                set_phys_to_machine((__pa(vstart)>>PAGE_SHIFT)+i,
@@ -424,13 +424,13 @@ void xen_destroy_contiguous_region(unsigned long vstart, unsigned int order)
 
        /* 2. Map new pages in place of old pages. */
        for (i = 0; i < (1<<order); i++) {
+               frame = (__pa(vstart) >> PAGE_SHIFT) + i;
                BUG_ON(HYPERVISOR_memory_op(
-                       XENMEM_increase_reservation, &reservation) != 1);
+                       XENMEM_populate_physmap, &reservation) != 1);
                BUG_ON(HYPERVISOR_update_va_mapping(
                        vstart + (i*PAGE_SIZE),
-                       pfn_pte_ma(mfn, PAGE_KERNEL), 0));
-               xen_machphys_update(mfn, (__pa(vstart)>>PAGE_SHIFT)+i);
-               set_phys_to_machine((__pa(vstart)>>PAGE_SHIFT)+i, mfn);
+                       pfn_pte_ma(frame, PAGE_KERNEL), 0));
+               set_phys_to_machine((__pa(vstart)>>PAGE_SHIFT)+i, frame);
        }
 
        flush_tlb_all();
index 7b6d08801653b753222d952adfadf4da245b7158..89b98173fcd513c166cd31299c95572876c9f191 100644 (file)
@@ -139,6 +139,21 @@ static struct page *balloon_retrieve(void)
        return page;
 }
 
+static struct page *balloon_first_page(void)
+{
+       if (list_empty(&ballooned_pages))
+               return NULL;
+       return LIST_TO_PAGE(ballooned_pages.next);
+}
+
+static struct page *balloon_next_page(struct page *page)
+{
+       struct list_head *next = PAGE_TO_LIST(page)->next;
+       if (next == &ballooned_pages)
+               return NULL;
+       return LIST_TO_PAGE(next);
+}
+
 static void balloon_alarm(unsigned long unused)
 {
        schedule_work(&balloon_worker);
@@ -154,7 +169,7 @@ static unsigned long current_target(void)
 
 static int increase_reservation(unsigned long nr_pages)
 {
-       unsigned long *mfn_list, pfn, i, flags;
+       unsigned long *frame_list, pfn, i, flags;
        struct page   *page;
        long           rc;
        struct xen_memory_reservation reservation = {
@@ -166,20 +181,27 @@ static int increase_reservation(unsigned long nr_pages)
        if (nr_pages > (PAGE_SIZE / sizeof(unsigned long)))
                nr_pages = PAGE_SIZE / sizeof(unsigned long);
 
-       mfn_list = (unsigned long *)__get_free_page(GFP_KERNEL);
-       if (mfn_list == NULL)
+       frame_list = (unsigned long *)__get_free_page(GFP_KERNEL);
+       if (frame_list == NULL)
                return -ENOMEM;
 
        balloon_lock(flags);
 
-       reservation.extent_start = mfn_list;
+       page = balloon_first_page();
+       for (i = 0; i < nr_pages; i++) {
+               BUG_ON(page == NULL);
+               frame_list[i] = page_to_pfn(page);;
+               page = balloon_next_page(page);
+       }
+
+       reservation.extent_start = frame_list;
        reservation.nr_extents   = nr_pages;
        rc = HYPERVISOR_memory_op(
-               XENMEM_increase_reservation, &reservation);
+               XENMEM_populate_physmap, &reservation);
        if (rc < nr_pages) {
                int ret;
                /* We hit the Xen hard limit: reprobe. */
-               reservation.extent_start = mfn_list;
+               reservation.extent_start = frame_list;
                reservation.nr_extents   = rc;
                ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation,
                                &reservation);
@@ -196,15 +218,15 @@ static int increase_reservation(unsigned long nr_pages)
                BUG_ON(phys_to_machine_mapping_valid(pfn));
 
                /* Update P->M and M->P tables. */
-               set_phys_to_machine(pfn, mfn_list[i]);
-               xen_machphys_update(mfn_list[i], pfn);
+               set_phys_to_machine(pfn, frame_list[i]);
+               xen_machphys_update(frame_list[i], pfn);
             
                /* Link back into the page tables if not highmem. */
                if (pfn < max_low_pfn) {
                        int ret;
                        ret = HYPERVISOR_update_va_mapping(
                                (unsigned long)__va(pfn << PAGE_SHIFT),
-                               pfn_pte_ma(mfn_list[i], PAGE_KERNEL),
+                               pfn_pte_ma(frame_list[i], PAGE_KERNEL),
                                0);
                        BUG_ON(ret);
                }
@@ -221,14 +243,14 @@ static int increase_reservation(unsigned long nr_pages)
  out:
        balloon_unlock(flags);
 
-       free_page((unsigned long)mfn_list);
+       free_page((unsigned long)frame_list);
 
        return 0;
 }
 
 static int decrease_reservation(unsigned long nr_pages)
 {
-       unsigned long *mfn_list, pfn, i, flags;
+       unsigned long *frame_list, pfn, i, flags;
        struct page   *page;
        void          *v;
        int            need_sleep = 0;
@@ -242,8 +264,8 @@ static int decrease_reservation(unsigned long nr_pages)
        if (nr_pages > (PAGE_SIZE / sizeof(unsigned long)))
                nr_pages = PAGE_SIZE / sizeof(unsigned long);
 
-       mfn_list = (unsigned long *)__get_free_page(GFP_KERNEL);
-       if (mfn_list == NULL)
+       frame_list = (unsigned long *)__get_free_page(GFP_KERNEL);
+       if (frame_list == NULL)
                return -ENOMEM;
 
        for (i = 0; i < nr_pages; i++) {
@@ -254,7 +276,7 @@ static int decrease_reservation(unsigned long nr_pages)
                }
 
                pfn = page_to_pfn(page);
-               mfn_list[i] = pfn_to_mfn(pfn);
+               frame_list[i] = pfn_to_mfn(pfn);
 
                if (!PageHighMem(page)) {
                        v = phys_to_virt(pfn << PAGE_SHIFT);
@@ -280,12 +302,12 @@ static int decrease_reservation(unsigned long nr_pages)
 
        /* No more mappings: invalidate P2M and add to balloon. */
        for (i = 0; i < nr_pages; i++) {
-               pfn = mfn_to_pfn(mfn_list[i]);
+               pfn = mfn_to_pfn(frame_list[i]);
                set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
                balloon_append(pfn_to_page(pfn));
        }
 
-       reservation.extent_start = mfn_list;
+       reservation.extent_start = frame_list;
        reservation.nr_extents   = nr_pages;
        ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, &reservation);
        BUG_ON(ret != nr_pages);
@@ -295,7 +317,7 @@ static int decrease_reservation(unsigned long nr_pages)
 
        balloon_unlock(flags);
 
-       free_page((unsigned long)mfn_list);
+       free_page((unsigned long)frame_list);
 
        return need_sleep;
 }
index ddad691d29a771d3671d3e7d06cc70485484ca13..35cf01c6792f5345986b231ca092cf1982b61054 100644 (file)
@@ -30,7 +30,7 @@ increase_reservation(
     int           *preempted)
 {
     struct pfn_info *page;
-    unsigned int     i;
+    unsigned long    i;
 
     if ( (extent_list != NULL) &&
          !array_access_ok(extent_list, nr_extents, sizeof(*extent_list)) )
@@ -52,7 +52,7 @@ increase_reservation(
             d, extent_order, flags)) == NULL) )
         {
             DPRINTK("Could not allocate order=%d extent: "
-                    "id=%d flags=%x (%d of %d)\n",
+                    "id=%d flags=%x (%ld of %d)\n",
                     extent_order, d->domain_id, flags, i, nr_extents);
             return i;
         }
@@ -66,6 +66,58 @@ increase_reservation(
     return nr_extents;
 }
     
+static long
+populate_physmap(
+    struct domain *d, 
+    unsigned long *extent_list, 
+    unsigned int   nr_extents,
+    unsigned int   extent_order,
+    unsigned int   flags,
+    int           *preempted)
+{
+    struct pfn_info *page;
+    unsigned long    i, j, pfn, mfn;
+
+    if ( !array_access_ok(extent_list, nr_extents, sizeof(*extent_list)) )
+        return 0;
+
+    if ( (extent_order != 0) &&
+         !multipage_allocation_permitted(current->domain) )
+        return 0;
+
+    for ( i = 0; i < nr_extents; i++ )
+    {
+        if ( hypercall_preempt_check() )
+        {
+            *preempted = 1;
+            return i;
+        }
+
+        if ( unlikely((page = alloc_domheap_pages(
+            d, extent_order, flags)) == NULL) )
+        {
+            DPRINTK("Could not allocate order=%d extent: "
+                    "id=%d flags=%x (%ld of %d)\n",
+                    extent_order, d->domain_id, flags, i, nr_extents);
+            return i;
+        }
+
+        mfn = page_to_pfn(page);
+
+        if ( unlikely(__get_user(pfn, &extent_list[i]) != 0) )
+            return i;
+
+        for ( j = 0; j < (1 << extent_order); j++ )
+            set_pfn_from_mfn(mfn + j, pfn + j);
+
+        /* Inform the domain of the new page's machine address. */ 
+        if ( __put_user(mfn, &extent_list[i]) != 0 )
+            return i;
+    }
+
+    return nr_extents;
+}
+    
 static long
 decrease_reservation(
     struct domain *d, 
@@ -76,7 +128,7 @@ decrease_reservation(
     int           *preempted)
 {
     struct pfn_info *page;
-    unsigned long    i, j, mpfn;
+    unsigned long    i, j, mfn;
 
     if ( !array_access_ok(extent_list, nr_extents, sizeof(*extent_list)) )
         return 0;
@@ -89,19 +141,19 @@ decrease_reservation(
             return i;
         }
 
-        if ( unlikely(__get_user(mpfn, &extent_list[i]) != 0) )
+        if ( unlikely(__get_user(mfn, &extent_list[i]) != 0) )
             return i;
 
         for ( j = 0; j < (1 << extent_order); j++ )
         {
-            if ( unlikely((mpfn + j) >= max_page) )
+            if ( unlikely((mfn + j) >= max_page) )
             {
                 DPRINTK("Domain %u page number out of range (%lx >= %lx)\n", 
-                        d->domain_id, mpfn + j, max_page);
+                        d->domain_id, mfn + j, max_page);
                 return i;
             }
             
-            page = pfn_to_page(mpfn + j);
+            page = pfn_to_page(mfn + j);
             if ( unlikely(!get_page(page, d)) )
             {
                 DPRINTK("Bad page free for domain %u\n", d->domain_id);
@@ -143,6 +195,7 @@ long do_memory_op(int cmd, void *arg)
     {
     case XENMEM_increase_reservation:
     case XENMEM_decrease_reservation:
+    case XENMEM_populate_physmap:
         if ( copy_from_user(&reservation, arg, sizeof(reservation)) )
             return -EFAULT;
 
@@ -170,14 +223,37 @@ long do_memory_op(int cmd, void *arg)
         else if ( (d = find_domain_by_id(reservation.domid)) == NULL )
             return -ESRCH;
 
-        rc = ((op == XENMEM_increase_reservation) ?
-              increase_reservation : decrease_reservation)(
-                  d,
-                  reservation.extent_start,
-                  reservation.nr_extents,
-                  reservation.extent_order,
-                  flags,
-                  &preempted);
+        switch ( op )
+        {
+        case XENMEM_increase_reservation:
+            rc = increase_reservation(
+                d,
+                reservation.extent_start,
+                reservation.nr_extents,
+                reservation.extent_order,
+                flags,
+                &preempted);
+            break;
+        case XENMEM_decrease_reservation:
+            rc = decrease_reservation(
+                d,
+                reservation.extent_start,
+                reservation.nr_extents,
+                reservation.extent_order,
+                flags,
+                &preempted);
+            break;
+        case XENMEM_populate_physmap:
+        default:
+            rc = populate_physmap(
+                d,
+                reservation.extent_start,
+                reservation.nr_extents,
+                reservation.extent_order,
+                flags,
+                &preempted);
+            break;
+        }
 
         if ( unlikely(reservation.domid != DOMID_SELF) )
             put_domain(d);
index 8e6a61a6f3b5cbc9bac3db0e2fe3124c3505f241..70c8197a17b9d068ea0214afb79b5b5ff95bdf41 100644 (file)
  */
 #define XENMEM_increase_reservation 0
 #define XENMEM_decrease_reservation 1
+#define XENMEM_populate_physmap     6
 typedef struct xen_memory_reservation {
 
     /*
-     * MFN bases of extents to free (XENMEM_decrease_reservation).
-     * MFN bases of extents that were allocated (XENMEM_increase_reservation).
+     * XENMEM_increase_reservation:
+     *   OUT: MFN bases of extents that were allocated
+     * XENMEM_decrease_reservation:
+     *   IN:  MFN bases of extents to free
+     * XENMEM_populate_physmap:
+     *   IN:  PFN bases of extents to populate with memory
+     *   OUT: MFN bases of extents that were allocated
+     *   (NB. This command also updates the mach_to_phys translation table)
      */
     unsigned long *extent_start;
 
@@ -29,11 +36,10 @@ typedef struct xen_memory_reservation {
     unsigned int   extent_order;
 
     /*
-     * XENMEM_increase_reservation: maximum # bits addressable by the user
-     * of the allocated region (e.g., I/O devices often have a 32-bit
-     * limitation even in 64-bit systems). If zero then the user has no
-     * addressing restriction.
-     * XENMEM_decrease_reservation: unused.
+     * Mmaximum # bits addressable by the user of the allocated region (e.g., 
+     * I/O devices often have a 32-bit limitation even in 64-bit systems). If 
+     * zero then the user has no addressing restriction.
+     * This field is not used by XENMEM_decrease_reservation.
      */
     unsigned int   address_bits;