X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=blobdiff_plain;f=linux_module%2Fbuddy.c;h=ed692c8ef4730851eb48192ca0d468362a3ba8de;hb=a8686374c6aa74d805b32e7675f42f7ab9a0b348;hp=548c7ff45d4f509d87a5e83dadc50e11f53c36bf;hpb=84c84a909e8c3374e2cd7768ef4240ca9d73222f;p=palacios.git diff --git a/linux_module/buddy.c b/linux_module/buddy.c index 548c7ff..ed692c8 100644 --- a/linux_module/buddy.c +++ b/linux_module/buddy.c @@ -153,9 +153,9 @@ int buddy_add_pool(struct buddy_memzone * zone, return -1; } - mp = palacios_alloc_node_extended(sizeof(struct buddy_mempool), GFP_KERNEL, zone->node_id); + 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; } @@ -170,10 +170,17 @@ int buddy_add_pool(struct buddy_memzone * zone, /* Allocate a bitmap with 1 bit per minimum-sized block */ mp->num_blocks = (1UL << pool_order) / (1UL << zone->min_order); - mp->tag_bits = palacios_alloc_node_extended( + mp->tag_bits = palacios_alloc_extended( 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,23 +278,26 @@ 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] 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) +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; struct list_head * list = NULL; + struct list_head * cur = NULL; struct block * block = NULL; struct block * buddy_block = NULL; unsigned long flags = 0; @@ -292,13 +318,43 @@ buddy_alloc(struct buddy_memzone *zone, unsigned long order) INFO("Order iter=%lu\n", j); - /* Try to allocate the first block in the order j list */ - list = &zone->avail[j]; + block=NULL; - if (list_empty(list)) + list = &(zone->avail[j]); + + if (list_empty(list)) { continue; + } + + list_for_each(cur, list) { + block = list_entry(cur, struct block, link); + + if (!filter_func) { + // without a filter, we just want the first one + break; + } else { + + void *block_pa = (void*)__pa(block); + + if (filter_func(block_pa,filter_state)) { + // this block will work + break; + } else { + // this block won't work + block=NULL; + continue; + } + + } + } + + if (!block) { + // uh oh, no block, look to next order + continue; + } + + // have appropriate block, will allocate - block = list_entry(list->next, struct block, link); list_del(&(block->link)); mp = block->mp; @@ -307,11 +363,6 @@ buddy_alloc(struct buddy_memzone *zone, unsigned long order) INFO("pool=%p, block=%p, order=%lu, j=%lu\n", mp, block, order, j); - /* - palacios_spinlock_unlock_irqrestore(&(zone->lock), flags); - return 0; - */ - /* Trim if a higher order block than necessary was allocated */ while (j > order) { --j; @@ -338,7 +389,7 @@ buddy_alloc(struct buddy_memzone *zone, unsigned long order) /** * Returns a block of memory to the buddy system memory allocator. */ -void +int buddy_free( //! Buddy system memory allocator object. struct buddy_memzone * zone, @@ -373,9 +424,9 @@ buddy_free( pool = find_mempool(zone, addr); if ((pool == NULL) || (order > 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; } @@ -385,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)); @@ -416,6 +467,8 @@ buddy_free( list_add(&(block->link), &(zone->avail[order])); palacios_spinlock_unlock_irqrestore(&(zone->lock), flags); + + return 0; } @@ -481,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)); } @@ -496,28 +549,77 @@ static struct file_operations zone_proc_ops = { }; -extern struct proc_dir_entry * palacios_proc_dir; - -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_proc_dir); + remove_proc_entry(proc_file_name, palacios_get_procdir()); } + palacios_free(pools); palacios_free(zone->avail); palacios_free(zone); @@ -553,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); @@ -565,11 +669,11 @@ buddy_init( if (min_order > max_order) return NULL; - zone = palacios_alloc_node_extended(sizeof(struct buddy_memzone), GFP_KERNEL, node_id); + zone = palacios_alloc_extended(sizeof(struct buddy_memzone), GFP_KERNEL, node_id); INFO("Allocated zone at %p\n", zone); - if (IS_ERR(zone)) { + if (!zone) { ERROR("Could not allocate memzone\n"); return NULL; } @@ -581,7 +685,13 @@ buddy_init( zone->node_id = node_id; /* Allocate a list for every order up to the maximum allowed order */ - zone->avail = palacios_alloc_node_extended((max_order + 1) * sizeof(struct list_head), GFP_KERNEL, zone->node_id); + zone->avail = palacios_alloc_extended((max_order + 1) * sizeof(struct list_head), GFP_KERNEL, zone->node_id); + + if (!(zone->avail)) { + ERROR("Unable to allocate space for zone list\n"); + palacios_free(zone); + return NULL; + } INFO("Allocated free lists at %p\n", zone->avail); @@ -597,22 +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%d", zone->node_id); + snprintf(proc_file_name, 128, "v3-mem%u", zone->node_id); - zone_entry = create_proc_entry(proc_file_name, 0444, palacios_proc_dir); - 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("Error creating memory zone proc file\n"); + ERROR("Cannot create /proc/v3vee/v3-mem%d\n", zone->node_id); } - } return zone; }