From: Peter Dinda Date: Fri, 17 Apr 2015 17:11:43 +0000 (-0500) Subject: Generalization of constraints on page allocation and implementation/use X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?p=palacios.git;a=commitdiff_plain;h=b58fe2254858e3ecc94be5d86f2a93f2cfe0a0d5 Generalization of constraints on page allocation and implementation/use The idea here is to allow Palacios code to request pages that satisfy some filter function. For example, a filter function might reject allocations above the 4GB line, or it might reject allocations that map to undesirable cache lines. - it removes the notion of a constraint mask in page allocation - eliminates the < 4GB flag - adds the notion of constraints in page allocation as filter functions - modifies the implementation and uses to match --- diff --git a/linux_module/buddy.c b/linux_module/buddy.c index 26a7021..f21c95d 100644 --- a/linux_module/buddy.c +++ b/linux_module/buddy.c @@ -285,13 +285,14 @@ int buddy_remove_pool(struct buddy_memzone * zone, * Arguments: * [IN] mp: Buddy system memory allocator object. * [IN] order: Block size to allocate (2^order bytes). - * [IN] constraints: bitmmask showing restrictions for scan. currently: 0=none, or LWK_BUDDY_CONSTRAINT_4GB + * [IN] filter_func: returns nonzero if given paddr is OK to use + * [IN] filter_state: opaque argument to filter_func * Returns: * Success: Pointer to the start of the allocated memory block. * Failure: NULL */ uintptr_t -buddy_alloc(struct buddy_memzone *zone, unsigned long order, int constraints) +buddy_alloc(struct buddy_memzone *zone, unsigned long order, int (*filter_func)(void *paddr, void *filter_state), void *filter_state) { unsigned long j; struct buddy_mempool * mp = NULL; @@ -301,11 +302,6 @@ buddy_alloc(struct buddy_memzone *zone, unsigned long order, int constraints) struct block * buddy_block = NULL; unsigned long flags = 0; - if (constraints && constraints!=LWK_BUDDY_CONSTRAINT_4GB) { - ERROR("Do not know how to satisfy constraint mask 0x%x\n", constraints); - return (uintptr_t) NULL; - } - BUG_ON(zone == NULL); BUG_ON(order > zone->max_order); @@ -333,23 +329,22 @@ buddy_alloc(struct buddy_memzone *zone, unsigned long order, int constraints) list_for_each(cur, list) { block = list_entry(cur, struct block, link); - if (!constraints) { - // without a constraint, we just want the first one + if (!filter_func) { + // without a filter, we just want the first one break; - } - - if (constraints & LWK_BUDDY_CONSTRAINT_4GB) { - // under this constraint, we will only use if the entirity - // of the allocation within the block will be below 4 GB + } else { + void *block_pa = (void*)__pa(block); - if ((block_pa + (1ULL< no constraints, otherwise bitmask of: -#define LWK_BUDDY_CONSTRAINT_4GB 0x1 /* Allocate pages, returns physical address */ extern uintptr_t buddy_alloc(struct buddy_memzone * zone, unsigned long order, - int constraints); + int (*filter_func)(void *paddr, void *filter_state), + void *filter_state); /* Free a physical address */ diff --git a/linux_module/mm.c b/linux_module/mm.c index 1b70b74..e4c374a 100644 --- a/linux_module/mm.c +++ b/linux_module/mm.c @@ -21,20 +21,9 @@ static uintptr_t * seed_addrs = NULL; // alignment is in bytes -uintptr_t alloc_palacios_pgs(u64 num_pages, u32 alignment, int node_id, int constraints) { +uintptr_t alloc_palacios_pgs(u64 num_pages, u32 alignment, int node_id, int (*filter_func)(void *paddr, void *filter_state), void *filter_state) { uintptr_t addr = 0; int any = node_id==-1; // can allocate on any - int buddy_constraints=0; - - if (constraints && constraints!=V3_ALLOC_PAGES_CONSTRAINT_4GB) { - ERROR("Unknown constraint mask 0x%x\n",constraints); - return 0; - } - - if (constraints & V3_ALLOC_PAGES_CONSTRAINT_4GB) { - buddy_constraints |= LWK_BUDDY_CONSTRAINT_4GB; - } - if (node_id == -1) { int cpu_id = get_cpu(); @@ -50,14 +39,14 @@ uintptr_t alloc_palacios_pgs(u64 num_pages, u32 alignment, int node_id, int cons return 0; } - addr = buddy_alloc(memzones[node_id], get_order(num_pages * PAGE_SIZE) + PAGE_SHIFT, buddy_constraints); + addr = buddy_alloc(memzones[node_id], get_order(num_pages * PAGE_SIZE) + PAGE_SHIFT, filter_func, filter_state); if (!addr && any) { int i; // do a scan to see if we can satisfy request on any node for (i=0; i< numa_num_nodes(); i++) { if (i!=node_id) { - addr = buddy_alloc(memzones[i], get_order(num_pages * PAGE_SIZE) + PAGE_SHIFT, buddy_constraints); + addr = buddy_alloc(memzones[i], get_order(num_pages * PAGE_SIZE) + PAGE_SHIFT, filter_func, filter_state); if (addr) { break; } @@ -313,7 +302,7 @@ int palacios_init_mm( void ) { pgs = alloc_pages_node(node_id, GFP_KERNEL, MAX_ORDER - 1); if (!pgs) { - INFO("Could not allocate initial memory block for node %d beloew 4GB\n", node_id); + INFO("Could not allocate initial memory block for node %d below 4GB\n", node_id); if (!pgs) { ERROR("Could not allocate initial memory block for node %d without restrictions\n", node_id); BUG_ON(!pgs); diff --git a/linux_module/mm.h b/linux_module/mm.h index b758b72..29c0738 100644 --- a/linux_module/mm.h +++ b/linux_module/mm.h @@ -7,7 +7,7 @@ -uintptr_t alloc_palacios_pgs(u64 num_pages, u32 alignment, int node_id, int constraints); +uintptr_t alloc_palacios_pgs(u64 num_pages, u32 alignment, int node_id, int (*filter_func)(void *paddr, void *filter_state), void *filter_state); void free_palacios_pg(uintptr_t base_addr); void free_palacios_pgs(uintptr_t base_addr, u64 num_pages); diff --git a/linux_module/palacios-stubs.c b/linux_module/palacios-stubs.c index 54b2ad1..10d2fde 100644 --- a/linux_module/palacios-stubs.c +++ b/linux_module/palacios-stubs.c @@ -175,18 +175,18 @@ void palacios_print_scoped(void * vm, int vcore, const char *fmt, ...) { * Allocates a contiguous region of pages of the requested size. * Returns the physical address of the first page in the region. */ -void *palacios_allocate_pages(int num_pages, unsigned int alignment, int node_id, int constraints) { +void *palacios_allocate_pages(int num_pages, unsigned int alignment, int node_id, int (*filter_func)(void *paddr, void *filter_state), void *filter_state) { void * pg_addr = NULL; if (num_pages<=0) { - ERROR("ALERT ALERT Attempt to allocate zero or fewer pages (%d pages, alignment %d, node %d, constraints 0x%x)\n",num_pages, alignment, node_id, constraints); + ERROR("ALERT ALERT Attempt to allocate zero or fewer pages (%d pages, alignment %d, node %d, filter_func %p, filter_state %p)\n",num_pages, alignment, node_id, filter_func, filter_state); return NULL; } - pg_addr = (void *)alloc_palacios_pgs(num_pages, alignment, node_id, constraints); + pg_addr = (void *)alloc_palacios_pgs(num_pages, alignment, node_id, filter_func, filter_state); if (!pg_addr) { - ERROR("ALERT ALERT Page allocation has FAILED Warning (%d pages, alignment %d, node %d, constraints 0x%x)\n",num_pages, alignment, node_id, constraints); + ERROR("ALERT ALERT Page allocation has FAILED Warning (%d pages, alignment %d, node %d, filter_func %p, filter_state %p)\n",num_pages, alignment, node_id, filter_func, filter_state); return NULL; } diff --git a/linux_module/palacios.h b/linux_module/palacios.h index 1b5cf44..4c8cf62 100644 --- a/linux_module/palacios.h +++ b/linux_module/palacios.h @@ -62,10 +62,9 @@ struct v3_guest_img { char name[128]; } __attribute__((packed)); -typedef enum { PREALLOCATED=0, // user space-allocated (e.g. hot remove) +typedef enum { PREALLOCATED=0, // user space-allocated (e.g. hot remove) REQUESTED, // kernel will attempt allocation (anywhere) REQUESTED32, // kernel will attempt allocation (<4GB) - } v3_mem_region_type_t; struct v3_mem_region { @@ -156,7 +155,7 @@ struct proc_dir_entry *palacios_get_procdir(void); void palacios_print_scoped(void *vm, int vcore, const char *fmt, ...); #define palacios_print(...) palacios_print_scoped(0,-1, __VA_ARGS__) // node_id=-1 => no node constraint -void *palacios_allocate_pages(int num_pages, unsigned int alignment, int node_id, int constraints); +void *palacios_allocate_pages(int num_pages, unsigned int alignment, int node_id, int (*filter_func)(void *paddr, void *filter_state), void *filter_state); void palacios_free_pages(void *page_addr, int num_pages); void *palacios_alloc(unsigned int size); // node_id=-1 => no node constraint diff --git a/palacios/include/palacios/vmm.h b/palacios/include/palacios/vmm.h index 14bbb2b..c00e10f 100644 --- a/palacios/include/palacios/vmm.h +++ b/palacios/include/palacios/vmm.h @@ -59,7 +59,7 @@ int v3_get_vcore(struct guest_info *); extern struct v3_os_hooks * os_hooks; \ void * ptr = 0; \ if ((os_hooks) && (os_hooks)->allocate_pages) { \ - ptr = (os_hooks)->allocate_pages(num_pages,PAGE_SIZE_4KB,-1,0); \ + ptr = (os_hooks)->allocate_pages(num_pages,PAGE_SIZE_4KB,-1,0,0); \ } \ ptr; \ }) @@ -70,7 +70,7 @@ int v3_get_vcore(struct guest_info *); extern struct v3_os_hooks * os_hooks; \ void * ptr = 0; \ if ((os_hooks) && (os_hooks)->allocate_pages) { \ - ptr = (os_hooks)->allocate_pages(num_pages,align,-1,0); \ + ptr = (os_hooks)->allocate_pages(num_pages,align,-1,0,0); \ } \ ptr; \ }) @@ -81,17 +81,17 @@ int v3_get_vcore(struct guest_info *); extern struct v3_os_hooks * os_hooks; \ void * ptr = 0; \ if ((os_hooks) && (os_hooks)->allocate_pages) { \ - ptr = (os_hooks)->allocate_pages(num_pages, PAGE_SIZE_4KB, node_id,0); \ + ptr = (os_hooks)->allocate_pages(num_pages, PAGE_SIZE_4KB, node_id,0,0); \ } \ ptr; \ }) -#define V3_AllocPagesExtended(num_pages, align, node_id, constraints) \ +#define V3_AllocPagesExtended(num_pages, align, node_id, filter_func, filter_state) \ ({ \ extern struct v3_os_hooks * os_hooks; \ void * ptr = 0; \ if ((os_hooks) && (os_hooks)->allocate_pages) { \ - ptr = (os_hooks)->allocate_pages(num_pages, align, node_id,constraints); \ + ptr = (os_hooks)->allocate_pages(num_pages, align, node_id, filter_func, filter_state); \ } \ ptr; \ }) @@ -357,8 +357,9 @@ struct v3_os_hooks { // - node_id -1 => any node, otherwise the numa node we want to alloc from // - constraint = 0 => no constraints, otherwise a bitwise-or of the following flags // Allocates physically contiguous pages -#define V3_ALLOC_PAGES_CONSTRAINT_4GB 1 - void *(*allocate_pages)(int num_pages, unsigned int alignment, int node_id, int constraint); + // - with desired alignment + // - that the filter_func returns nonzero on (if filter_func is given) + void *(*allocate_pages)(int num_pages, unsigned int alignment, int node_id, int (*filter_func)(void *paddr, void *filter_state), void *filter_state); void (*free_pages)(void * page, int num_pages); // Allocates virtually contiguous memory diff --git a/palacios/src/palacios/mmu/vmm_shdw_pg_tlb.c b/palacios/src/palacios/mmu/vmm_shdw_pg_tlb.c index 9c5545c..d6f77d8 100644 --- a/palacios/src/palacios/mmu/vmm_shdw_pg_tlb.c +++ b/palacios/src/palacios/mmu/vmm_shdw_pg_tlb.c @@ -54,13 +54,6 @@ static struct shadow_page_data * create_new_shadow_pt(struct guest_info * core); #include "vmm_shdw_pg_tlb_32pae.h" #include "vmm_shdw_pg_tlb_64.h" -static inline int get_constraints(struct guest_info *core) -{ - // the current version of VTLB does not require any constraints - // on where page tables are allocated since it will use - // 32PAE page tables on a 64 bit machine even in 32 bit mode and below - return 0; -} static struct shadow_page_data * create_new_shadow_pt(struct guest_info * core) { @@ -98,7 +91,7 @@ static struct shadow_page_data * create_new_shadow_pt(struct guest_info * core) return NULL; } - page_tail->page_pa = (addr_t)V3_AllocPagesExtended(1,PAGE_SIZE_4KB,-1,get_constraints(core)); + page_tail->page_pa = (addr_t)V3_AllocPagesExtended(1,PAGE_SIZE_4KB,-1,0,0); if (!page_tail->page_pa) { PrintError(core->vm_info, core, "Cannot allocate page\n"); diff --git a/palacios/src/palacios/vmm.c b/palacios/src/palacios/vmm.c index f9e07df..b7f45cd 100644 --- a/palacios/src/palacios/vmm.c +++ b/palacios/src/palacios/vmm.c @@ -616,7 +616,7 @@ int v3_move_vm_mem(struct v3_vm_info * vm, void *gpa, int target_cpu) { new_hpa = V3_AllocPagesExtended(num_pages, PAGE_SIZE_4KB, new_node, - 0); // no constraints given new shadow pager impl + 0, 0); // no constraints given new shadow pager impl if (!new_hpa) { PrintError(vm, VCORE_NONE, "Cannot allocate memory for new base region...\n"); diff --git a/palacios/src/palacios/vmm_direct_paging.c b/palacios/src/palacios/vmm_direct_paging.c index 0458155..1175b25 100644 --- a/palacios/src/palacios/vmm_direct_paging.c +++ b/palacios/src/palacios/vmm_direct_paging.c @@ -161,7 +161,7 @@ static addr_t create_generic_pt_page(struct guest_info *core) { void * page = 0; void *temp; - temp = V3_AllocPagesExtended(1, PAGE_SIZE_4KB, -1, 0); // no constraints + temp = V3_AllocPagesExtended(1, PAGE_SIZE_4KB, -1, 0, 0); // no constraints if (!temp) { PrintError(VM_NONE, VCORE_NONE,"Cannot allocate page\n"); diff --git a/palacios/src/palacios/vmm_mem.c b/palacios/src/palacios/vmm_mem.c index aa71a8b..9cf6ea1 100644 --- a/palacios/src/palacios/vmm_mem.c +++ b/palacios/src/palacios/vmm_mem.c @@ -221,7 +221,7 @@ int v3_init_mem_map(struct v3_vm_info * vm) { region->host_addr = (addr_t)V3_AllocPagesExtended(block_pages, PAGE_SIZE_4KB, node_id, - 0); // no constraints + 0, 0); // no constraints if ((void *)region->host_addr == NULL) { PrintError(vm, VCORE_NONE, "Could not allocate guest memory\n");