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
1 /* Copyright (c) 2007, Sandia National Laboratories */
2 /* Modified by Jack Lange, 2012 */
3
4 #include <linux/module.h>
5 #include <linux/slab.h>
6 #include <linux/log2.h>
7 #include "buddy.h"
8 #include "palacios.h"
9
10 #include <linux/proc_fs.h>
11 #include <linux/seq_file.h>
12
13
14 /**
15  * Converts a block address to its block index in the specified buddy allocator.
16  * A block's index is used to find the block's tag bit, mp->tag_bits[block_id].
17  */
18 static unsigned long
19 block_to_id(struct buddy_mempool *mp, struct block *block)
20 {
21     unsigned long block_id =
22         ((unsigned long)__pa(block) - mp->base_addr) >> mp->zone->min_order;
23     BUG_ON(block_id >= mp->num_blocks);
24     return block_id;
25 }
26
27
28 /**
29  * Marks a block as free by setting its tag bit to one.
30  */
31 static void
32 mark_available(struct buddy_mempool *mp, struct block *block)
33 {
34     __set_bit(block_to_id(mp, block), mp->tag_bits);
35 }
36
37
38 /**
39  * Marks a block as allocated by setting its tag bit to zero.
40  */
41 static void
42 mark_allocated(struct buddy_mempool *mp, struct block *block)
43 {
44     __clear_bit(block_to_id(mp, block), mp->tag_bits);
45 }
46
47
48 /**
49  * Returns true if block is free, false if it is allocated.
50  */
51 static int
52 is_available(struct buddy_mempool *mp, struct block *block)
53 {
54     return test_bit(block_to_id(mp, block), mp->tag_bits);
55 }
56
57
58 /**
59  * Returns the address of the block's buddy block.
60  */
61 static void *
62 find_buddy(struct buddy_mempool *mp, struct block *block, unsigned long order)
63 {
64     unsigned long _block;
65     unsigned long _buddy;
66
67     BUG_ON((unsigned long)__pa(block) < mp->base_addr);
68
69     /* Fixup block address to be zero-relative */
70     _block = (unsigned long)__pa(block) - mp->base_addr;
71
72     /* Calculate buddy in zero-relative space */
73     _buddy = _block ^ (1UL << order);
74
75     /* Return the buddy's address */
76     return (void *)(_buddy + __va(mp->base_addr));
77 }
78
79
80 static inline uintptr_t pool_end_addr(struct buddy_mempool * pool) {
81     return pool->base_addr + (1UL << pool->pool_order);
82 }
83
84
85 static struct buddy_mempool * 
86 find_mempool(struct buddy_memzone * zone, uintptr_t addr) {
87     struct rb_node * n = zone->mempools.rb_node;
88     struct buddy_mempool * pool = NULL;
89
90     while (n) {
91         pool = rb_entry(n, struct buddy_mempool, tree_node);
92
93         if (addr < pool->base_addr) {
94             n = n->rb_left;
95         } else if (addr >= pool_end_addr(pool)) {
96             n = n->rb_right;
97         } else {
98             return pool;
99         }
100     }
101
102     return NULL;
103 }
104
105
106
107 static int 
108 insert_mempool(struct buddy_memzone * zone, 
109                struct buddy_mempool * pool) {
110     struct rb_node ** p = &(zone->mempools.rb_node);
111     struct rb_node * parent = NULL;
112     struct buddy_mempool * tmp_pool;
113
114     while (*p) {
115         parent = *p;
116         tmp_pool = rb_entry(parent, struct buddy_mempool, tree_node);
117
118         if (pool_end_addr(pool) <= tmp_pool->base_addr) {
119             p = &(*p)->rb_left;
120         } else if (pool->base_addr >= pool_end_addr(tmp_pool)) {
121             p = &(*p)->rb_right;
122         } else {
123             return -1;
124         }
125     }
126
127     rb_link_node(&(pool->tree_node), parent, p);  
128     rb_insert_color(&(pool->tree_node), &(zone->mempools));
129     zone->num_pools++;
130
131     return 0;
132 }
133
134
135
136
137 /* This adds a pool of a given size to a buddy allocated zone
138  */
139
140 int buddy_add_pool(struct buddy_memzone * zone, 
141                    unsigned long base_addr, 
142                    unsigned long pool_order,
143                    void *user_metadata) {
144     struct buddy_mempool * mp = NULL;
145     unsigned long flags = 0;
146     int ret = 0;
147
148     if (pool_order > zone->max_order) {
149         ERROR("Pool order size is larger than max allowable zone size (pool_order=%lu) (max_order=%lu)\n", pool_order, zone->max_order);
150         return -1;
151     } else if (pool_order < zone->min_order) {
152         ERROR("Pool order is smaller than min allowable zone size (pool_order=%lu) (min_order=%lu)\n", pool_order, zone->min_order);
153         return -1;
154     }
155
156     mp = palacios_alloc_extended(sizeof(struct buddy_mempool), GFP_KERNEL, zone->node_id);
157
158     if (!mp) {
159         ERROR("Could not allocate mempool\n");
160         return -1;
161     }
162
163     mp->base_addr  = base_addr;
164     mp->pool_order = pool_order;
165     mp->zone = zone;
166     mp->num_free_blocks = 0;
167
168     mp->user_metadata = user_metadata;
169
170     /* Allocate a bitmap with 1 bit per minimum-sized block */
171     mp->num_blocks = (1UL << pool_order) / (1UL << zone->min_order);
172
173     mp->tag_bits   = palacios_alloc_extended(
174                                   BITS_TO_LONGS(mp->num_blocks) * sizeof(long), GFP_KERNEL, zone->node_id
175                                   );
176
177     if (!(mp->tag_bits)) { 
178         ERROR("Could not allocate tag_bits\n");
179         palacios_free(mp);
180         return -1;
181     }
182         
183
184     /* Initially mark all minimum-sized blocks as allocated */
185     bitmap_zero(mp->tag_bits, mp->num_blocks);
186
187     palacios_spinlock_lock_irqsave(&(zone->lock), flags);
188     ret = insert_mempool(zone, mp);
189     palacios_spinlock_unlock_irqrestore(&(zone->lock), flags);
190
191     if (ret == -1) {
192         ERROR("Error: Could not insert mempool into zone\n");
193         palacios_free(mp->tag_bits);
194         palacios_free(mp);
195
196         return -1;
197     }
198
199     buddy_free(zone, base_addr, pool_order);
200
201     INFO("Added memory pool (addr=%p), order=%lu\n", (void *)base_addr, pool_order);
202
203     return 0;
204 }
205
206
207 /** 
208  * Removes a mempool from a zone, 
209  * assumes the zone lock is already held 
210  */
211 static int __buddy_remove_mempool(struct buddy_memzone * zone, 
212                                   unsigned long base_addr, 
213                                   unsigned char force,
214                                   void **user_metadata) 
215 {
216
217     struct buddy_mempool * pool = NULL;
218     struct block * block = NULL;
219
220
221     pool = find_mempool(zone, base_addr);
222
223     if (pool == NULL) {
224         ERROR("Could not find mempool with base address (%p)\n", (void *)base_addr);
225         return -1;
226     }
227
228     block = (struct block *)__va(pool->base_addr);
229
230     INFO("Removing Mempool %p, base=%p\n",pool,block);
231
232     // The largest order block in the memory pool must be free
233     if (!is_available(pool, block)) { 
234         if (!force) { 
235             ERROR("Trying to remove an in use memory pool\n");
236             *user_metadata=0;
237             return -1;
238         } else {
239             WARNING("Forcefully removing in use memory pool\n");
240         }
241     }
242
243     *user_metadata = pool->user_metadata;
244     
245     if (is_available(pool,block)) { 
246         list_del(&(block->link));
247     } else {
248         // we may not be on the free list if we are being
249         // forcibly removed before all allocations are freed
250     }
251         
252     rb_erase(&(pool->tree_node), &(zone->mempools));
253
254     palacios_free(pool->tag_bits);
255     palacios_free(pool);
256
257     zone->num_pools--;
258
259     return 0;
260 }
261
262 int buddy_remove_pool(struct buddy_memzone * zone,
263                       unsigned long base_addr, 
264                       unsigned char force,
265                       void          **user_metadata)
266 {
267     unsigned long flags = 0;
268     int ret = 0;
269
270
271     palacios_spinlock_lock_irqsave(&(zone->lock), flags);    
272     ret = __buddy_remove_mempool(zone, base_addr, force, user_metadata);
273     palacios_spinlock_unlock_irqrestore(&(zone->lock), flags);
274
275     return ret;
276 }
277
278
279
280
281
282 /**
283  * Allocates a block of memory of the requested size (2^order bytes).
284  *
285  * Arguments:
286  *       [IN] mp:    Buddy system memory allocator object.
287  *       [IN] order: Block size to allocate (2^order bytes).
288  *       [IN] filter_func: returns nonzero if given paddr is OK to use
289  *       [IN] filter_state: opaque argument to filter_func
290  * Returns:
291  *       Success: Pointer to the start of the allocated memory block.
292  *       Failure: NULL
293  */
294 uintptr_t
295 buddy_alloc(struct buddy_memzone *zone, unsigned long order, int (*filter_func)(void *paddr, void *filter_state), void *filter_state)
296 {
297     unsigned long j;
298     struct buddy_mempool * mp = NULL;
299     struct list_head * list = NULL;
300     struct list_head * cur = NULL;
301     struct block * block = NULL;
302     struct block * buddy_block = NULL;
303     unsigned long flags = 0;
304
305     BUG_ON(zone == NULL);
306     BUG_ON(order > zone->max_order);
307
308     /* Fixup requested order to be at least the minimum supported */
309     if (order < zone->min_order) {
310         order = zone->min_order;
311     }
312
313     INFO("zone=%p, order=%lu\n", zone, order);
314
315     palacios_spinlock_lock_irqsave(&(zone->lock), flags);
316
317     for (j = order; j <= zone->max_order; j++) {
318
319         INFO("Order iter=%lu\n", j);
320
321         block=NULL;
322
323         list = &(zone->avail[j]);
324         
325         if (list_empty(list)) {
326             continue;
327         }
328
329         list_for_each(cur, list) {
330             block = list_entry(cur, struct block, link);
331
332             if (!filter_func) {
333                 // without a filter, we just want the first one
334                 break;
335             } else {
336
337                 void *block_pa = (void*)__pa(block);
338
339                 if (filter_func(block_pa,filter_state)) { 
340                     // this block will work
341                     break;
342                 } else {
343                     // this block won't work
344                     block=NULL;
345                     continue;
346                 }
347
348             }
349         }
350         
351         if (!block) { 
352             // uh oh, no block, look to next order
353             continue;
354         }
355
356         // have appropriate block, will allocate
357
358         list_del(&(block->link));
359
360         mp = block->mp;
361
362         mark_allocated(mp, block);
363
364         INFO("pool=%p, block=%p, order=%lu, j=%lu\n", mp, block, order, j);
365
366         /* Trim if a higher order block than necessary was allocated */
367         while (j > order) {
368             --j;
369             buddy_block = (struct block *)((unsigned long)block + (1UL << j));
370             buddy_block->mp = mp;
371             buddy_block->order = j;
372             mark_available(mp, buddy_block);
373             list_add(&(buddy_block->link), &(zone->avail[j]));
374         }
375
376         mp->num_free_blocks -= (1UL << (order - zone->min_order));
377
378         palacios_spinlock_unlock_irqrestore(&(zone->lock), flags);
379
380         return __pa(block);
381     }
382
383     palacios_spinlock_unlock_irqrestore(&(zone->lock), flags);
384
385     return (uintptr_t)NULL;
386 }
387
388
389 /**
390  * Returns a block of memory to the buddy system memory allocator.
391  */
392 int
393 buddy_free(
394         //!    Buddy system memory allocator object.
395         struct buddy_memzone *  zone,
396         //!  Address of memory block to free.
397         uintptr_t addr,
398         //! Size of the memory block (2^order bytes).
399         unsigned long           order
400
401 {
402     struct block * block  = NULL;
403     struct buddy_mempool * pool = NULL;
404     unsigned long flags = 0;
405
406     BUG_ON(zone == NULL);
407     BUG_ON(order > zone->max_order);
408
409
410     if ((addr & ((1UL << zone->min_order) - 1)) != 0) {
411         ERROR("Attempting to free an invalid memory address (%p)\n", (void *)addr);
412         BUG_ON(1);
413     }
414
415
416     /* Fixup requested order to be at least the minimum supported */
417     if (order < zone->min_order) {
418         order = zone->min_order;
419     }
420
421
422     palacios_spinlock_lock_irqsave(&(zone->lock), flags);
423
424     pool = find_mempool(zone, addr);
425
426     if ((pool == NULL) || (order > pool->pool_order)) {
427         WARNING("Attempted to free an invalid page address (%p) - pool=%p order=%lu\n", (void *)addr,pool,order);
428         palacios_spinlock_unlock_irqrestore(&(zone->lock), flags);
429         return -1;
430     }
431
432
433     /* Overlay block structure on the memory block being freed */
434     block = (struct block *) __va(addr);
435     
436     if (is_available(pool, block)) {
437         ERROR("Error: Freeing an available block\n");
438         palacios_spinlock_unlock_irqrestore(&(zone->lock), flags);
439         return -1;
440     }
441
442     pool->num_free_blocks += (1UL << (order - zone->min_order));
443
444     /* Coalesce as much as possible with adjacent free buddy blocks */
445     while (order < pool->pool_order) {
446         /* Determine our buddy block's address */
447         struct block * buddy = find_buddy(pool, block, order);
448
449         /* Make sure buddy is available and has the same size as us */
450         if (!is_available(pool, buddy))
451             break;
452         if (is_available(pool, buddy) && (buddy->order != order))
453             break;
454
455         /* OK, we're good to go... buddy merge! */
456         list_del(&buddy->link);
457         if (buddy < block)
458             block = buddy;
459         ++order;
460         block->order = order;
461     }
462
463     /* Add the (possibly coalesced) block to the appropriate free list */
464     block->order = order;
465     block->mp = pool;
466     mark_available(pool, block);
467     list_add(&(block->link), &(zone->avail[order]));
468
469     palacios_spinlock_unlock_irqrestore(&(zone->lock), flags);
470
471     return 0;
472 }
473
474
475
476
477 /**
478  * Dumps the state of a buddy system memory allocator object to the console.
479  */
480 static int 
481 zone_mem_show(struct seq_file * s, void * v) {
482     struct buddy_memzone * zone = s->private;
483     unsigned long i;
484     unsigned long num_blocks;
485     struct list_head * entry = NULL;
486     unsigned long flags = 0;
487
488
489     if (!zone) {
490         seq_printf(s, "Null Zone Pointer!!\n");
491         return 0;
492     }
493
494     seq_printf(s, "DUMP OF BUDDY MEMORY ZONE:\n");
495     seq_printf(s, "  Zone Max Order=%lu, Min Order=%lu\n", 
496            zone->max_order, zone->min_order);
497
498     palacios_spinlock_lock_irqsave(&(zone->lock), flags);
499
500     for (i = zone->min_order; i <= zone->max_order; i++) {
501
502         /* Count the number of memory blocks in the list */
503         num_blocks = 0;
504         list_for_each(entry, &zone->avail[i]) {
505             ++num_blocks;
506         }
507
508         seq_printf(s, "  order %2lu: %lu free blocks\n", i, num_blocks);
509     }
510
511
512     seq_printf(s, " %lu memory pools\n", zone->num_pools);
513     // list pools in zone
514     {
515         struct rb_node * node = rb_first(&(zone->mempools));
516         struct buddy_mempool * pool = NULL;
517     
518         while (node) {
519             pool = rb_entry(node, struct buddy_mempool, tree_node);
520             
521             seq_printf(s, "    Base Addr=%p, order=%lu, size=%lu, free=%lu\n", 
522                        (void *)pool->base_addr, pool->pool_order, (1UL << pool->pool_order),
523                        pool->num_free_blocks << zone->min_order);
524
525
526             node = rb_next(node);
527         }
528     }
529
530     palacios_spinlock_unlock_irqrestore(&(zone->lock), flags);
531
532     return 0;
533 }
534
535
536 static int zone_proc_open(struct inode * inode, struct file * filp) {
537     struct proc_dir_entry * proc_entry = PAL_PDE(inode);
538     INFO("proc_entry at %p, data at %p\n", proc_entry, PAL_PROC_GETDATA(inode));
539     return single_open(filp, zone_mem_show, PAL_PROC_GETDATA(inode));
540 }
541
542
543 static struct file_operations zone_proc_ops = {
544     .owner = THIS_MODULE,
545     .open = zone_proc_open, 
546     .read = seq_read,
547     .llseek = seq_lseek, 
548     .release = single_release,
549 };
550
551
552 void buddy_deinit(struct buddy_memzone * zone, int (*free_callback)(void *user_metadata)) {
553     unsigned long flags;
554     struct rb_node *node;
555     struct buddy_mempool **pools;
556     unsigned long long base_addr;
557     void *meta;
558     int i;
559     unsigned long num_in_tree;
560
561     pools = (struct buddy_mempool **) palacios_alloc(sizeof(struct buddy_mempool *)*zone->num_pools);
562     if (!pools) { 
563         ERROR("Cannot allocate space for doing deinit of memory zone\n");
564         return ;
565     }
566     
567     // We will lock only to build up the memory pool list
568     // when we free memory, we need to be able to support free callbacks
569     // that could block.  This does leave a race with adds, allocs, and frees, however
570     // In Palacios, we expect a deinit will only really happen on the module unload
571     // so this should not present a problem
572     palacios_spinlock_lock_irqsave(&(zone->lock), flags);
573
574     // because it does not appear possible to erase while iterating
575     // over the rb tree, we do the following contorted mess
576     // get the pools 
577     for (num_in_tree=0, node=rb_first(&(zone->mempools));
578          node && num_in_tree<zone->num_pools;
579          node=rb_next(node), num_in_tree++) { 
580         
581         pools[num_in_tree]=rb_entry(node,struct buddy_mempool, tree_node);
582     }
583
584     palacios_spinlock_unlock_irqrestore(&(zone->lock), flags);
585
586     if (num_in_tree != zone->num_pools) { 
587         WARNING("Odd, the number of pools in the tree is %lu, but the zone reports %lu\n",
588                 num_in_tree, zone->num_pools);
589     }
590
591     // now we'll free the memory
592     // note that buddy_remove_mempool also removes them
593     // from the rb tree, and frees them
594     for (i=0;i<num_in_tree;i++) { 
595         base_addr = pools[i]->base_addr;
596         
597         if (buddy_remove_pool(zone, base_addr, 1, &meta)) {
598             WARNING("Cannot remove memory pool at %p during zone deinit...\n",(void*)(base_addr));
599             continue;
600         }
601         
602         // pool and node are now gone... 
603
604         // invoke the callback to free the actual memory, if any
605         if (free_callback) { 
606             free_callback(meta);
607         }
608     }
609
610
611     // get rid of /proc entry
612     {
613         char proc_file_name[128];
614
615         memset(proc_file_name, 0, 128);
616         snprintf(proc_file_name, 128, "v3-mem%u", zone->node_id);
617
618         remove_proc_entry(proc_file_name, palacios_get_procdir());
619     }
620
621
622     palacios_free(pools);
623     palacios_free(zone->avail);
624     palacios_free(zone);
625
626     return;
627 }
628
629
630
631 /**
632  * Initializes a buddy system memory allocator object.
633  *
634  * Arguments:
635  *       [IN] base_addr:  Base address of the memory pool.
636  *       [IN] pool_order: Size of the memory pool (2^pool_order bytes).
637  *       [IN] min_order:  Minimum allocatable block size (2^min_order bytes).
638  *
639  * Returns:
640  *       Success: Pointer to an initialized buddy system memory allocator.
641  *       Failure: NULL
642  *
643  * NOTE: The min_order argument is provided as an optimization. Since one tag
644  *       bit is required for each minimum-sized block, large memory pools that
645  *       allow order 0 allocations will use large amounts of memory. Specifying
646  *       a min_order of 5 (32 bytes), for example, reduces the number of tag
647  *       bits by 32x.
648  */
649 struct buddy_memzone *
650 buddy_init(
651         unsigned long max_order,
652         unsigned long min_order,
653         unsigned int node_id
654 )
655 {
656     struct buddy_memzone * zone = NULL;
657     unsigned long i;
658         struct proc_dir_entry * zone_entry = NULL;
659         char proc_file_name[128];
660
661     DEBUG("Initializing Memory zone with up to %lu bit blocks on Node %d\n", max_order, node_id);
662
663
664     /* Smallest block size must be big enough to hold a block structure */
665     if ((1UL << min_order) < sizeof(struct block))
666         min_order = ilog2( roundup_pow_of_two(sizeof(struct block)) );
667
668     /* The minimum block order must be smaller than the pool order */
669     if (min_order > max_order)
670         return NULL;
671
672     zone = palacios_alloc_extended(sizeof(struct buddy_memzone), GFP_KERNEL, node_id);
673         
674     INFO("Allocated zone at %p\n", zone);
675
676     if (!zone) {
677         ERROR("Could not allocate memzone\n");
678         return NULL;
679     }
680
681     memset(zone, 0, sizeof(struct buddy_memzone));
682
683     zone->max_order = max_order;
684     zone->min_order  = min_order;
685     zone->node_id = node_id;
686
687     /* Allocate a list for every order up to the maximum allowed order */
688     zone->avail = palacios_alloc_extended((max_order + 1) * sizeof(struct list_head), GFP_KERNEL, zone->node_id);
689
690     if (!(zone->avail)) { 
691         ERROR("Unable to allocate space for zone list\n");
692         palacios_free(zone);
693         return NULL;
694     }
695
696     INFO("Allocated free lists at %p\n", zone->avail);
697
698     /* Initially all lists are empty */
699     for (i = 0; i <= max_order; i++) {
700         INIT_LIST_HEAD(&zone->avail[i]);
701     }
702
703
704     palacios_spinlock_init(&(zone->lock));
705
706     zone->mempools.rb_node = NULL;
707
708     INFO("Allocated zone at %p\n", zone);
709
710
711         memset(proc_file_name, 0, 128);
712         snprintf(proc_file_name, 128, "v3-mem%u", zone->node_id);
713
714     PAL_PROC_CREATE_DATA(zone_entry, proc_file_name, 0444, palacios_get_procdir(), &zone_proc_ops, zone);
715     if (zone_entry) {
716             INFO("Successfully created /proc/v3vee/v3-mem%d\n", zone->node_id);
717         } else {
718             ERROR("Cannot create /proc/v3vee/v3-mem%d\n", zone->node_id);
719         }
720
721
722     return zone;
723 }