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.


Fixed spurious warning when memory block size is overrriden
[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 #include "palacios/vmm.h"
17
18
19 static struct buddy_memzone ** memzones = NULL;
20 static uintptr_t * seed_addrs = NULL;
21
22
23 // alignment is in bytes
24 uintptr_t alloc_palacios_pgs(u64 num_pages, u32 alignment, int node_id, int constraints) {
25     uintptr_t addr = 0; 
26     int any = node_id==-1; // can allocate on any
27     int buddy_constraints=0;
28
29     if (constraints && constraints!=V3_ALLOC_PAGES_CONSTRAINT_4GB) { 
30         ERROR("Unknown constraint mask 0x%x\n",constraints);
31         return 0;
32     }
33     
34     if (constraints & V3_ALLOC_PAGES_CONSTRAINT_4GB) { 
35         buddy_constraints |= LWK_BUDDY_CONSTRAINT_4GB;
36     }
37
38
39     if (node_id == -1) {
40         int cpu_id = get_cpu();
41         put_cpu();
42         
43         node_id = numa_cpu_to_node(cpu_id); // try first preferentially for the calling pcore
44
45     } else if (numa_num_nodes() == 1) {
46         node_id = 0;
47     } else if (node_id >= numa_num_nodes()) {
48         ERROR("Requesting memory from an invalid NUMA node. (Node: %d) (%d nodes on system)\n", 
49               node_id, numa_num_nodes());
50         return 0;
51     }
52
53     addr = buddy_alloc(memzones[node_id], get_order(num_pages * PAGE_SIZE) + PAGE_SHIFT, buddy_constraints);
54
55     if (!addr && any) { 
56         int i;
57         // do a scan to see if we can satisfy request on any node
58         for (i=0; i< numa_num_nodes(); i++) { 
59             if (i!=node_id) { 
60                 addr = buddy_alloc(memzones[i], get_order(num_pages * PAGE_SIZE) + PAGE_SHIFT, buddy_constraints);
61                 if (addr) {
62                     break;
63                 }
64             }
65         }
66     }
67                 
68
69     //DEBUG("Returning from alloc addr=%p, vaddr=%p\n", (void *)addr, __va(addr));
70     return addr;
71 }
72
73
74
75 void free_palacios_pgs(uintptr_t pg_addr, u64 num_pages) {
76     int node_id = numa_addr_to_node(pg_addr);
77
78     //DEBUG("Freeing Memory page %p\n", (void *)pg_addr);
79     buddy_free(memzones[node_id], pg_addr, get_order(num_pages * PAGE_SIZE) + PAGE_SHIFT);
80     
81     return;
82 }
83
84
85 unsigned long long pow2(int i)
86 {
87     unsigned long long x=1;
88     for (;i!=0;i--) { x*=2; } 
89     return x;
90 }
91
92 static unsigned long long get_palacios_mem_block_size(void)
93 {
94     char *s = v3_lookup_option("mem_block_size");
95
96     if (!s) { 
97         return V3_CONFIG_MEM_BLOCK_SIZE;
98     } else {
99         unsigned long long temp;
100
101         if (strict_strtoull(s,0,&temp)) { 
102             return V3_CONFIG_MEM_BLOCK_SIZE; // odd...
103         } else {
104             return temp;
105         }
106     }
107 }
108
109 int add_palacios_memory(struct v3_mem_region *r) {
110     int pool_order = 0;
111     int node_id = 0;
112
113
114     struct v3_mem_region *keep;
115
116     INFO("Palacios Memory Add Request: type=%d, node=%d, base_addr=0x%llx, num_pages=%llu\n",r->type,r->node,r->base_addr,r->num_pages);
117
118     // fixup request regardless of its type
119     if (r->num_pages*4096 < get_palacios_mem_block_size()) { 
120         WARNING("Allocating a memory pool smaller than the Palacios block size - may not be useful\n");
121     }
122
123     if (pow2(get_order(r->num_pages*PAGE_SIZE)) != r->num_pages) { 
124         WARNING("Allocating a memory pool that is not a power of two (is %llu) - it will be rounded down!\n", r->num_pages);
125         r->num_pages=pow2(get_order(r->num_pages*PAGE_SIZE));
126         WARNING("Rounded request is for %llu pages\n", r->num_pages);
127     }
128
129
130     if (!(keep=palacios_alloc(sizeof(struct v3_mem_region)))) { 
131         ERROR("Error allocating space for tracking region\n");
132         return -1;
133     }
134
135
136     if (r->type==REQUESTED || r->type==REQUESTED32) { 
137         struct page *pgs;
138
139         INFO("Attempting to allocate %llu pages of %s memory\n", r->num_pages,
140              r->type==REQUESTED ? "64 bit (unrestricted)" : 
141              r->type==REQUESTED32 ? "32 bit (restricted)" : "unknown (assuming 64 bit unrestricted)");
142              
143         pgs = alloc_pages_node(r->node, 
144                                r->type==REQUESTED ? GFP_KERNEL :
145                                r->type==REQUESTED32 ? GFP_DMA32 : GFP_KERNEL, 
146                                get_order(r->num_pages*PAGE_SIZE));
147         if (!pgs) { 
148             ERROR("Unable to satisfy allocation request\n");
149             palacios_free(keep);
150             return -1;
151         }
152         r->base_addr = page_to_pfn(pgs) << PAGE_SHIFT;
153     }
154         
155
156     *keep = *r;
157
158     node_id = numa_addr_to_node(r->base_addr);
159
160     if (node_id == -1) {
161         ERROR("Error locating node for addr %p\n", (void *)(r->base_addr));
162         return -1;
163     }
164
165     if ((node_id != r->node) && (r->node!=-1)) { 
166         INFO("Memory add request is for node %d, but memory is in node %d\n",r->node,node_id);
167     }
168
169     pool_order = get_order(r->num_pages * PAGE_SIZE) + PAGE_SHIFT;
170
171     if (buddy_add_pool(memzones[node_id], r->base_addr, pool_order, keep)) {
172         ERROR("ALERT ALERT ALERT Unable to add pool to buddy allocator...\n");
173         if (r->type==REQUESTED || r->type==REQUESTED32) { 
174             free_pages((uintptr_t)__va(r->base_addr), get_order(r->num_pages*PAGE_SIZE));
175         }
176         palacios_free(keep);
177         return -1;
178     }
179
180     return 0;
181 }
182
183
184
185 int remove_palacios_memory(struct v3_mem_region *req) {
186     int node_id = numa_addr_to_node(req->base_addr);
187     struct v3_mem_region *r;
188
189     if (buddy_remove_pool(memzones[node_id], req->base_addr, 0, (void**)(&r))) { //unforced remove
190         ERROR("Cannot remove memory at base address 0x%p\n", (void*)(req->base_addr));
191         return -1;
192     }
193
194     if (r) {
195         if (r->type==REQUESTED || r->type==REQUESTED32) { 
196             free_pages((uintptr_t)__va(r->base_addr), get_order(r->num_pages*PAGE_SIZE));
197         } else {
198             // user space responsible for onlining
199         }
200         palacios_free(r);
201     }
202
203     return 0;
204 }
205
206
207 static int handle_free(void *meta)
208 {
209     struct v3_mem_region *r = (struct v3_mem_region *)meta;
210
211     if (r) { 
212         if (r->type==REQUESTED || r->type==REQUESTED32) { 
213             //INFO("Freeing %llu pages at %p\n",r->num_pages,(void*)(r->base_addr));
214             free_pages((uintptr_t)__va(r->base_addr), get_order(r->num_pages*PAGE_SIZE));
215         } else {
216             // user space responsible for onlining
217         }
218         palacios_free(r);
219     }
220     
221     return 0;
222 }
223
224         
225
226
227 int palacios_deinit_mm( void ) {
228
229     int i = 0;
230
231     if (memzones) {
232         for (i = 0; i < numa_num_nodes(); i++) {
233             
234             if (memzones[i]) {
235                 INFO("Deiniting memory zone %d\n",i);
236                 buddy_deinit(memzones[i],handle_free);
237             }
238             
239             // note that the memory is not onlined here - offlining and onlining
240             // is the resposibility of the caller
241             
242             if (seed_addrs[i]) {
243                 // free the seed regions
244                 INFO("Freeing seed addrs %d\n",i);
245                 free_pages((uintptr_t)__va(seed_addrs[i]), MAX_ORDER - 1);
246             }
247         }
248         
249         palacios_free(memzones);
250         palacios_free(seed_addrs);
251     }
252
253     return 0;
254 }
255
256 int palacios_init_mm( void ) {
257     int num_nodes = numa_num_nodes();
258     int node_id = 0;
259
260     INFO("memory manager init: MAX_ORDER=%d (%llu bytes)\n",MAX_ORDER, PAGE_SIZE*pow2(MAX_ORDER));
261
262     memzones = palacios_alloc_extended(sizeof(struct buddy_memzone *) * num_nodes, GFP_KERNEL,-1);
263
264     if (!memzones) { 
265         ERROR("Cannot allocate space for memory zones\n");
266         palacios_deinit_mm();
267         return -1;
268     }
269
270     memset(memzones, 0, sizeof(struct buddy_memzone *) * num_nodes);
271
272     seed_addrs = palacios_alloc_extended(sizeof(uintptr_t) * num_nodes, GFP_KERNEL,-1);
273
274     if (!seed_addrs) { 
275         ERROR("Cannot allocate space for seed addrs\n");
276         palacios_deinit_mm();
277         return -1;
278     }
279
280     memset(seed_addrs, 0, sizeof(uintptr_t) * num_nodes);
281
282     for (node_id = 0; node_id < num_nodes; node_id++) {
283         struct buddy_memzone * zone = NULL;
284
285         // Seed the allocator with a small set of pages to allow initialization to complete. 
286         // For now we will just grab some random pages, but in the future we will need to grab NUMA specific regions
287         // See: alloc_pages_node()
288
289         {
290             struct page * pgs;
291
292             // attempt to first allocate below 4 GB for compatibility with
293             // 32 bit shadow paging
294             pgs = alloc_pages_node(node_id, GFP_DMA32, MAX_ORDER - 1);
295
296             if (!pgs) {
297                 INFO("Could not allocate initial memory block for node %d below 4GB\n", node_id);
298                 
299                 pgs = alloc_pages_node(node_id, GFP_KERNEL, MAX_ORDER - 1);
300
301                 if (!pgs) {
302                     INFO("Could not allocate initial memory block for node %d beloew 4GB\n", node_id);
303                     if (!pgs) {
304                         ERROR("Could not allocate initial memory block for node %d without restrictions\n", node_id);
305                         BUG_ON(!pgs);
306                         palacios_deinit_mm();
307                         return -1;
308                     }
309                 }
310             }
311
312             seed_addrs[node_id] = page_to_pfn(pgs) << PAGE_SHIFT;
313         }
314
315     // Initialization is done using the compile-time memory block size since
316     // at this point, we do not yet know what the run-time size is
317         zone = buddy_init(get_order(V3_CONFIG_MEM_BLOCK_SIZE) + PAGE_SHIFT, PAGE_SHIFT, node_id);
318
319         if (zone == NULL) {
320             ERROR("Could not initialization memory management for node %d\n", node_id);
321             palacios_deinit_mm();
322             return -1;
323         }
324
325         printk("Zone initialized, Adding seed region (order=%d)\n", 
326                (MAX_ORDER - 1) + PAGE_SHIFT);
327
328         if (buddy_add_pool(zone, seed_addrs[node_id], (MAX_ORDER - 1) + PAGE_SHIFT,0)) { 
329             ERROR("Could not add pool to buddy allocator\n");
330             palacios_deinit_mm();
331             return -1;
332         }
333
334         memzones[node_id] = zone;
335     }
336
337     return 0;
338
339 }
340