From cd12909cb576d37311fe35868780e82d5007d0c8 Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Thu, 29 Sep 2011 16:53:32 +0100 Subject: xen: map foreign pages for shared rings by updating the PTEs directly When mapping a foreign page with xenbus_map_ring_valloc() with the GNTTABOP_map_grant_ref hypercall, set the GNTMAP_contains_pte flag and pass a pointer to the PTE (in init_mm). After the page is mapped, the usual fault mechanism can be used to update additional MMs. This allows the vmalloc_sync_all() to be removed from alloc_vm_area(). Signed-off-by: David Vrabel Acked-by: Andrew Morton [v1: Squashed fix by Michal for no-mmu case] Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Michal Simek --- drivers/xen/xenbus/xenbus_client.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers/xen') diff --git a/drivers/xen/xenbus/xenbus_client.c b/drivers/xen/xenbus/xenbus_client.c index 81c3ce6b8bb..1906125eab4 100644 --- a/drivers/xen/xenbus/xenbus_client.c +++ b/drivers/xen/xenbus/xenbus_client.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -436,19 +437,20 @@ EXPORT_SYMBOL_GPL(xenbus_free_evtchn); int xenbus_map_ring_valloc(struct xenbus_device *dev, int gnt_ref, void **vaddr) { struct gnttab_map_grant_ref op = { - .flags = GNTMAP_host_map, + .flags = GNTMAP_host_map | GNTMAP_contains_pte, .ref = gnt_ref, .dom = dev->otherend_id, }; struct vm_struct *area; + pte_t *pte; *vaddr = NULL; - area = alloc_vm_area(PAGE_SIZE); + area = alloc_vm_area(PAGE_SIZE, &pte); if (!area) return -ENOMEM; - op.host_addr = (unsigned long)area->addr; + op.host_addr = arbitrary_virt_to_machine(pte).maddr; if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1)) BUG(); @@ -527,6 +529,7 @@ int xenbus_unmap_ring_vfree(struct xenbus_device *dev, void *vaddr) struct gnttab_unmap_grant_ref op = { .host_addr = (unsigned long)vaddr, }; + unsigned int level; /* It'd be nice if linux/vmalloc.h provided a find_vm_area(void *addr) * method so that we don't have to muck with vmalloc internals here. @@ -548,6 +551,8 @@ int xenbus_unmap_ring_vfree(struct xenbus_device *dev, void *vaddr) } op.handle = (grant_handle_t)area->phys_addr; + op.host_addr = arbitrary_virt_to_machine( + lookup_address((unsigned long)vaddr, &level)).maddr; if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1)) BUG(); -- cgit v1.2.3 From 72e9cf2ab12ef3e050577ffebdb0c88a28df821d Mon Sep 17 00:00:00 2001 From: Daniel De Graaf Date: Wed, 19 Oct 2011 17:59:37 -0400 Subject: xen/balloon: Avoid OOM when requesting highmem If highmem pages are requested from the balloon on a system without highmem, the implementation of alloc_xenballooned_pages will allocate all available memory trying to find highmem pages to return. Allow low memory to be returned when highmem pages are requested to avoid this loop. Signed-off-by: Daniel De Graaf Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/balloon.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/xen') diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index a767884a6c7..31ab82fda38 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c @@ -501,7 +501,7 @@ EXPORT_SYMBOL_GPL(balloon_set_new_target); * alloc_xenballooned_pages - get pages that have been ballooned out * @nr_pages: Number of pages to get * @pages: pages returned - * @highmem: highmem or lowmem pages + * @highmem: allow highmem pages * @return 0 on success, error otherwise */ int alloc_xenballooned_pages(int nr_pages, struct page **pages, bool highmem) @@ -511,7 +511,7 @@ int alloc_xenballooned_pages(int nr_pages, struct page **pages, bool highmem) mutex_lock(&balloon_mutex); while (pgno < nr_pages) { page = balloon_retrieve(highmem); - if (page && PageHighMem(page) == highmem) { + if (page && (highmem || !PageHighMem(page))) { pages[pgno++] = page; } else { enum bp_state st; -- cgit v1.2.3 From fc6e0c3b909157748ce1c0c0f2a9935a5ee3c812 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 4 Nov 2011 21:23:32 +0300 Subject: xen-gntdev: integer overflow in gntdev_alloc_map() The multiplications here can overflow resulting in smaller buffer sizes than expected. "count" comes from a copy_from_user(). Signed-off-by: Dan Carpenter Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/gntdev.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/xen') diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index 39871326afa..afca14d9042 100644 --- a/drivers/xen/gntdev.c +++ b/drivers/xen/gntdev.c @@ -114,11 +114,11 @@ static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count) if (NULL == add) return NULL; - add->grants = kzalloc(sizeof(add->grants[0]) * count, GFP_KERNEL); - add->map_ops = kzalloc(sizeof(add->map_ops[0]) * count, GFP_KERNEL); - add->unmap_ops = kzalloc(sizeof(add->unmap_ops[0]) * count, GFP_KERNEL); - add->kmap_ops = kzalloc(sizeof(add->kmap_ops[0]) * count, GFP_KERNEL); - add->pages = kzalloc(sizeof(add->pages[0]) * count, GFP_KERNEL); + add->grants = kcalloc(count, sizeof(add->grants[0]), GFP_KERNEL); + add->map_ops = kcalloc(count, sizeof(add->map_ops[0]), GFP_KERNEL); + add->unmap_ops = kcalloc(count, sizeof(add->unmap_ops[0]), GFP_KERNEL); + add->kmap_ops = kcalloc(count, sizeof(add->kmap_ops[0]), GFP_KERNEL); + add->pages = kcalloc(count, sizeof(add->pages[0]), GFP_KERNEL); if (NULL == add->grants || NULL == add->map_ops || NULL == add->unmap_ops || -- cgit v1.2.3 From 21643e69a4c06f7ef155fbc70e3fba13fba4a756 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 4 Nov 2011 21:24:08 +0300 Subject: xen-gntalloc: integer overflow in gntalloc_ioctl_alloc() On 32 bit systems a high value of op.count could lead to an integer overflow in the kzalloc() and gref_ids would be smaller than expected. If the you triggered another integer overflow in "if (gref_size + op.count > limit)" then you'd probably get memory corruption inside add_grefs(). CC: stable@kernel.org Signed-off-by: Dan Carpenter Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/gntalloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/xen') diff --git a/drivers/xen/gntalloc.c b/drivers/xen/gntalloc.c index f6832f46aea..23c60cf4313 100644 --- a/drivers/xen/gntalloc.c +++ b/drivers/xen/gntalloc.c @@ -280,7 +280,7 @@ static long gntalloc_ioctl_alloc(struct gntalloc_file_private_data *priv, goto out; } - gref_ids = kzalloc(sizeof(gref_ids[0]) * op.count, GFP_TEMPORARY); + gref_ids = kcalloc(op.count, sizeof(gref_ids[0]), GFP_TEMPORARY); if (!gref_ids) { rc = -ENOMEM; goto out; -- cgit v1.2.3 From 99cb2ddcc617f43917e94a4147aa3ccdb2bcd77e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 4 Nov 2011 21:24:36 +0300 Subject: xen-gntalloc: signedness bug in add_grefs() gref->gref_id is unsigned so the error handling didn't work. gnttab_grant_foreign_access() returns an int type, so we can add a cast here, and it doesn't cause any problems. gnttab_grant_foreign_access() can return a variety of errors including -ENOSPC, -ENOSYS and -ENOMEM. CC: stable@kernel.org Signed-off-by: Dan Carpenter Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/gntalloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/xen') diff --git a/drivers/xen/gntalloc.c b/drivers/xen/gntalloc.c index 23c60cf4313..e1c4c6e5b46 100644 --- a/drivers/xen/gntalloc.c +++ b/drivers/xen/gntalloc.c @@ -135,7 +135,7 @@ static int add_grefs(struct ioctl_gntalloc_alloc_gref *op, /* Grant foreign access to the page. */ gref->gref_id = gnttab_grant_foreign_access(op->domid, pfn_to_mfn(page_to_pfn(gref->page)), readonly); - if (gref->gref_id < 0) { + if ((int)gref->gref_id < 0) { rc = gref->gref_id; goto undo; } -- cgit v1.2.3