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

[Xen-devel] [PATCH, RFC 4/4] 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 what used to be xc_get_pfn_type_batch().

API-wise the question is whether xc_get_pfn_type_{batch,bulk}() are
supposed to be externally visible functions (their implementation
living in xc_private.c contradicts their prototypes being in
xenctrl.h). If not, the former can go away altogether (or simply be
changed instead of a new variant being added). If so, fallback code
for the latter function may be deemed necessary.

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>

--- 2010-01-06.orig/tools/libxc/xc_domain_save.c        2010-01-11 
14:39:23.000000000 +0100
+++ 2010-01-06/tools/libxc/xc_domain_save.c     2010-01-11 14:41:41.000000000 
+0100
@@ -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_bulk(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++ )
                 {
--- 2010-01-06.orig/tools/libxc/xc_offline_page.c       2010-01-11 
14:41:20.000000000 +0100
+++ 2010-01-06/tools/libxc/xc_offline_page.c    2010-01-11 14:09:01.000000000 
+0100
@@ -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;
@@ -287,7 +286,7 @@ static int init_mem_info(int xc_handle, 
     for (i = 0; i < minfo->p2m_size ; i+=1024)
     {
         int count = ((dinfo->p2m_size - i ) > 1024 ) ? 1024: (dinfo->p2m_size 
- i);
-        if ( ( rc = xc_get_pfn_type_batch(xc_handle, domid, count,
+        if ( ( rc = xc_get_pfn_type_bulk(xc_handle, domid, count,
                   minfo->pfn_type + i)) )
         {
             ERROR("Failed to get pfn_type %x\n", rc);
@@ -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)
     {
-        minfo->pfn_type = NULL;
         free(minfo->pfn_type);
+        minfo->pfn_type = NULL;
     }
     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 )
--- 2010-01-06.orig/tools/libxc/xc_private.c    2010-01-11 14:41:20.000000000 
+0100
+++ 2010-01-06/tools/libxc/xc_private.c 2010-01-11 13:52:37.000000000 +0100
@@ -160,6 +160,18 @@ int xc_get_pfn_type_batch(int xc_handle,
     return do_domctl(xc_handle, &domctl);
 }
 
+/* NB: arr must be locked */
+int xc_get_pfn_type_bulk(int xc_handle, uint32_t dom,
+                         unsigned int num, xen_pfn_t *arr)
+{
+    DECLARE_DOMCTL;
+    domctl.cmd = XEN_DOMCTL_getpageframeinfo3;
+    domctl.domain = (domid_t)dom;
+    domctl.u.getpageframeinfo3.num = num;
+    set_xen_guest_handle(domctl.u.getpageframeinfo3.array, arr);
+    return do_domctl(xc_handle, &domctl);
+}
+
 int xc_mmuext_op(
     int xc_handle,
     struct mmuext_op *op,
--- 2010-01-06.orig/tools/libxc/xenctrl.h       2010-01-08 13:50:58.000000000 
+0100
+++ 2010-01-06/tools/libxc/xenctrl.h    2010-01-11 13:51:22.000000000 +0100
@@ -802,6 +802,9 @@ int xc_mmuext_op(int xc_handle, struct m
 
 int xc_memory_op(int xc_handle, int cmd, void *arg);
 
+int xc_get_pfn_type_bulk(int xc_handle, uint32_t dom,
+                         unsigned int num, xen_pfn_t *);
+/* DEPRECATED - use xc_get_pfn_type_bulk() instead. */
 int xc_get_pfn_type_batch(int xc_handle, uint32_t dom,
                           int num, uint32_t *arr);
 
--- 2010-01-06.orig/xen/arch/x86/domctl.c       2010-01-11 14:41:20.000000000 
+0100
+++ 2010-01-06/xen/arch/x86/domctl.c    2010-01-11 14:15:24.000000000 +0100
@@ -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 )
-                    continue;
+                if ( domctl->cmd == XEN_DOMCTL_getpageframeinfo3)
+                    arr32[j] = 0;
 
-                if ( likely(mfn_valid(mfn) && get_page(page, d)) ) 
+                if ( unlikely(!mfn_valid(mfn)) )
+                    arr32[j] |= XEN_DOMCTL_PFINFO_XTAB;
+                else if ( xsm_getpageframeinfo(page) != 0 )
+                    continue;
+                else if ( likely(get_page(page, d)) )
                 {
                     unsigned long type = 0;
 
--- 2010-01-06.orig/xen/include/public/domctl.h 2010-01-11 14:41:20.000000000 
+0100
+++ 2010-01-06/xen/include/public/domctl.h      2010-01-11 12:13:16.000000000 
+0100
@@ -161,6 +161,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;
+};
+
 
 /*
  * Control shadow pagetables operation
@@ -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-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel


 


Rackspace

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