[IA64] libxc: make xc_ia64_copy_memmap use DOM0VP_get_memmap.

Guest domain's memory map may be updated concurrently so that
it is protected sequence lock.
This patch makes xc_ia64_copy_memmap() use DOM0VP_get_memmap
hypercall to avoid the race.

Signed-off-by: Isaku Yamahata <[EMAIL PROTECTED]>

diff -r f839b8f7ff6f tools/libxc/ia64/xc_ia64_stubs.c
--- a/tools/libxc/ia64/xc_ia64_stubs.c  Thu Oct 02 15:25:23 2008 +0900
+++ b/tools/libxc/ia64/xc_ia64_stubs.c  Thu Oct 02 15:26:27 2008 +0900
@@ -60,46 +60,89 @@
             ? -1 : domctl.u.getdomaininfo.max_pages);
 }
 
+/* It is possible to get memmap_info and memmap by
+   foreign domain page mapping. But it's racy. Use hypercall to avoid race. */
+static int
+xc_ia64_get_memmap(int xc_handle,
+                   uint32_t domid, char *buf, unsigned long bufsize)
+{
+    privcmd_hypercall_t hypercall;
+    int ret;
+
+    hypercall.op = __HYPERVISOR_ia64_dom0vp_op;
+    hypercall.arg[0] = IA64_DOM0VP_get_memmap;
+    hypercall.arg[1] = domid;
+    hypercall.arg[2] = (unsigned long)buf;
+    hypercall.arg[3] = bufsize;
+    hypercall.arg[4] = 0;
+
+    if (lock_pages(buf, bufsize) != 0)
+        return -1;
+    ret = do_xen_hypercall(xc_handle, &hypercall);
+    unlock_pages(buf, bufsize);
+    return ret;
+}
+
 int
 xc_ia64_copy_memmap(int xc_handle, uint32_t domid, shared_info_t *live_shinfo,
                     xen_ia64_memmap_info_t **memmap_info_p,
                     unsigned long *memmap_info_num_pages_p)
 {
-    unsigned int memmap_info_num_pages;
-    unsigned long memmap_info_pfn;
+    unsigned long gpfn_max_prev;
+    unsigned long gpfn_max_post;
+
+    unsigned long num_pages;
+    unsigned long num_pages_post;
     unsigned long memmap_size;
-
-    xen_ia64_memmap_info_t *memmap_info_live;
     xen_ia64_memmap_info_t *memmap_info;
 
-    /* copy before use in case someone updating them */
-    memmap_info_num_pages = live_shinfo->arch.memmap_info_num_pages;
-    memmap_info_pfn = live_shinfo->arch.memmap_info_pfn;
-    if (memmap_info_num_pages == 0 || memmap_info_pfn == 0) {
-        ERROR("memmap_info_num_pages 0x%x memmap_info_pfn 0x%lx",
-              memmap_info_num_pages, memmap_info_pfn);
+    int ret;
+
+    gpfn_max_prev = xc_memory_op(xc_handle, XENMEM_maximum_gpfn, &domid);
+    if (gpfn_max_prev < 0)
+        return -1;
+
+ again:
+    num_pages = live_shinfo->arch.memmap_info_num_pages;
+    if (num_pages == 0) {
+        ERROR("num_pages 0x%x", num_pages);
         return -1;
     }
 
-    memmap_size = memmap_info_num_pages << PAGE_SHIFT;
-    memmap_info_live = xc_map_foreign_range(xc_handle, domid, memmap_size,
-                                            PROT_READ, memmap_info_pfn);
-    if (memmap_info_live == NULL) {
-        PERROR("Could not map memmap info.");
+    memmap_size = num_pages << PAGE_SHIFT;
+    memmap_info = malloc(memmap_size);
+    if (memmap_info == NULL)
+        return -1;
+    ret = xc_ia64_get_memmap(xc_handle,
+                             domid, (char*)memmap_info, memmap_size);
+    if (ret != 0) {
+        free(memmap_info);
         return -1;
     }
-    memmap_info = malloc(memmap_size);
-    if (memmap_info == NULL) {
-        munmap(memmap_info_live, memmap_size);
+    xen_rmb();
+    num_pages_post = live_shinfo->arch.memmap_info_num_pages;
+    if (num_pages != num_pages_post) {
+        free(memmap_info);
+        num_pages = num_pages_post;
+        goto again;
+    }
+
+    gpfn_max_post = xc_memory_op(xc_handle, XENMEM_maximum_gpfn, &domid);
+    if (gpfn_max_prev < 0) {
+        free(memmap_info);
         return -1;
     }
-    memcpy(memmap_info, memmap_info_live, memmap_size); /* copy before use */
-    munmap(memmap_info_live, memmap_size);
+    if (gpfn_max_post > gpfn_max_prev) {
+        free(memmap_info);
+        gpfn_max_prev = gpfn_max_post;
+        goto again;
+    }
 
     /* reject unknown memmap */
     if (memmap_info->efi_memdesc_size != sizeof(efi_memory_desc_t) ||
         (memmap_info->efi_memmap_size / memmap_info->efi_memdesc_size) == 0 ||
-        memmap_info->efi_memmap_size > memmap_size - sizeof(memmap_info) ||
+        memmap_info->efi_memmap_size >
+        (num_pages << PAGE_SHIFT) - sizeof(memmap_info) ||
         memmap_info->efi_memdesc_version != EFI_MEMORY_DESCRIPTOR_VERSION) {
         PERROR("unknown memmap header. defaulting to compat mode.");
         free(memmap_info);
@@ -108,7 +151,7 @@
 
     *memmap_info_p = memmap_info;
     if (memmap_info_num_pages_p != NULL)
-        *memmap_info_num_pages_p = memmap_info_num_pages;
+        *memmap_info_num_pages_p = num_pages;
 
     return 0;
 }
[IA64] libxc: make xc_ia64_copy_memmap use DOM0VP_get_memmap.

Guest domain's memory map may be updated concurrently so that
it is protected sequence lock.
This patch makes xc_ia64_copy_memmap() use DOM0VP_get_memmap
hypercall to avoid the race.

Signed-off-by: Isaku Yamahata <[EMAIL PROTECTED]>

diff -r f839b8f7ff6f tools/libxc/ia64/xc_ia64_stubs.c
--- a/tools/libxc/ia64/xc_ia64_stubs.c	Thu Oct 02 15:25:23 2008 +0900
+++ b/tools/libxc/ia64/xc_ia64_stubs.c	Thu Oct 02 15:26:27 2008 +0900
@@ -60,46 +60,89 @@
             ? -1 : domctl.u.getdomaininfo.max_pages);
 }
 
+/* It is possible to get memmap_info and memmap by
+   foreign domain page mapping. But it's racy. Use hypercall to avoid race. */
+static int
+xc_ia64_get_memmap(int xc_handle,
+                   uint32_t domid, char *buf, unsigned long bufsize)
+{
+    privcmd_hypercall_t hypercall;
+    int ret;
+
+    hypercall.op = __HYPERVISOR_ia64_dom0vp_op;
+    hypercall.arg[0] = IA64_DOM0VP_get_memmap;
+    hypercall.arg[1] = domid;
+    hypercall.arg[2] = (unsigned long)buf;
+    hypercall.arg[3] = bufsize;
+    hypercall.arg[4] = 0;
+
+    if (lock_pages(buf, bufsize) != 0)
+        return -1;
+    ret = do_xen_hypercall(xc_handle, &hypercall);
+    unlock_pages(buf, bufsize);
+    return ret;
+}
+
 int
 xc_ia64_copy_memmap(int xc_handle, uint32_t domid, shared_info_t *live_shinfo,
                     xen_ia64_memmap_info_t **memmap_info_p,
                     unsigned long *memmap_info_num_pages_p)
 {
-    unsigned int memmap_info_num_pages;
-    unsigned long memmap_info_pfn;
+    unsigned long gpfn_max_prev;
+    unsigned long gpfn_max_post;
+
+    unsigned long num_pages;
+    unsigned long num_pages_post;
     unsigned long memmap_size;
-
-    xen_ia64_memmap_info_t *memmap_info_live;
     xen_ia64_memmap_info_t *memmap_info;
 
-    /* copy before use in case someone updating them */
-    memmap_info_num_pages = live_shinfo->arch.memmap_info_num_pages;
-    memmap_info_pfn = live_shinfo->arch.memmap_info_pfn;
-    if (memmap_info_num_pages == 0 || memmap_info_pfn == 0) {
-        ERROR("memmap_info_num_pages 0x%x memmap_info_pfn 0x%lx",
-              memmap_info_num_pages, memmap_info_pfn);
+    int ret;
+
+    gpfn_max_prev = xc_memory_op(xc_handle, XENMEM_maximum_gpfn, &domid);
+    if (gpfn_max_prev < 0)
+        return -1;
+
+ again:
+    num_pages = live_shinfo->arch.memmap_info_num_pages;
+    if (num_pages == 0) {
+        ERROR("num_pages 0x%x", num_pages);
         return -1;
     }
 
-    memmap_size = memmap_info_num_pages << PAGE_SHIFT;
-    memmap_info_live = xc_map_foreign_range(xc_handle, domid, memmap_size,
-                                            PROT_READ, memmap_info_pfn);
-    if (memmap_info_live == NULL) {
-        PERROR("Could not map memmap info.");
+    memmap_size = num_pages << PAGE_SHIFT;
+    memmap_info = malloc(memmap_size);
+    if (memmap_info == NULL)
+        return -1;
+    ret = xc_ia64_get_memmap(xc_handle,
+                             domid, (char*)memmap_info, memmap_size);
+    if (ret != 0) {
+        free(memmap_info);
         return -1;
     }
-    memmap_info = malloc(memmap_size);
-    if (memmap_info == NULL) {
-        munmap(memmap_info_live, memmap_size);
+    xen_rmb();
+    num_pages_post = live_shinfo->arch.memmap_info_num_pages;
+    if (num_pages != num_pages_post) {
+        free(memmap_info);
+        num_pages = num_pages_post;
+        goto again;
+    }
+
+    gpfn_max_post = xc_memory_op(xc_handle, XENMEM_maximum_gpfn, &domid);
+    if (gpfn_max_prev < 0) {
+        free(memmap_info);
         return -1;
     }
-    memcpy(memmap_info, memmap_info_live, memmap_size); /* copy before use */
-    munmap(memmap_info_live, memmap_size);
+    if (gpfn_max_post > gpfn_max_prev) {
+        free(memmap_info);
+        gpfn_max_prev = gpfn_max_post;
+        goto again;
+    }
 
     /* reject unknown memmap */
     if (memmap_info->efi_memdesc_size != sizeof(efi_memory_desc_t) ||
         (memmap_info->efi_memmap_size / memmap_info->efi_memdesc_size) == 0 ||
-        memmap_info->efi_memmap_size > memmap_size - sizeof(memmap_info) ||
+        memmap_info->efi_memmap_size >
+        (num_pages << PAGE_SHIFT) - sizeof(memmap_info) ||
         memmap_info->efi_memdesc_version != EFI_MEMORY_DESCRIPTOR_VERSION) {
         PERROR("unknown memmap header. defaulting to compat mode.");
         free(memmap_info);
@@ -108,7 +151,7 @@
 
     *memmap_info_p = memmap_info;
     if (memmap_info_num_pages_p != NULL)
-        *memmap_info_num_pages_p = memmap_info_num_pages;
+        *memmap_info_num_pages_p = num_pages;
 
     return 0;
 }
_______________________________________________
Xen-ia64-devel mailing list
Xen-ia64-devel@lists.xensource.com
http://lists.xensource.com/xen-ia64-devel

Reply via email to