[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] x86: add and use XEN_DOMCTL_getpageframeinfo3



# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1263370441 0
# Node ID 0447c5532e9fcfaeaf39bec5e0cba02e5393e399
# Parent  0b138a01929237f671a3bb7021755d304e294699
x86: add and use XEN_DOMCTL_getpageframeinfo3

To support wider than 28-bit MFNs, add XEN_DOMCTL_getpageframeinfo3
(with the type replacing the passed in MFN rather than getting or-ed
into it) to properly back xc_get_pfn_type_batch().

With xc_get_pfn_type_batch() only used internally to libxc, move its
prototype from xenctrl.h to xc_private.h.

This also fixes a couple of bugs in pre-existing code:
- the failure path for init_mem_info() leaked minfo->pfn_type,
- one error path of the XEN_DOMCTL_getpageframeinfo2 handler used
  put_domain() where rcu_unlock_domain() was meant, and
- the XEN_DOMCTL_getpageframeinfo2 handler could call
  xsm_getpageframeinfo() with an invalid struct page_info pointer.

Signed-off-by: Jan Beulich <jbeulich@xxxxxxxxxx>
---
 tools/libxc/xc_domain_save.c  |   14 ++---
 tools/libxc/xc_offline_page.c |   15 ++---
 tools/libxc/xc_private.c      |   10 +--
 tools/libxc/xc_private.h      |    3 +
 tools/libxc/xenctrl.h         |    3 -
 xen/arch/x86/domctl.c         |  113 ++++++++++++++++++++++++++++++++++++++++--
 xen/include/public/domctl.h   |   10 +++
 7 files changed, 141 insertions(+), 27 deletions(-)

