Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Linux compatibility fixes
[palacios.git] / linux_module / buddy.c
index 548c7ff..ed692c8 100644 (file)
@@ -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_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];
 
        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;
 }