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.


Handle oddball NUMA alloc/dealloc cases when kernel provides memory on undesired...
[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 (IS_ERR(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     /* Initially mark all minimum-sized blocks as allocated */
178     bitmap_zero(mp->tag_bits, mp->num_blocks);
179
180     palacios_spinlock_lock_irqsave(&(zone->lock), flags);
181     ret = insert_mempool(zone, mp);
182     palacios_spinlock_unlock_irqrestore(&(zone->lock), flags);
183
184     if (ret == -1) {
185         ERROR("Error: Could not insert mempool into zone\n");
186         palacios_free(mp->tag_bits);
187         palacios_free(mp);
188
189         return -1;
190     }
191
192     buddy_free(zone, base_addr, pool_order);
193
194     INFO("Added memory pool (addr=%p), order=%lu\n", (void *)base_addr, pool_order);
195
196     return 0;
197 }
198
199
200 /** 
201  * Removes a mempool from a zone, 
202  * assumes the zone lock is already held 
203  */
204 static int __buddy_remove_mempool(struct buddy_memzone * zone, 
205                                   unsigned long base_addr, 
206                                   unsigned char force,
207                                   void **user_metadata) 
208 {
209
210     struct buddy_mempool * pool = NULL;
211     struct block * block = NULL;
212
213
214     pool = find_mempool(zone, base_addr);
215
216     if (pool == NULL) {
217         ERROR("Could not find mempool with base address (%p)\n", (void *)base_addr);
218         return -1;
219     }
220
221     block = (struct block *)__va(pool->base_addr);
222
223     INFO("Removing Mempool %p, base=%p\n",pool,block);
224
225     // The largest order block in the memory pool must be free
226     if (!is_available(pool, block)) { 
227         if (!force) { 
228             ERROR("Trying to remove an in use memory pool\n");
229             *user_metadata=0;
230             return -1;
231         } else {
232             WARNING("Forcefully removing in use memory pool\n");
233         }
234     }
235
236     *user_metadata = pool->user_metadata;
237     
238     if (is_available(pool,block)) { 
239         list_del(&(block->link));
240     } else {
241         // we may not be on the free list if we are being
242         // forcibly removed before all allocations are freed
243     }
244         
245     rb_erase(&(pool->tree_node), &(zone->mempools));
246
247     palacios_free(pool->tag_bits);
248     palacios_free(pool);
249
250     zone->num_pools--;
251
252     return 0;
253 }
254
255 int buddy_remove_pool(struct buddy_memzone * zone,
256                       unsigned long base_addr, 
257                       unsigned char force,
258                       void          **user_metadata)
259 {
260     unsigned long flags = 0;
261     int ret = 0;
262
263
264     palacios_spinlock_lock_irqsave(&(zone->lock), flags);    
265     ret = __buddy_remove_mempool(zone, base_addr, force, user_metadata);
266     palacios_spinlock_unlock_irqrestore(&(zone->lock), flags);
267
268     return ret;
269 }
270
271
272
273
274
275 /**
276  * Allocates a block of memory of the requested size (2^order bytes).
277  *
278  * Arguments:
279  *       [IN] mp:    Buddy system memory allocator object.
280  *       [IN] order: Block size to allocate (2^order bytes).
281  *       [IN] constraints: bitmmask showing restrictions for scan. currently: 0=none, or LWK_BUDDY_CONSTRAINT_4GB
282  * Returns:
283  *       Success: Pointer to the start of the allocated memory block.
284  *       Failure: NULL
285  */
286 uintptr_t
287 buddy_alloc(struct buddy_memzone *zone, unsigned long order, int constraints)
288 {
289     unsigned long j;
290     struct buddy_mempool * mp = NULL;
291     struct list_head * list = NULL;
292     struct list_head * cur = NULL;
293     struct block * block = NULL;
294     struct block * buddy_block = NULL;
295     unsigned long flags = 0;
296
297     if (constraints && constraints!=LWK_BUDDY_CONSTRAINT_4GB) { 
298         ERROR("Do not know how to satisfy constraint mask 0x%x\n", constraints);
299         return (uintptr_t) NULL;
300     }
301
302     BUG_ON(zone == NULL);
303     BUG_ON(order > zone->max_order);
304
305     /* Fixup requested order to be at least the minimum supported */
306     if (order < zone->min_order) {
307         order = zone->min_order;
308     }
309
310     INFO("zone=%p, order=%lu\n", zone, order);
311
312     palacios_spinlock_lock_irqsave(&(zone->lock), flags);
313
314     for (j = order; j <= zone->max_order; j++) {
315
316         INFO("Order iter=%lu\n", j);
317
318         block=NULL;
319
320         list = &(zone->avail[j]);
321         
322         if (list_empty(list)) {
323             continue;
324         }
325
326         list_for_each(cur, list) {
327             block = list_entry(cur, struct block, link);
328
329             if (!constraints) {
330                 // without a constraint, we just want the first one
331                 break;
332             }
333             
334             if (constraints & LWK_BUDDY_CONSTRAINT_4GB) {
335                 // under this constraint, we will only use if the entirity
336                 // of the allocation within the block will be below 4 GB
337                 void *block_pa = (void*)__pa(block);
338                 if ((block_pa + (1ULL<<order)) <= (void*)(0x100000000ULL)) {
339                     // this block will work
340                     break;
341                 } else {
342                     // look for the next block
343                     block=NULL;
344                     continue;
345                 }
346             }
347         }
348         
349         if (!block) { 
350             // uh oh, no block, look to next order
351             continue;
352         }
353
354         // have appropriate block, will allocate
355
356         list_del(&(block->link));
357
358         mp = block->mp;
359
360         mark_allocated(mp, block);
361
362         INFO("pool=%p, block=%p, order=%lu, j=%lu\n", mp, block, order, j);
363
364         /* Trim if a higher order block than necessary was allocated */
365         while (j > order) {
366             --j;
367             buddy_block = (struct block *)((unsigned long)block + (1UL << j));
368             buddy_block->mp = mp;
369             buddy_block->order = j;
370             mark_available(mp, buddy_block);
371             list_add(&(buddy_block->link), &(zone->avail[j]));
372         }
373
374         mp->num_free_blocks -= (1UL << (order - zone->min_order));
375
376         palacios_spinlock_unlock_irqrestore(&(zone->lock), flags);
377
378         return __pa(block);
379     }
380
381     palacios_spinlock_unlock_irqrestore(&(zone->lock), flags);
382
383     return (uintptr_t)NULL;
384 }
385
386
387 /**
388  * Returns a block of memory to the buddy system memory allocator.
389  */
390 int
391 buddy_free(
392         //!    Buddy system memory allocator object.
393         struct buddy_memzone *  zone,
394         //!  Address of memory block to free.
395         uintptr_t addr,
396         //! Size of the memory block (2^order bytes).
397         unsigned long           order
398
399 {
400     struct block * block  = NULL;
401     struct buddy_mempool * pool = NULL;
402     unsigned long flags = 0;
403
404     BUG_ON(zone == NULL);
405     BUG_ON(order > zone->max_order);
406
407
408     if ((addr & ((1UL << zone->min_order) - 1)) != 0) {
409         ERROR("Attempting to free an invalid memory address (%p)\n", (void *)addr);
410         BUG_ON(1);
411     }
412
413
414     /* Fixup requested order to be at least the minimum supported */
415     if (order < zone->min_order) {
416         order = zone->min_order;
417     }
418
419
420     palacios_spinlock_lock_irqsave(&(zone->lock), flags);
421
422     pool = find_mempool(zone, addr);
423
424     if ((pool == NULL) || (order > pool->pool_order)) {
425         WARNING("Attempted to free an invalid page address (%p) - pool=%p order=%lu\n", (void *)addr,pool,order);
426         palacios_spinlock_unlock_irqrestore(&(zone->lock), flags);
427         return -1;
428     }
429
430
431     /* Overlay block structure on the memory block being freed */
432     block = (struct block *) __va(addr);
433     
434     if (is_available(pool, block)) {
435         ERROR("Error: Freeing an available block\n");
436         palacios_spinlock_unlock_irqrestore(&(zone->lock), flags);
437         return -1;
438     }
439
440     pool->num_free_blocks += (1UL << (order - zone->min_order));
441
442     /* Coalesce as much as possible with adjacent free buddy blocks */
443     while (order < pool->pool_order) {
444         /* Determine our buddy block's address */
445         struct block * buddy = find_buddy(pool, block, order);
446
447         /* Make sure buddy is available and has the same size as us */
448         if (!is_available(pool, buddy))
449             break;
450         if (is_available(pool, buddy) && (buddy->order != order))
451             break;
452
453         /* OK, we're good to go... buddy merge! */
454         list_del(&buddy->link);
455         if (buddy < block)
456             block = buddy;
457         ++order;
458         block->order = order;
459     }
460
461     /* Add the (possibly coalesced) block to the appropriate free list */
462     block->order = order;
463     block->mp = pool;
464     mark_available(pool, block);
465     list_add(&(block->link), &(zone->avail[order]));
466
467     palacios_spinlock_unlock_irqrestore(&(zone->lock), flags);
468
469     return 0;
470 }
471
472
473
474
475 /**
476  * Dumps the state of a buddy system memory allocator object to the console.
477  */
478 static int 
479 zone_mem_show(struct seq_file * s, void * v) {
480     struct buddy_memzone * zone = s->private;
481     unsigned long i;
482     unsigned long num_blocks;
483     struct list_head * entry = NULL;
484     unsigned long flags = 0;
485
486
487     if (!zone) {
488         seq_printf(s, "Null Zone Pointer!!\n");
489         return 0;
490     }
491
492     seq_printf(s, "DUMP OF BUDDY MEMORY ZONE:\n");
493     seq_printf(s, "  Zone Max Order=%lu, Min Order=%lu\n", 
494            zone->max_order, zone->min_order);
495
496     palacios_spinlock_lock_irqsave(&(zone->lock), flags);
497
498     for (i = zone->min_order; i <= zone->max_order; i++) {
499
500         /* Count the number of memory blocks in the list */
501         num_blocks = 0;
502         list_for_each(entry, &zone->avail[i]) {
503             ++num_blocks;
504         }
505
506         seq_printf(s, "  order %2lu: %lu free blocks\n", i, num_blocks);
507     }
508
509
510     seq_printf(s, " %lu memory pools\n", zone->num_pools);
511     // list pools in zone
512     {
513         struct rb_node * node = rb_first(&(zone->mempools));
514         struct buddy_mempool * pool = NULL;
515     
516         while (node) {
517             pool = rb_entry(node, struct buddy_mempool, tree_node);
518             
519             seq_printf(s, "    Base Addr=%p, order=%lu, size=%lu, free=%lu\n", 
520                        (void *)pool->base_addr, pool->pool_order, (1UL << pool->pool_order),
521                        pool->num_free_blocks << zone->min_order);
522
523
524             node = rb_next(node);
525         }
526     }
527
528     palacios_spinlock_unlock_irqrestore(&(zone->lock), flags);
529
530     return 0;
531 }
532
533
534 static int zone_proc_open(struct inode * inode, struct file * filp) {
535     struct proc_dir_entry * proc_entry = PDE(inode);
536     INFO("proc_entry at %p, data at %p\n", proc_entry, proc_entry->data);
537     return single_open(filp, zone_mem_show, proc_entry->data);
538 }
539
540
541 static struct file_operations zone_proc_ops = {
542     .owner = THIS_MODULE,
543     .open = zone_proc_open, 
544     .read = seq_read,
545     .llseek = seq_lseek, 
546     .release = single_release,
547 };
548
549
550 void buddy_deinit(struct buddy_memzone * zone, int (*free_callback)(void *user_metadata)) {
551     unsigned long flags;
552     struct rb_node *node;
553     struct buddy_mempool **pools;
554     unsigned long long base_addr;
555     void *meta;
556     int i;
557     unsigned long num_in_tree;
558
559     pools = (struct buddy_mempool **) palacios_alloc(sizeof(struct buddy_mempool *)*zone->num_pools);
560     if (!pools) { 
561         ERROR("Cannot allocate space for doing deinit of memory zone\n");
562         return ;
563     }
564     
565     // We will lock only to build up the memory pool list
566     // when we free memory, we need to be able to support free callbacks
567     // that could block.  This does leave a race with adds, allocs, and frees, however
568     // In Palacios, we expect a deinit will only really happen on the module unload
569     // so this should not present a problem
570     palacios_spinlock_lock_irqsave(&(zone->lock), flags);
571
572     // because it does not appear possible to erase while iterating
573     // over the rb tree, we do the following contorted mess
574     // get the pools 
575     for (num_in_tree=0, node=rb_first(&(zone->mempools));
576          node && num_in_tree<zone->num_pools;
577          node=rb_next(node), num_in_tree++) { 
578         
579         pools[num_in_tree]=rb_entry(node,struct buddy_mempool, tree_node);
580     }
581
582     palacios_spinlock_unlock_irqrestore(&(zone->lock), flags);
583
584     if (num_in_tree != zone->num_pools) { 
585         WARNING("Odd, the number of pools in the tree is %lu, but the zone reports %lu\n",
586                 num_in_tree, zone->num_pools);
587     }
588
589     // now we'll free the memory
590     // note that buddy_remove_mempool also removes them
591     // from the rb tree, and frees them
592     for (i=0;i<num_in_tree;i++) { 
593         base_addr = pools[i]->base_addr;
594         
595         if (buddy_remove_pool(zone, base_addr, 1, &meta)) {
596             WARNING("Cannot remove memory pool at %p during zone deinit...\n",(void*)(base_addr));
597             continue;
598         }
599         
600         // pool and node are now gone... 
601
602         // invoke the callback to free the actual memory, if any
603         if (free_callback) { 
604             free_callback(meta);
605         }
606     }
607
608
609     // get rid of /proc entry
610     {
611         char proc_file_name[128];
612
613         memset(proc_file_name, 0, 128);
614         snprintf(proc_file_name, 128, "v3-mem%d", zone->node_id);
615
616         remove_proc_entry(proc_file_name, palacios_get_procdir());
617     }
618
619
620     palacios_free(pools);
621     palacios_free(zone->avail);
622     palacios_free(zone);
623
624     return;
625 }
626
627
628
629 /**
630  * Initializes a buddy system memory allocator object.
631  *
632  * Arguments:
633  *       [IN] base_addr:  Base address of the memory pool.
634  *       [IN] pool_order: Size of the memory pool (2^pool_order bytes).
635  *       [IN] min_order:  Minimum allocatable block size (2^min_order bytes).
636  *
637  * Returns:
638  *       Success: Pointer to an initialized buddy system memory allocator.
639  *       Failure: NULL
640  *
641  * NOTE: The min_order argument is provided as an optimization. Since one tag
642  *       bit is required for each minimum-sized block, large memory pools that
643  *       allow order 0 allocations will use large amounts of memory. Specifying
644  *       a min_order of 5 (32 bytes), for example, reduces the number of tag
645  *       bits by 32x.
646  */
647 struct buddy_memzone *
648 buddy_init(
649         unsigned long max_order,
650         unsigned long min_order,
651         unsigned int node_id
652 )
653 {
654     struct buddy_memzone * zone = NULL;
655     unsigned long i;
656
657     DEBUG("Initializing Memory zone with up to %lu bit blocks on Node %d\n", max_order, node_id);
658
659
660     /* Smallest block size must be big enough to hold a block structure */
661     if ((1UL << min_order) < sizeof(struct block))
662         min_order = ilog2( roundup_pow_of_two(sizeof(struct block)) );
663
664     /* The minimum block order must be smaller than the pool order */
665     if (min_order > max_order)
666         return NULL;
667
668     zone = palacios_alloc_extended(sizeof(struct buddy_memzone), GFP_KERNEL, node_id);
669         
670     INFO("Allocated zone at %p\n", zone);
671
672     if (!zone) {
673         ERROR("Could not allocate memzone\n");
674         return NULL;
675     }
676
677     memset(zone, 0, sizeof(struct buddy_memzone));
678
679     zone->max_order = max_order;
680     zone->min_order  = min_order;
681     zone->node_id = node_id;
682
683     /* Allocate a list for every order up to the maximum allowed order */
684     zone->avail = palacios_alloc_extended((max_order + 1) * sizeof(struct list_head), GFP_KERNEL, zone->node_id);
685
686     if (!(zone->avail)) { 
687         ERROR("Unable to allocate space for zone list\n");
688         palacios_free(zone);
689         return NULL;
690     }
691
692     INFO("Allocated free lists at %p\n", zone->avail);
693
694     /* Initially all lists are empty */
695     for (i = 0; i <= max_order; i++) {
696         INIT_LIST_HEAD(&zone->avail[i]);
697     }
698
699
700     palacios_spinlock_init(&(zone->lock));
701
702     zone->mempools.rb_node = NULL;
703
704     INFO("Allocated zone at %p\n", zone);
705
706     {
707         struct proc_dir_entry * zone_entry = NULL;
708         char proc_file_name[128];
709
710         memset(proc_file_name, 0, 128);
711         snprintf(proc_file_name, 128, "v3-mem%u", zone->node_id);
712
713         zone_entry = create_proc_entry(proc_file_name, 0444, palacios_get_procdir());
714         if (zone_entry) {
715             zone_entry->proc_fops = &zone_proc_ops;
716             zone_entry->data = zone;
717             INFO("Successfully created /proc/v3vee/v3-mem%d\n", zone->node_id);
718         } else {
719             ERROR("Cannot create /proc/v3vee/v3-mem%d\n", zone->node_id);
720         }
721
722     }
723
724     return zone;
725 }