diff -r 0b138a019292 -r 0447c5532e9f tools/libxc/xc_domain_save.c
--- a/tools/libxc/xc_domain_save.c      Wed Jan 13 08:12:56 2010 +0000
+++ b/tools/libxc/xc_domain_save.c      Wed Jan 13 08:14:01 2010 +0000
@@ -959,6 +959,12 @@ int xc_domain_save(int xc_handle, int io
     /* Get the size of the P2M table */
     dinfo->p2m_size = xc_memory_op(xc_handle, XENMEM_maximum_gpfn, &dom) + 1;
 
+    if ( dinfo->p2m_size > ~XEN_DOMCTL_PFINFO_LTAB_MASK )
+    {
+        ERROR("Cannot save this big a guest");
+        goto out;
+    }
+
     /* Domain is still running at this point */
     if ( live )
     {
@@ -1296,17 +1302,11 @@ int xc_domain_save(int xc_handle, int io
             else
             {
                 /* Get page types */
-                for ( j = 0; j < batch; j++ )
-                    ((uint32_t *)pfn_type)[j] = pfn_type[j];
-                if ( xc_get_pfn_type_batch(xc_handle, dom, batch,
-                                           (uint32_t *)pfn_type) )
+                if ( xc_get_pfn_type_batch(xc_handle, dom, batch, pfn_type) )
                 {
                     ERROR("get_pfn_type_batch failed");
                     goto out;
                 }
-                for ( j = batch-1; j >= 0; j-- )
-                    pfn_type[j] = ((uint32_t *)pfn_type)[j] &
-                                  XEN_DOMCTL_PFINFO_LTAB_MASK;
 
                 for ( j = 0; j < batch; j++ )
                 {
diff -r 0b138a019292 -r 0447c5532e9f tools/libxc/xc_offline_page.c
--- a/tools/libxc/xc_offline_page.c     Wed Jan 13 08:12:56 2010 +0000
+++ b/tools/libxc/xc_offline_page.c     Wed Jan 13 08:14:01 2010 +0000
@@ -24,7 +24,7 @@ struct domain_mem_info{
     int domid;
     unsigned int pt_level;
     unsigned int guest_width;
-    uint32_t *pfn_type;
+    xen_pfn_t *pfn_type;
     xen_pfn_t *p2m_table;
     unsigned long p2m_size;
     xen_pfn_t *m2p_table;
@@ -266,19 +266,18 @@ static int init_mem_info(int xc_handle, 
     }
 
     /* Get pfn type */
-    minfo->pfn_type = malloc(sizeof(uint32_t) * minfo->p2m_size);
+    minfo->pfn_type = calloc(sizeof(*minfo->pfn_type), minfo->p2m_size);
     if (!minfo->pfn_type)
     {
         ERROR("Failed to malloc pfn_type\n");
         goto failed;
     }
-    memset(minfo->pfn_type, 0, sizeof(uint32_t) * minfo->p2m_size);
 
     for (i = 0; i < minfo->p2m_size; i++)
         minfo->pfn_type[i] = pfn_to_mfn(i, minfo->p2m_table,
                                         minfo->guest_width);
 
-    if ( lock_pages(minfo->pfn_type, minfo->p2m_size * sizeof(uint32_t)) )
+    if ( lock_pages(minfo->pfn_type, minfo->p2m_size * 
sizeof(*minfo->pfn_type)) )
     {
         ERROR("Unable to lock pfn_type array");
         goto failed;
@@ -297,12 +296,12 @@ static int init_mem_info(int xc_handle, 
     return 0;
 
 unlock:
-    unlock_pages(minfo->pfn_type, minfo->p2m_size * sizeof(uint32_t));
+    unlock_pages(minfo->pfn_type, minfo->p2m_size * sizeof(*minfo->pfn_type));
 failed:
     if (minfo->pfn_type)
     {
+        free(minfo->pfn_type);
         minfo->pfn_type = NULL;
-        free(minfo->pfn_type);
     }
     if (live_shinfo)
         munmap(live_shinfo, PAGE_SIZE);
@@ -418,7 +417,9 @@ static int change_pte(int xc_handle, int
         uint64_t pte, new_pte;
         int j;
 
-        if ( table_mfn == INVALID_P2M_ENTRY )
+        if ( (table_mfn == INVALID_P2M_ENTRY) ||
+             ((minfo->pfn_type[i] & XEN_DOMCTL_PFINFO_LTAB_MASK) ==
+              XEN_DOMCTL_PFINFO_XTAB) )
             continue;
 
         if ( minfo->pfn_type[i] & XEN_DOMCTL_PFINFO_LTABTYPE_MASK )
diff -r 0b138a019292 -r 0447c5532e9f tools/libxc/xc_private.c
--- a/tools/libxc/xc_private.c  Wed Jan 13 08:12:56 2010 +0000
+++ b/tools/libxc/xc_private.c  Wed Jan 13 08:14:01 2010 +0000
@@ -149,14 +149,14 @@ void unlock_pages(void *addr, size_t len
 }
 
 /* NB: arr must be locked */
-int xc_get_pfn_type_batch(int xc_handle,
-                          uint32_t dom, int num, uint32_t *arr)
+int xc_get_pfn_type_batch(int xc_handle, uint32_t dom,
+                          unsigned int num, xen_pfn_t *arr)
 {
     DECLARE_DOMCTL;
-    domctl.cmd = XEN_DOMCTL_getpageframeinfo2;
+    domctl.cmd = XEN_DOMCTL_getpageframeinfo3;
     domctl.domain = (domid_t)dom;
-    domctl.u.getpageframeinfo2.num    = num;
-    set_xen_guest_handle(domctl.u.getpageframeinfo2.array, arr);
+    domctl.u.getpageframeinfo3.num = num;
+    set_xen_guest_handle(domctl.u.getpageframeinfo3.array, arr);
     return do_domctl(xc_handle, &domctl);
 }
 
diff -r 0b138a019292 -r 0447c5532e9f tools/libxc/xc_private.h
--- a/tools/libxc/xc_private.h  Wed Jan 13 08:12:56 2010 +0000
+++ b/tools/libxc/xc_private.h  Wed Jan 13 08:14:01 2010 +0000
@@ -190,6 +190,9 @@ void *xc_map_foreign_ranges(int xc_handl
 void *xc_map_foreign_ranges(int xc_handle, uint32_t dom,
                             size_t size, int prot, size_t chunksize,
                             privcmd_mmap_entry_t entries[], int nentries);
+
+int xc_get_pfn_type_batch(int xc_handle, uint32_t dom,
+                          unsigned int num, xen_pfn_t *);
 
 void bitmap_64_to_byte(uint8_t *bp, const uint64_t *lp, int nbits);
 void bitmap_byte_to_64(uint64_t *lp, const uint8_t *bp, int nbits);
diff -r 0b138a019292 -r 0447c5532e9f tools/libxc/xenctrl.h
--- a/tools/libxc/xenctrl.h     Wed Jan 13 08:12:56 2010 +0000
+++ b/tools/libxc/xenctrl.h     Wed Jan 13 08:14:01 2010 +0000
@@ -801,9 +801,6 @@ int xc_mmuext_op(int xc_handle, struct m
                  domid_t dom);
 
 int xc_memory_op(int xc_handle, int cmd, void *arg);
-
-int xc_get_pfn_type_batch(int xc_handle, uint32_t dom,
-                          int num, uint32_t *arr);
 
 
 /* Get current total pages allocated to a domain. */
diff -r 0b138a019292 -r 0447c5532e9f xen/arch/x86/domctl.c
--- a/xen/arch/x86/domctl.c     Wed Jan 13 08:12:56 2010 +0000
+++ b/xen/arch/x86/domctl.c     Wed Jan 13 08:14:01 2010 +0000
@@ -160,6 +160,106 @@ long arch_do_domctl(
     }
     break;
 
+    case XEN_DOMCTL_getpageframeinfo3:
+#ifdef __x86_64__
+        if (!has_32bit_shinfo(current->domain))
+        {
+            unsigned int n, j;
+            unsigned int num = domctl->u.getpageframeinfo3.num;
+            domid_t dom = domctl->domain;
+            struct domain *d;
+            struct page_info *page;
+            xen_pfn_t *arr;
+
+            ret = -ESRCH;
+            if ( unlikely((d = rcu_lock_domain_by_id(dom)) == NULL) )
+                break;
+
+            if ( unlikely(num > 1024) ||
+                 unlikely(num != domctl->u.getpageframeinfo3.num) )
+            {
+                ret = -E2BIG;
+                rcu_unlock_domain(d);
+                break;
+            }
+
+            page = alloc_domheap_page(NULL, 0);
+            if ( !page )
+            {
+                ret = -ENOMEM;
+                rcu_unlock_domain(d);
+                break;
+            }
+            arr = page_to_virt(page);
+
+            for ( n = ret = 0; n < num; )
+            {
+                unsigned int k = min_t(unsigned int, num - n, PAGE_SIZE / 4);
+
+                if ( copy_from_guest_offset(arr,
+                                            domctl->u.getpageframeinfo3.array,
+                                            n, k) )
+                {
+                    ret = -EFAULT;
+                    break;
+                }
+
+                for ( j = 0; j < k; j++ )
+                {
+                    unsigned long type = 0, mfn = arr[j];
+
+                    page = mfn_to_page(mfn);
+
+                    if ( unlikely(!mfn_valid(mfn)) )
+                        type = XEN_DOMCTL_PFINFO_XTAB;
+                    else if ( xsm_getpageframeinfo(page) != 0 )
+                        ;
+                    else if ( likely(get_page(page, d)) )
+                    {
+                        switch( page->u.inuse.type_info & PGT_type_mask )
+                        {
+                        case PGT_l1_page_table:
+                            type = XEN_DOMCTL_PFINFO_L1TAB;
+                            break;
+                        case PGT_l2_page_table:
+                            type = XEN_DOMCTL_PFINFO_L2TAB;
+                            break;
+                        case PGT_l3_page_table:
+                            type = XEN_DOMCTL_PFINFO_L3TAB;
+                            break;
+                        case PGT_l4_page_table:
+                            type = XEN_DOMCTL_PFINFO_L4TAB;
+                            break;
+                        }
+
+                        if ( page->u.inuse.type_info & PGT_pinned )
+                            type |= XEN_DOMCTL_PFINFO_LPINTAB;
+
+                        put_page(page);
+                    }
+                    else
+                        type = XEN_DOMCTL_PFINFO_XTAB;
+
+                    arr[j] = type;
+                }
+
+                if ( copy_to_guest_offset(domctl->u.getpageframeinfo3.array,
+                                          n, arr, k) )
+                {
+                    ret = -EFAULT;
+                    break;
+                }
+
+                n += k;
+            }
+
+            free_domheap_page(virt_to_page(arr));
+
+            rcu_unlock_domain(d);
+            break;
+        }
+#endif
+        /* fall thru */
     case XEN_DOMCTL_getpageframeinfo2:
     {
         int n,j;
@@ -183,7 +283,7 @@ long arch_do_domctl(
         if ( !arr32 )
         {
             ret = -ENOMEM;
-            put_domain(d);
+            rcu_unlock_domain(d);
             break;
         }
  
@@ -209,11 +309,14 @@ long arch_do_domctl(
 
                 page = mfn_to_page(mfn);
 
-                ret = xsm_getpageframeinfo(page);
-                if ( ret )
+                if ( domctl->cmd == XEN_DOMCTL_getpageframeinfo3)
+                    arr32[j] = 0;
+
+                if ( unlikely(!mfn_valid(mfn)) )
+                    arr32[j] |= XEN_DOMCTL_PFINFO_XTAB;
+                else if ( xsm_getpageframeinfo(page) != 0 )
                     continue;
-
-                if ( likely(mfn_valid(mfn) && get_page(page, d)) ) 
+                else if ( likely(get_page(page, d)) )
                 {
                     unsigned long type = 0;
 
diff -r 0b138a019292 -r 0447c5532e9f xen/include/public/domctl.h
--- a/xen/include/public/domctl.h       Wed Jan 13 08:12:56 2010 +0000
+++ b/xen/include/public/domctl.h       Wed Jan 13 08:14:01 2010 +0000
@@ -160,6 +160,14 @@ struct xen_domctl_getpageframeinfo2 {
 };
 typedef struct xen_domctl_getpageframeinfo2 xen_domctl_getpageframeinfo2_t;
 DEFINE_XEN_GUEST_HANDLE(xen_domctl_getpageframeinfo2_t);
+
+/* XEN_DOMCTL_getpageframeinfo3 */
+struct xen_domctl_getpageframeinfo3 {
+    /* IN variables. */
+    uint64_aligned_t num;
+    /* IN/OUT variables. */
+    XEN_GUEST_HANDLE_64(xen_pfn_t) array;
+};
 
 
 /*
@@ -832,6 +840,7 @@ struct xen_domctl {
 #define XEN_DOMCTL_disable_migrate               58
 #define XEN_DOMCTL_gettscinfo                    59
 #define XEN_DOMCTL_settscinfo                    60
+#define XEN_DOMCTL_getpageframeinfo3             61
 #define XEN_DOMCTL_gdbsx_guestmemio            1000
 #define XEN_DOMCTL_gdbsx_pausevcpu             1001
 #define XEN_DOMCTL_gdbsx_unpausevcpu           1002
@@ -844,6 +853,7 @@ struct xen_domctl {
         struct xen_domctl_getmemlist        getmemlist;
         struct xen_domctl_getpageframeinfo  getpageframeinfo;
         struct xen_domctl_getpageframeinfo2 getpageframeinfo2;
+        struct xen_domctl_getpageframeinfo3 getpageframeinfo3;
         struct xen_domctl_vcpuaffinity      vcpuaffinity;
         struct xen_domctl_shadow_op         shadow_op;
         struct xen_domctl_max_mem           max_mem;

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.