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.


1b70b74639ef2d267176b130b2312f6aaa2878e3
[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     if (buddy_free(memzones[node_id], pg_addr, get_order(num_pages * PAGE_SIZE) + PAGE_SHIFT)) {
80       // it is possible that the allocation was actually on a different zone,
81       // so, just to be sure, we'll try to dellocate on each
82       for (node_id=0;node_id<numa_num_nodes();node_id++) { 
83         if (!buddy_free(memzones[node_id], pg_addr, get_order(num_pages * PAGE_SIZE) + PAGE_SHIFT)) {
84           // successfully freed on different zone, which is also OK
85           break;
86         }
87       }
88       if (node_id==numa_num_nodes()) { 
89         ERROR("Unable to free pages -addr=%p, numpages=%llu on any node\n",(void*)pg_addr,num_pages);
90       }
91     }
92     
93     return;
94 }
95
96
97 unsigned long long pow2(int i)
98 {
99     unsigned long long x=1;
100     for (;i!=0;i--) { x*=2; } 
101     return x;
102 }
103
104 static unsigned long long get_palacios_mem_block_size(void)
105 {
106     char *s = v3_lookup_option("mem_block_size");
107
108     if (!s) { 
109         return V3_CONFIG_MEM_BLOCK_SIZE;
110     } else {
111         unsigned long long temp;
112
113         if (strict_strtoull(s,0,&temp)) { 
114             return V3_CONFIG_MEM_BLOCK_SIZE; // odd...
115         } else {
116             return temp;
117         }
118     }
119 }
120
121 int add_palacios_memory(struct v3_mem_region *r) {
122     int pool_order = 0;
123     int node_id = 0;
124
125
126     struct v3_mem_region *keep;
127
128     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);
129
130     // fixup request regardless of its type
131     if (r->num_pages*4096 < get_palacios_mem_block_size()) { 
132         WARNING("Allocating a memory pool smaller than the Palacios block size - may not be useful\n");
133     }
134
135     if (pow2(get_order(r->num_pages*PAGE_SIZE)) != r->num_pages) { 
136         WARNING("Allocating a memory pool that is not a power of two (is %llu) - it will be rounded down!\n", r->num_pages);
137         r->num_pages=pow2(get_order(r->num_pages*PAGE_SIZE));
138         WARNING("Rounded request is for %llu pages\n", r->num_pages);
139     }
140
141
142     if (!(keep=palacios_alloc(sizeof(struct v3_mem_region)))) { 
143         ERROR("Error allocating space for tracking region\n");
144         return -1;
145     }
146
147
148     if (r->type==REQUESTED || r->type==REQUESTED32) { 
149         struct page *pgs;
150
151         INFO("Attempting to allocate %llu pages of %s memory\n", r->num_pages,
152              r->type==REQUESTED ? "64 bit (unrestricted)" : 
153              r->type==REQUESTED32 ? "32 bit (restricted)" : "unknown (assuming 64 bit unrestricted)");
154              
155         pgs = alloc_pages_node(r->node, 
156                                r->type==REQUESTED ? GFP_KERNEL :
157                                r->type==REQUESTED32 ? GFP_DMA32 : GFP_KERNEL, 
158                                get_order(r->num_pages*PAGE_SIZE));
159         if (!pgs) { 
160             ERROR("Unable to satisfy allocation request\n");
161             palacios_free(keep);
162             return -1;
163         } 
164         r->base_addr = page_to_pfn(pgs) << PAGE_SHIFT;
165     }
166         
167
168     *keep = *r;
169
170     node_id = numa_addr_to_node(r->base_addr);
171
172     if (node_id == -1) {
173         ERROR("Error locating node for addr %p\n", (void *)(r->base_addr));
174         return -1;
175     }
176
177     if ((node_id != r->node) && (r->node!=-1)) { 
178         INFO("Memory add request is for node %d, but memory is in node %d\n",r->node,node_id);
179     }
180
181     pool_order = get_order(r->num_pages * PAGE_SIZE) + PAGE_SHIFT;
182
183     if (buddy_add_pool(memzones[node_id], r->base_addr, pool_order, keep)) {
184         ERROR("ALERT ALERT ALERT Unable to add pool to buddy allocator...\n");
185         if (r->type==REQUESTED || r->type==REQUESTED32) { 
186             free_pages((uintptr_t)__va(r->base_addr), get_order(r->num_pages*PAGE_SIZE));
187         }
188         palacios_free(keep);
189         return -1;
190     }
191
192     return 0;
193 }
194
195
196
197 int remove_palacios_memory(struct v3_mem_region *req) {
198     int node_id = numa_addr_to_node(req->base_addr);
199     struct v3_mem_region *r;
200
201     if (buddy_remove_pool(memzones[node_id], req->base_addr, 0, (void**)(&r))) { //unforced remove
202         ERROR("Cannot remove memory at base address 0x%p\n", (void*)(req->base_addr));
203         return -1;
204     }
205
206     if (r) {
207         if (r->type==REQUESTED || r->type==REQUESTED32) { 
208             free_pages((uintptr_t)__va(r->base_addr), get_order(r->num_pages*PAGE_SIZE));
209         } else {
210             // user space responsible for onlining
211         }
212         palacios_free(r);
213     }
214
215     return 0;
216 }
217
218
219 static int handle_free(void *meta)
220 {
221     struct v3_mem_region *r = (struct v3_mem_region *)meta;
222
223     if (r) { 
224         if (r->type==REQUESTED || r->type==REQUESTED32) { 
225             //INFO("Freeing %llu pages at %p\n",r->num_pages,(void*)(r->base_addr));
226             free_pages((uintptr_t)__va(r->base_addr), get_order(r->num_pages*PAGE_SIZE));
227         } else {
228             // user space responsible for onlining
229         }
230         palacios_free(r);
231     }
232     
233     return 0;
234 }
235
236         
237
238
239 int palacios_deinit_mm( void ) {
240
241     int i = 0;
242
243     if (memzones) {
244         for (i = 0; i < numa_num_nodes(); i++) {
245             
246             if (memzones[i]) {
247                 INFO("Deiniting memory zone %d\n",i);
248                 buddy_deinit(memzones[i],handle_free);
249             }
250             
251             // note that the memory is not onlined here - offlining and onlining
252             // is the resposibility of the caller
253             
254             if (seed_addrs[i]) {
255                 // free the seed regions
256                 INFO("Freeing seed addrs %d\n",i);
257                 free_pages((uintptr_t)__va(seed_addrs[i]), MAX_ORDER - 1);
258             }
259         }
260         
261         palacios_free(memzones);
262         palacios_free(seed_addrs);
263     }
264
265     return 0;
266 }
267
268 int palacios_init_mm( void ) {
269     int num_nodes = numa_num_nodes();
270     int node_id = 0;
271
272     INFO("memory manager init: MAX_ORDER=%d (%llu bytes)\n",MAX_ORDER, PAGE_SIZE*pow2(MAX_ORDER));
273
274     memzones = palacios_alloc_extended(sizeof(struct buddy_memzone *) * num_nodes, GFP_KERNEL,-1);
275
276     if (!memzones) { 
277         ERROR("Cannot allocate space for memory zones\n");
278         palacios_deinit_mm();
279         return -1;
280     }
281
282     memset(memzones, 0, sizeof(struct buddy_memzone *) * num_nodes);
283
284     seed_addrs = palacios_alloc_extended(sizeof(uintptr_t) * num_nodes, GFP_KERNEL,-1);
285
286     if (!seed_addrs) { 
287         ERROR("Cannot allocate space for seed addrs\n");
288         palacios_deinit_mm();
289         return -1;
290     }
291
292     memset(seed_addrs, 0, sizeof(uintptr_t) * num_nodes);
293
294     for (node_id = 0; node_id < num_nodes; node_id++) {
295         struct buddy_memzone * zone = NULL;
296
297         // Seed the allocator with a small set of pages to allow initialization to complete. 
298         // For now we will just grab some random pages, but in the future we will need to grab NUMA specific regions
299         // See: alloc_pages_node()
300
301         {
302             struct page * pgs;
303             int actual_node;
304               
305             // attempt to first allocate below 4 GB for compatibility with
306             // 32 bit shadow paging
307             pgs = alloc_pages_node(node_id, GFP_DMA32, MAX_ORDER - 1);
308
309
310             if (!pgs) {
311                 INFO("Could not allocate initial memory block for node %d below 4GB\n", node_id);
312                 
313                 pgs = alloc_pages_node(node_id, GFP_KERNEL, MAX_ORDER - 1);
314
315                 if (!pgs) {
316                     INFO("Could not allocate initial memory block for node %d beloew 4GB\n", node_id);
317                     if (!pgs) {
318                         ERROR("Could not allocate initial memory block for node %d without restrictions\n", node_id);
319                         BUG_ON(!pgs);
320                         palacios_deinit_mm();
321                         return -1;
322                     }
323                 } else {
324                   actual_node=numa_addr_to_node((uintptr_t)(page_to_pfn(pgs) << PAGE_SHIFT));
325                   if (actual_node != node_id) { 
326                     WARNING("Initial 64 bit allocation attempt for node %d resulted in allocation on node %d\n",node_id,actual_node);
327                   }
328                 }
329                   
330             } else {
331               actual_node=numa_addr_to_node((uintptr_t)(page_to_pfn(pgs) << PAGE_SHIFT));
332               if (actual_node != node_id) { 
333                 WARNING("Initial 32bit-limited allocation attempt for node %d resulted in allocation on node %d\n",node_id,actual_node);
334               }
335             }
336
337             seed_addrs[node_id] = page_to_pfn(pgs) << PAGE_SHIFT;
338         }
339
340     // Initialization is done using the compile-time memory block size since
341     // at this point, we do not yet know what the run-time size is
342         zone = buddy_init(get_order(V3_CONFIG_MEM_BLOCK_SIZE) + PAGE_SHIFT, PAGE_SHIFT, node_id);
343
344         if (zone == NULL) {
345             ERROR("Could not initialization memory management for node %d\n", node_id);
346             palacios_deinit_mm();
347             return -1;
348         }
349
350         printk("Zone initialized, Adding seed region (order=%d)\n", 
351                (MAX_ORDER - 1) + PAGE_SHIFT);
352
353         if (buddy_add_pool(zone, seed_addrs[node_id], (MAX_ORDER - 1) + PAGE_SHIFT,0)) { 
354             ERROR("Could not add pool to buddy allocator\n");
355             palacios_deinit_mm();
356             return -1;
357         }
358
359         memzones[node_id] = zone;
360     }
361
362     return 0;
363
364 }
365