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.


Integration of buddy allocator
[palacios.git] / linux_module / mm.c
1 /* Palacios memory manager 
2  * (c) Jack Lange, 2010
3  */
4
5 #include <asm/page_64_types.h>
6 #include <linux/kernel.h>
7 #include <linux/list.h>
8 #include <linux/slab.h>
9 #include <linux/mm.h>
10 //static struct list_head pools;
11
12 #include "palacios.h"
13 #include "mm.h"
14 #include "buddy.h"
15 #include "numa.h"
16
17
18 static struct buddy_memzone ** memzones = NULL;
19 static uintptr_t * seed_addrs = NULL;
20
21
22 // alignment is in bytes
23 uintptr_t alloc_palacios_pgs(u64 num_pages, u32 alignment, int node_id) {
24     uintptr_t addr = 0; 
25
26     if (node_id == -1) {
27         int cpu_id = get_cpu();
28         put_cpu();
29         
30         node_id = numa_cpu_to_node(cpu_id);
31     } else if (numa_num_nodes() == 1) {
32         node_id = 0;
33     } else if (node_id >= numa_num_nodes()) {
34         ERROR("Requesting memory from an invalid NUMA node. (Node: %d) (%d nodes on system)\n", 
35               node_id, numa_num_nodes());
36         return 0;
37     }
38
39     addr = buddy_alloc(memzones[node_id], get_order(num_pages * PAGE_SIZE) + PAGE_SHIFT);
40
41     //DEBUG("Returning from alloc addr=%p, vaddr=%p\n", (void *)addr, __va(addr));
42     return addr;
43 }
44
45
46
47 void free_palacios_pgs(uintptr_t pg_addr, u64 num_pages) {
48     int node_id = numa_addr_to_node(pg_addr);
49
50     //DEBUG("Freeing Memory page %p\n", (void *)pg_addr);
51     buddy_free(memzones[node_id], pg_addr, get_order(num_pages * PAGE_SIZE) + PAGE_SHIFT);
52     
53     return;
54 }
55
56
57 int pow2(int i)
58 {
59     int x=1;
60     for (;i>0;i--) { x*=2; } 
61     return x;
62 }
63
64 int add_palacios_memory(struct v3_mem_region *r) {
65     int pool_order = 0;
66     int node_id = 0;
67
68     struct v3_mem_region *keep;
69
70     // fixup request regardless of its type
71     if (r->num_pages*4096 < V3_CONFIG_MEM_BLOCK_SIZE) { 
72         WARNING("Allocating a memory pool smaller than the Palacios block size - may not be useful\n");
73     }
74
75     if (pow2(get_order(r->num_pages)) != r->num_pages) { 
76         WARNING("Allocating a memory pool that is not a power of two - it will be rounded down!\n");
77         r->num_pages=pow2(get_order(r->num_pages));
78     }
79
80
81     if (!(keep=palacios_alloc(sizeof(struct v3_mem_region)))) { 
82         ERROR("Error allocating space for tracking region\n");
83         return -1;
84     }
85
86
87     if (r->type==REQUESTED || r->type==REQUESTED32) { 
88         struct page * pgs = alloc_pages_node(r->node, 
89                                              r->type==REQUESTED ? GFP_KERNEL :
90                                              r->type==REQUESTED32 ? GFP_DMA32 : GFP_KERNEL, 
91                                              get_order(r->num_pages));
92         if (!pgs) { 
93             ERROR("Unable to satisfy allocation request\n");
94             palacios_free(keep);
95             return -1;
96         }
97         r->base_addr = page_to_pfn(pgs) << PAGE_SHIFT;
98     }
99         
100
101     *keep = *r;
102
103     node_id = numa_addr_to_node(r->base_addr);
104
105     if (node_id == -1) {
106         ERROR("Error locating node for addr %p\n", (void *)(r->base_addr));
107         return -1;
108     }
109
110     pool_order = get_order(r->num_pages * PAGE_SIZE) + PAGE_SHIFT;
111
112     if (buddy_add_pool(memzones[node_id], r->base_addr, pool_order, keep)) {
113         ERROR("ALERT ALERT ALERT Unable to add pool to buddy allocator...\n");
114         if (r->type==REQUESTED || r->type==REQUESTED32) { 
115             free_pages((uintptr_t)__va(r->base_addr), get_order(r->num_pages));
116         }
117         palacios_free(keep);
118         return -1;
119     }
120
121     return 0;
122 }
123
124
125
126 int palacios_remove_memory(uintptr_t base_addr) {
127     int node_id = numa_addr_to_node(base_addr);
128     struct v3_mem_region *r;
129
130     if (buddy_remove_pool(memzones[node_id], base_addr, 0, (void**)(&r))) { //unforced remove
131         ERROR("Cannot remove memory at base address 0x%p because it is in use\n", (void*)base_addr);
132         return -1;
133     }
134
135     if (r->type==REQUESTED || r->type==REQUESTED32) { 
136         free_pages((uintptr_t)__va(r->base_addr), get_order(r->num_pages));
137     } else {
138         // user space resposible for onlining
139     }
140     
141     palacios_free(r);
142
143     return 0;
144 }
145
146
147
148 int palacios_deinit_mm( void ) {
149
150     int i = 0;
151
152     if (memzones) {
153         for (i = 0; i < numa_num_nodes(); i++) {
154             
155             if (memzones[i]) {
156                 buddy_deinit(memzones[i]);
157             }
158             
159             // note that the memory is not onlined here - offlining and onlining
160             // is the resposibility of the caller
161             
162             if (seed_addrs[i]) {
163                 // free the seed regions
164                 free_pages((uintptr_t)__va(seed_addrs[i]), MAX_ORDER - 1);
165             }
166         }
167         
168         palacios_free(memzones);
169         palacios_free(seed_addrs);
170     }
171
172     return 0;
173 }
174
175 int palacios_init_mm( void ) {
176     int num_nodes = numa_num_nodes();
177     int node_id = 0;
178
179     memzones = palacios_alloc_extended(sizeof(struct buddy_memzone *) * num_nodes, GFP_KERNEL);
180
181     if (!memzones) { 
182         ERROR("Cannot allocate space for memory zones\n");
183         palacios_deinit_mm();
184         return -1;
185     }
186
187     memset(memzones, 0, sizeof(struct buddy_memzone *) * num_nodes);
188
189     seed_addrs = palacios_alloc_extended(sizeof(uintptr_t) * num_nodes, GFP_KERNEL);
190
191     if (!seed_addrs) { 
192         ERROR("Cannot allocate space for seed addrs\n");
193         palacios_deinit_mm();
194         return -1;
195     }
196
197     memset(seed_addrs, 0, sizeof(uintptr_t) * num_nodes);
198
199     for (node_id = 0; node_id < num_nodes; node_id++) {
200         struct buddy_memzone * zone = NULL;
201
202         // Seed the allocator with a small set of pages to allow initialization to complete. 
203         // For now we will just grab some random pages, but in the future we will need to grab NUMA specific regions
204         // See: alloc_pages_node()
205
206         {
207             struct page * pgs = alloc_pages_node(node_id, GFP_KERNEL, MAX_ORDER - 1);
208
209             if (!pgs) {
210                 ERROR("Could not allocate initial memory block for node %d\n", node_id);
211                 BUG_ON(!pgs);
212                 palacios_deinit_mm();
213                 return -1;
214             }
215
216             seed_addrs[node_id] = page_to_pfn(pgs) << PAGE_SHIFT;
217         }
218
219         zone = buddy_init(get_order(V3_CONFIG_MEM_BLOCK_SIZE) + PAGE_SHIFT, PAGE_SHIFT, node_id);
220
221         if (zone == NULL) {
222             ERROR("Could not initialization memory management for node %d\n", node_id);
223             palacios_deinit_mm();
224             return -1;
225         }
226
227         printk("Zone initialized, Adding seed region (order=%d)\n", 
228                (MAX_ORDER - 1) + PAGE_SHIFT);
229
230         if (buddy_add_pool(zone, seed_addrs[node_id], (MAX_ORDER - 1) + PAGE_SHIFT,0)) { 
231             ERROR("Could not add pool to buddy allocator\n");
232             palacios_deinit_mm();
233             return -1;
234         }
235
236         memzones[node_id] = zone;
237     }
238
239     return 0;
240
241 }
242