X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=blobdiff_plain;f=linux_module%2Fbuddy.c;h=ed692c8ef4730851eb48192ca0d468362a3ba8de;hb=a8686374c6aa74d805b32e7675f42f7ab9a0b348;hp=f7c91cba7ee3159c198a50258cb0d64fbc9ee2c5;hpb=82071a7f5f0b18fbf1a4adc2a37fed1624572a79;p=palacios.git diff --git a/linux_module/buddy.c b/linux_module/buddy.c index f7c91cb..ed692c8 100644 --- a/linux_module/buddy.c +++ b/linux_module/buddy.c @@ -155,7 +155,7 @@ int buddy_add_pool(struct buddy_memzone * zone, mp = palacios_alloc_extended(sizeof(struct buddy_mempool), GFP_KERNEL, zone->node_id); - if (IS_ERR(mp)) { + if (!mp) { ERROR("Could not allocate mempool\n"); return -1; } @@ -174,6 +174,13 @@ int buddy_add_pool(struct buddy_memzone * zone, BITS_TO_LONGS(mp->num_blocks) * sizeof(long), GFP_KERNEL, zone->node_id ); + if (!(mp->tag_bits)) { + ERROR("Could not allocate tag_bits\n"); + palacios_free(mp); + return -1; + } + + /* Initially mark all minimum-sized blocks as allocated */ bitmap_zero(mp->tag_bits, mp->num_blocks); @@ -210,6 +217,7 @@ static int __buddy_remove_mempool(struct buddy_memzone * zone, struct buddy_mempool * pool = NULL; struct block * block = NULL; + pool = find_mempool(zone, base_addr); if (pool == NULL) { @@ -217,16 +225,30 @@ static int __buddy_remove_mempool(struct buddy_memzone * zone, return -1; } - if (!bitmap_empty(pool->tag_bits, pool->num_blocks)) { - ERROR("Trying to remove an in use memory pool\n"); - return -1; + block = (struct block *)__va(pool->base_addr); + + INFO("Removing Mempool %p, base=%p\n",pool,block); + + // The largest order block in the memory pool must be free + if (!is_available(pool, block)) { + if (!force) { + ERROR("Trying to remove an in use memory pool\n"); + *user_metadata=0; + return -1; + } else { + WARNING("Forcefully removing in use memory pool\n"); + } } *user_metadata = pool->user_metadata; - block = (struct block *)__va(pool->base_addr); - - list_del(&(block->link)); + if (is_available(pool,block)) { + list_del(&(block->link)); + } else { + // we may not be on the free list if we are being + // forcibly removed before all allocations are freed + } + rb_erase(&(pool->tree_node), &(zone->mempools)); palacios_free(pool->tag_bits); @@ -245,6 +267,7 @@ int buddy_remove_pool(struct buddy_memzone * zone, unsigned long flags = 0; int ret = 0; + palacios_spinlock_lock_irqsave(&(zone->lock), flags); ret = __buddy_remove_mempool(zone, base_addr, force, user_metadata); palacios_spinlock_unlock_irqrestore(&(zone->lock), flags); @@ -255,19 +278,21 @@ int buddy_remove_pool(struct buddy_memzone * zone, + /** * Allocates a block of memory of the requested size (2^order bytes). * * 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; @@ -277,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); @@ -309,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< pool->pool_order)) { - WARNING("Attempted to free an invalid page address (%p)\n", (void *)addr); + WARNING("Attempted to free an invalid page address (%p) - pool=%p order=%lu\n", (void *)addr,pool,order); palacios_spinlock_unlock_irqrestore(&(zone->lock), flags); - return; + return -1; } @@ -417,7 +436,7 @@ buddy_free( if (is_available(pool, block)) { ERROR("Error: Freeing an available block\n"); palacios_spinlock_unlock_irqrestore(&(zone->lock), flags); - return; + return -1; } pool->num_free_blocks += (1UL << (order - zone->min_order)); @@ -448,6 +467,8 @@ buddy_free( list_add(&(block->link), &(zone->avail[order])); palacios_spinlock_unlock_irqrestore(&(zone->lock), flags); + + return 0; } @@ -513,9 +534,9 @@ zone_mem_show(struct seq_file * s, void * v) { static int zone_proc_open(struct inode * inode, struct file * filp) { - struct proc_dir_entry * proc_entry = PDE(inode); - INFO("proc_entry at %p, data at %p\n", proc_entry, proc_entry->data); - return single_open(filp, zone_mem_show, proc_entry->data); + struct proc_dir_entry * proc_entry = PAL_PDE(inode); + INFO("proc_entry at %p, data at %p\n", proc_entry, PAL_PROC_GETDATA(inode)); + return single_open(filp, zone_mem_show, PAL_PROC_GETDATA(inode)); } @@ -528,26 +549,77 @@ static struct file_operations zone_proc_ops = { }; -void buddy_deinit(struct buddy_memzone * zone) { +void buddy_deinit(struct buddy_memzone * zone, int (*free_callback)(void *user_metadata)) { unsigned long flags; - + struct rb_node *node; + struct buddy_mempool **pools; + unsigned long long base_addr; + void *meta; + int i; + unsigned long num_in_tree; + + pools = (struct buddy_mempool **) palacios_alloc(sizeof(struct buddy_mempool *)*zone->num_pools); + if (!pools) { + ERROR("Cannot allocate space for doing deinit of memory zone\n"); + return ; + } + + // We will lock only to build up the memory pool list + // when we free memory, we need to be able to support free callbacks + // that could block. This does leave a race with adds, allocs, and frees, however + // In Palacios, we expect a deinit will only really happen on the module unload + // so this should not present a problem palacios_spinlock_lock_irqsave(&(zone->lock), flags); - // for each pool, free it -#warning We really need to free the memory pools here + // because it does not appear possible to erase while iterating + // over the rb tree, we do the following contorted mess + // get the pools + for (num_in_tree=0, node=rb_first(&(zone->mempools)); + node && num_in_treenum_pools; + node=rb_next(node), num_in_tree++) { + + pools[num_in_tree]=rb_entry(node,struct buddy_mempool, tree_node); + } palacios_spinlock_unlock_irqrestore(&(zone->lock), flags); - + + if (num_in_tree != zone->num_pools) { + WARNING("Odd, the number of pools in the tree is %lu, but the zone reports %lu\n", + num_in_tree, zone->num_pools); + } + + // now we'll free the memory + // note that buddy_remove_mempool also removes them + // from the rb tree, and frees them + for (i=0;ibase_addr; + + if (buddy_remove_pool(zone, base_addr, 1, &meta)) { + WARNING("Cannot remove memory pool at %p during zone deinit...\n",(void*)(base_addr)); + continue; + } + + // pool and node are now gone... + + // invoke the callback to free the actual memory, if any + if (free_callback) { + free_callback(meta); + } + } + + + // get rid of /proc entry { char proc_file_name[128]; memset(proc_file_name, 0, 128); - snprintf(proc_file_name, 128, "v3-mem%d", zone->node_id); + snprintf(proc_file_name, 128, "v3-mem%u", zone->node_id); remove_proc_entry(proc_file_name, palacios_get_procdir()); } + palacios_free(pools); palacios_free(zone->avail); palacios_free(zone); @@ -583,6 +655,8 @@ buddy_init( { struct buddy_memzone * zone = NULL; unsigned long i; + struct proc_dir_entry * zone_entry = NULL; + char proc_file_name[128]; DEBUG("Initializing Memory zone with up to %lu bit blocks on Node %d\n", max_order, node_id); @@ -633,23 +707,17 @@ buddy_init( INFO("Allocated zone at %p\n", zone); - { - struct proc_dir_entry * zone_entry = NULL; - char proc_file_name[128]; memset(proc_file_name, 0, 128); snprintf(proc_file_name, 128, "v3-mem%u", zone->node_id); - zone_entry = create_proc_entry(proc_file_name, 0444, palacios_get_procdir()); - if (zone_entry) { - zone_entry->proc_fops = &zone_proc_ops; - zone_entry->data = zone; + PAL_PROC_CREATE_DATA(zone_entry, proc_file_name, 0444, palacios_get_procdir(), &zone_proc_ops, zone); + if (zone_entry) { INFO("Successfully created /proc/v3vee/v3-mem%d\n", zone->node_id); } else { ERROR("Cannot create /proc/v3vee/v3-mem%d\n", zone->node_id); } - } return zone; }