# 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
|