[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v4 1/4] xen: introduce a helper to allocate non-contiguous memory
The allocator uses independent calls to alloc_heap_pages in order to get the desired amount of memory and then maps all the independent physical addresses into a contiguous virtual address space. In order to keep track of this regions a red-black tree is used. Signed-off-by: Roger Pau Monnà <roger.pau@xxxxxxxxxx> Cc: Ian Campbell <ian.campbell@xxxxxxxxxx> Cc: Jan Beulich <jbeulich@xxxxxxxx> Cc: Tim Deegan <tim@xxxxxxx> Cc: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> --- xen/common/page_alloc.c | 131 ++++++++++++++++++++++++++++++++++++++++++++++++ xen/include/xen/mm.h | 2 + 2 files changed, 133 insertions(+) diff --git a/xen/common/page_alloc.c b/xen/common/page_alloc.c index 8500ed7..4ad5184 100644 --- a/xen/common/page_alloc.c +++ b/xen/common/page_alloc.c @@ -38,6 +38,7 @@ #include <xen/event.h> #include <xen/tmem.h> #include <xen/tmem_xen.h> +#include <xen/rbtree.h> #include <public/sysctl.h> #include <public/sched.h> #include <asm/page.h> @@ -107,6 +108,13 @@ struct scrub_region { static struct scrub_region __initdata region[MAX_NUMNODES]; static unsigned long __initdata chunk_size; +static struct rb_root non_contiguous = { NULL, }; +struct va_page { + struct rb_node node; + void *va; + unsigned long mfn; +}; + static void __init boot_bug(int line) { panic("Boot BUG at %s:%d", __FILE__, line); @@ -1601,6 +1609,129 @@ void free_xenheap_pages(void *v, unsigned int order) #endif +static struct va_page *va_xenheap_search(struct rb_root *root, void *va) +{ + struct rb_node *node = root->rb_node; + + while ( node ) + { + struct va_page *data = container_of(node, struct va_page, node); + + if ( data->va == va ) + return data; + if ( va < data->va ) + node = node->rb_left; + else + node = node->rb_right; + } + + return NULL; +} + +static int va_xenheap_insert(struct rb_root *root, struct va_page *data) +{ + struct rb_node **new = &(root->rb_node), *parent = NULL; + + /* Figure out where to put new node */ + while ( *new ) + { + struct va_page *this = container_of(*new, struct va_page, node); + + parent = *new; + if ( data->va < this->va ) + new = &((*new)->rb_left); + else if ( data->va > this->va ) + new = &((*new)->rb_right); + else + return -EEXIST; + } + + /* Add new node and rebalance tree. */ + rb_link_node(&data->node, parent, new); + rb_insert_color(&data->node, root); + + return 0; +} + +void *alloc_xenheap_noncontiguous(unsigned int pages, unsigned int memflags) +{ + unsigned long *mfn; + unsigned int i; + struct va_page *va_rb; + struct page_info *pg; + void *va = NULL; + + + mfn = xzalloc_array(unsigned long, pages); + if ( mfn == NULL ) + return NULL; + + for ( i = 0; i < pages; i++ ) + { + pg = alloc_heap_pages(MEMZONE_XEN, MEMZONE_XEN, 1, memflags, NULL); + if ( pg == NULL ) + goto error; + mfn[i] = page_to_mfn(pg); + } + + va = vmap(mfn, pages); + if ( va == NULL ) + goto error; + + for ( i = 0; i < pages; i++ ) + { + va_rb = xmalloc_bytes(sizeof(*va_rb)); + if ( va_rb == NULL ) + goto error; + va_rb->va = va + i * PAGE_SIZE; + va_rb->mfn = mfn[i]; + BUG_ON(va_xenheap_insert(&non_contiguous, va_rb)); + } + + xfree(mfn); + return va; + + error: + if ( va != NULL ) + { + for ( i = 0; i < pages; i++ ) + { + va_rb = va_xenheap_search(&non_contiguous, va + i * PAGE_SIZE); + if ( va_rb != NULL ) + { + rb_erase(&va_rb->node, &non_contiguous); + xfree(va_rb); + } + } + vunmap(va); + } + for ( i = 0; i < pages; i++ ) + if ( mfn[i] != 0 ) + free_heap_pages(mfn_to_page(mfn[i]), 1); + xfree(mfn); + return NULL; +} + +void free_xenheap_noncontiguous(void *va, unsigned int pages) +{ + struct va_page *va_rb; + int i; + + if ( va == NULL || pages == 0 ) + return; + + vunmap(va); + + for ( i = 0; i < pages; i++ ) + { + va_rb = va_xenheap_search(&non_contiguous, va + i * PAGE_SIZE); + BUG_ON(va_rb == NULL); + free_heap_pages(mfn_to_page(va_rb->mfn), 1); + rb_erase(&va_rb->node, &non_contiguous); + xfree(va_rb); + } +} + /************************* diff --git a/xen/include/xen/mm.h b/xen/include/xen/mm.h index a066363..b1eae58 100644 --- a/xen/include/xen/mm.h +++ b/xen/include/xen/mm.h @@ -48,6 +48,8 @@ void *alloc_xenheap_pages(unsigned int order, unsigned int memflags); void free_xenheap_pages(void *v, unsigned int order); #define alloc_xenheap_page() (alloc_xenheap_pages(0,0)) #define free_xenheap_page(v) (free_xenheap_pages(v,0)) +void *alloc_xenheap_noncontiguous(unsigned int pages, unsigned int memflags); +void free_xenheap_noncontiguous(void *va, unsigned int pages); /* Map machine page range in Xen virtual address space. */ int map_pages_to_xen( unsigned long virt, -- 1.9.5 (Apple Git-50.3) _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |