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.


Clean up hashtable frees to fix rmmod crash on redhat
[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 void
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;
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;
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
470
471
472
473 /**
474  * Dumps the state of a buddy system memory allocator object to the console.
475  */
476 static int 
477 zone_mem_show(struct seq_file * s, void * v) {
478     struct buddy_memzone * zone = s->private;
479     unsigned long i;
480     unsigned long num_blocks;
481     struct list_head * entry = NULL;
482     unsigned long flags = 0;
483
484
485     if (!zone) {
486         seq_printf(s, "Null Zone Pointer!!\n");
487         return 0;
488     }
489
490     seq_printf(s, "DUMP OF BUDDY MEMORY ZONE:\n");
491     seq_printf(s, "  Zone Max Order=%lu, Min Order=%lu\n", 
492            zone->max_order, zone->min_order);
493
494     palacios_spinlock_lock_irqsave(&(zone->lock), flags);
495
496     for (i = zone->min_order; i <= zone->max_order; i++) {
497
498         /* Count the number of memory blocks in the list */
499         num_blocks = 0;
500         list_for_each(entry, &zone->avail[i]) {
501             ++num_blocks;
502         }
503
504         seq_printf(s, "  order %2lu: %lu free blocks\n", i, num_blocks);
505     }
506
507
508     seq_printf(s, " %lu memory pools\n", zone->num_pools);
509     // list pools in zone
510     {
511         struct rb_node * node = rb_first(&(zone->mempools));
512         struct buddy_mempool * pool = NULL;
513     
514         while (node) {
515             pool = rb_entry(node, struct buddy_mempool, tree_node);
516             
517             seq_printf(s, "    Base Addr=%p, order=%lu, size=%lu, free=%lu\n", 
518                        (void *)pool->base_addr, pool->pool_order, (1UL << pool->pool_order),
519                        pool->num_free_blocks << zone->min_order);
520
521
522             node = rb_next(node);
523         }
524     }
525
526     palacios_spinlock_unlock_irqrestore(&(zone->lock), flags);
527
528     return 0;
529 }
530
531
532 static int zone_proc_open(struct inode * inode, struct file * filp) {
533     struct proc_dir_entry * proc_entry = PDE(inode);
534     INFO("proc_entry at %p, data at %p\n", proc_entry, proc_entry->data);
535     return single_open(filp, zone_mem_show, proc_entry->data);
536 }
537
538
539 static struct file_operations zone_proc_ops = {
540     .owner = THIS_MODULE,
541     .open = zone_proc_open, 
542     .read = seq_read,
543     .llseek = seq_lseek, 
544     .release = single_release,
545 };
546
547
548 void buddy_deinit(struct buddy_memzone * zone, int (*free_callback)(void *user_metadata)) {
549     unsigned long flags;
550     struct rb_node *node;
551     struct buddy_mempool **pools;
552     unsigned long long base_addr;
553     void *meta;
554     int i;
555     unsigned long num_in_tree;
556
557     pools = (struct buddy_mempool **) palacios_alloc(sizeof(struct buddy_mempool *)*zone->num_pools);
558     if (!pools) { 
559         ERROR("Cannot allocate space for doing deinit of memory zone\n");
560         return ;
561     }
562     
563     // We will lock only to build up the memory pool list
564     // when we free memory, we need to be able to support free callbacks
565     // that could block.  This does leave a race with adds, allocs, and frees, however
566     // In Palacios, we expect a deinit will only really happen on the module unload
567     // so this should not present a problem
568     palacios_spinlock_lock_irqsave(&(zone->lock), flags);
569
570     // because it does not appear possible to erase while iterating
571     // over the rb tree, we do the following contorted mess
572     // get the pools 
573     for (num_in_tree=0, node=rb_first(&(zone->mempools));
574          node && num_in_tree<zone->num_pools;
575          node=rb_next(node), num_in_tree++) { 
576         
577         pools[num_in_tree]=rb_entry(node,struct buddy_mempool, tree_node);
578     }
579
580     palacios_spinlock_unlock_irqrestore(&(zone->lock), flags);
581
582     if (num_in_tree != zone->num_pools) { 
583         WARNING("Odd, the number of pools in the tree is %lu, but the zone reports %lu\n",
584                 num_in_tree, zone->num_pools);
585     }
586
587     // now we'll free the memory
588     // note that buddy_remove_mempool also removes them
589     // from the rb tree, and frees them
590     for (i=0;i<num_in_tree;i++) { 
591         base_addr = pools[i]->base_addr;
592         
593         if (buddy_remove_pool(zone, base_addr, 1, &meta)) {
594             WARNING("Cannot remove memory pool at %p during zone deinit...\n",(void*)(base_addr));
595             continue;
596         }
597         
598         // pool and node are now gone... 
599
600         // invoke the callback to free the actual memory, if any
601         if (free_callback) { 
602             free_callback(meta);
603         }
604     }
605
606
607     // get rid of /proc entry
608     {
609         char proc_file_name[128];
610
611         memset(proc_file_name, 0, 128);
612         snprintf(proc_file_name, 128, "v3-mem%d", zone->node_id);
613
614         remove_proc_entry(proc_file_name, palacios_get_procdir());
615     }
616
617
618     palacios_free(pools);
619     palacios_free(zone->avail);
620     palacios_free(zone);
621
622     return;
623 }
624
625
626
627 /**
628  * Initializes a buddy system memory allocator object.
629  *
630  * Arguments:
631  *       [IN] base_addr:  Base address of the memory pool.
632  *       [IN] pool_order: Size of the memory pool (2^pool_order bytes).
633  *       [IN] min_order:  Minimum allocatable block size (2^min_order bytes).
634  *
635  * Returns:
636  *       Success: Pointer to an initialized buddy system memory allocator.
637  *       Failure: NULL
638  *
639  * NOTE: The min_order argument is provided as an optimization. Since one tag
640  *       bit is required for each minimum-sized block, large memory pools that
641  *       allow order 0 allocations will use large amounts of memory. Specifying
642  *       a min_order of 5 (32 bytes), for example, reduces the number of tag
643  *       bits by 32x.
644  */
645 struct buddy_memzone *
646 buddy_init(
647         unsigned long max_order,
648         unsigned long min_order,
649         unsigned int node_id
650 )
651 {
652     struct buddy_memzone * zone = NULL;
653     unsigned long i;
654
655     DEBUG("Initializing Memory zone with up to %lu bit blocks on Node %d\n", max_order, node_id);
656
657
658     /* Smallest block size must be big enough to hold a block structure */
659     if ((1UL << min_order) < sizeof(struct block))
660         min_order = ilog2( roundup_pow_of_two(sizeof(struct block)) );
661
662     /* The minimum block order must be smaller than the pool order */
663     if (min_order > max_order)
664         return NULL;
665
666     zone = palacios_alloc_extended(sizeof(struct buddy_memzone), GFP_KERNEL, node_id);
667         
668     INFO("Allocated zone at %p\n", zone);
669
670     if (!zone) {
671         ERROR("Could not allocate memzone\n");
672         return NULL;
673     }
674
675     memset(zone, 0, sizeof(struct buddy_memzone));
676
677     zone->max_order = max_order;
678     zone->min_order  = min_order;
679     zone->node_id = node_id;
680
681     /* Allocate a list for every order up to the maximum allowed order */
682     zone->avail = palacios_alloc_extended((max_order + 1) * sizeof(struct list_head), GFP_KERNEL, zone->node_id);
683
684     if (!(zone->avail)) { 
685         ERROR("Unable to allocate space for zone list\n");
686         palacios_free(zone);
687         return NULL;
688     }
689
690     INFO("Allocated free lists at %p\n", zone->avail);
691
692     /* Initially all lists are empty */
693     for (i = 0; i <= max_order; i++) {
694         INIT_LIST_HEAD(&zone->avail[i]);
695     }
696
697
698     palacios_spinlock_init(&(zone->lock));
699
700     zone->mempools.rb_node = NULL;
701
702     INFO("Allocated zone at %p\n", zone);
703
704     {
705         struct proc_dir_entry * zone_entry = NULL;
706         char proc_file_name[128];
707
708         memset(proc_file_name, 0, 128);
709         snprintf(proc_file_name, 128, "v3-mem%u", zone->node_id);
710
711         zone_entry = create_proc_entry(proc_file_name, 0444, palacios_get_procdir());
712         if (zone_entry) {
713             zone_entry->proc_fops = &zone_proc_ops;
714             zone_entry->data = zone;
715             INFO("Successfully created /proc/v3vee/v3-mem%d\n", zone->node_id);
716         } else {
717             ERROR("Cannot create /proc/v3vee/v3-mem%d\n", zone->node_id);
718         }
719
720     }
721
722     return zone;
723 }