WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

[Xen-devel] [PATCH, RFC 4/4] add and use XEN_DOMCTL_getpageframeinfo3

To: <xen-devel@xxxxxxxxxxxxxxxxxxx>
Subject: [Xen-devel] [PATCH, RFC 4/4] add and use XEN_DOMCTL_getpageframeinfo3
From: "Jan Beulich" <JBeulich@xxxxxxxxxx>
Date: Mon, 11 Jan 2010 14:51:27 +0000
Delivery-date: Mon, 11 Jan 2010 06:54:10 -0800
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
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

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-devel] [PATCH, RFC 4/4] add and use XEN_DOMCTL_getpageframeinfo3, Jan Beulich <=