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;
}
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);
struct buddy_mempool * pool = NULL;
struct block * block = NULL;
+
pool = find_mempool(zone, base_addr);
if (pool == NULL) {
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);
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);
+
/**
* 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;
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);
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<<order)) <= (void*)(0x100000000ULL)) {
+
+ if (filter_func(block_pa,filter_state)) {
// this block will work
break;
} else {
- // look for the next block
+ // this block won't work
block=NULL;
continue;
}
+
}
}
/**
* Returns a block of memory to the buddy system memory allocator.
*/
-void
+int
buddy_free(
//! Buddy system memory allocator object.
struct buddy_memzone * zone,
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;
}
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));
list_add(&(block->link), &(zone->avail[order]));
palacios_spinlock_unlock_irqrestore(&(zone->lock), flags);
+
+ return 0;
}
};
-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_tree<zone->num_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;i<num_in_tree;i++) {
+ base_addr = pools[i]->base_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];
}
+ palacios_free(pools);
palacios_free(zone->avail);
palacios_free(zone);