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.


Enhanced user-space memory interface, allowing dynamic kernel-allocations
[palacios.git] / linux_usr / v3_mem.c
1 /* 
2  * V3 Control utility
3  * (c) Jack lange, 2010
4  */
5
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <fcntl.h> 
10 #include <sys/ioctl.h> 
11 #include <sys/stat.h> 
12 #include <sys/types.h> 
13 #include <unistd.h> 
14 #include <string.h>
15 #include <dirent.h> 
16
17 #include "v3_ctrl.h"
18
19 #define SYS_PATH "/sys/devices/system/memory/"
20
21 #define BUF_SIZE 128
22
23
24
25
26 static int offline_memory(unsigned long long mem_size_bytes,
27                           unsigned long long mem_min_start,
28                           int limit32, 
29                           unsigned long long *num_bytes, 
30                           unsigned long long *base_addr);
31
32 int main(int argc, char * argv[]) {
33     unsigned long long mem_size_bytes = 0;
34     unsigned long long mem_min_start = 0;
35     int v3_fd = -1;
36     int request = 0;
37     int limit32 = 0;
38     int node = -1;
39     int c;
40     unsigned long long num_bytes, base_addr;
41     struct v3_mem_region mem;
42
43     if (argc<2 || argc>5) {
44         printf("usage: v3_mem [-r] [-l] [-n k] <memory size (MB)> [min_start (MB)]\n\n"
45                "Allocate memory for use by Palacios.\n\n"
46                "With    -r    this requests in-kernel allocation.\n"
47                "Without -r    this attempts to offline memory via hot\n"
48                "              remove.\n"
49                "With    -l    the request or offlining is limited to first 4 GB\n"
50                "Without -l    the request or offlining has no limits\n\n"
51                "With    -n k  the request is for numa node k\n"
52                "Without -n k  the request can be on any numa node\n\n"
53                "For offlining, min_start is the minimum allowable starting address.\n"
54                "This is zero by default\n\n");  
55         return -1;
56     }
57
58     while ((c=getopt(argc,argv,"rln:"))!=-1) {
59         switch (c) {
60             case 'r':
61                 request=1;
62                 break;
63             case 'l':
64                 limit32=1;
65                 break;
66             case 'n':
67                 node = atoi(optarg);
68                 break;
69             case '?':
70                 if (optopt=='n') { 
71                     printf("-n requires the numa node...\n");
72                 } else {
73                     printf("Unknown option %c\n",optopt);
74                 }
75                 break;
76             default:
77                 printf("Unknown option %c\n",optopt);
78                 break;
79         }
80     }
81         
82
83     mem_size_bytes = atoll(argv[optind]) * (1024 * 1024);
84
85     if ((optind+1) < argc) { 
86         mem_min_start = atoll(argv[optind+1]) * (1024 * 1024);
87     }
88
89     v3_fd = open(v3_dev, O_RDONLY);
90     
91     if (v3_fd == -1) {
92         printf("Error opening V3Vee control device\n");
93         return -1;
94     }
95
96     if (!request) { 
97         printf("Trying to offline memory (size=%llu, min_start=%llu, limit32=%d)\n",mem_size_bytes,mem_min_start,limit32);
98         if (offline_memory(mem_size_bytes,mem_min_start,limit32, &num_bytes, &base_addr)) { 
99             printf("Could not offline memory\n");
100             return -1;
101         }
102         mem.type=PREALLOCATED;
103         mem.node=0;
104         mem.base_addr=base_addr;
105         mem.num_pages=num_bytes/4096;
106     } else {
107         printf("Generating memory allocation request (size=%llu, limit32=%d)\n", mem_size_bytes, limit32);
108         mem.type = limit32 ? REQUESTED32 : REQUESTED;
109         mem.node = node;
110         num_bytes = mem_size_bytes;
111         base_addr = 0;
112     }
113     
114     if (ioctl(v3_fd, V3_ADD_MEMORY, &mem)<0) { 
115         printf("Request rejected by Palacios\n");
116         close(v3_fd);
117         return -1;
118     } else {
119         printf("Request accepted by Palacios\n");
120         close(v3_fd);   
121         return 0;
122     }
123
124
125
126 static int dir_filter(const struct dirent * dir) {
127     if (strncmp("memory", dir->d_name, 6) == 0) {
128         return 1;
129     }
130
131     return 0;
132 }
133
134
135 static int dir_cmp(const struct dirent **dir1, const struct dirent ** dir2) {
136     int num1 = atoi((*dir1)->d_name + 6);
137     int num2 = atoi((*dir2)->d_name + 6);
138
139     return num1 - num2;
140 }
141
142
143 static int offline_memory(unsigned long long mem_size_bytes,
144                           unsigned long long mem_min_start,
145                           int limit32, 
146                           unsigned long long *num_bytes, 
147                           unsigned long long *base_addr)
148 {
149
150     unsigned int block_size_bytes = 0;
151     int bitmap_entries = 0;
152     unsigned char * bitmap = NULL;
153     int num_blocks = 0;    
154     int reg_start = 0;
155     int mem_ready = 0;
156     
157
158     printf("Trying to find %dMB (%d bytes) of memory above %llu with limit32=%d\n", mem_size_bytes/(1024*1024), mem_size_bytes, mem_min_start, limit32);
159         
160     /* Figure out the block size */
161     {
162         int tmp_fd = 0;
163         char tmp_buf[BUF_SIZE];
164         
165         tmp_fd = open(SYS_PATH "block_size_bytes", O_RDONLY);
166         
167         if (tmp_fd == -1) {
168             perror("Could not open block size file: " SYS_PATH "block_size_bytes");
169             return -1;
170         }
171     
172         if (read(tmp_fd, tmp_buf, BUF_SIZE) <= 0) {
173             perror("Could not read block size file: " SYS_PATH "block_size_bytes");
174             return -1;
175         }
176         
177         close(tmp_fd);
178         
179         block_size_bytes = strtoll(tmp_buf, NULL, 16);
180         
181         printf("Memory block size is %dMB (%d bytes)\n", block_size_bytes / (1024 * 1024), block_size_bytes);
182         
183     }
184     
185     
186     num_blocks =  mem_size_bytes / block_size_bytes;
187     if (mem_size_bytes % block_size_bytes) num_blocks++;
188     
189     mem_min_start = block_size_bytes * 
190         ((mem_min_start / block_size_bytes) + (!!(mem_min_start % block_size_bytes)));
191     
192     printf("Looking for %d blocks of memory starting at %p (block %llu) with limit32=%d\n", num_blocks, (void*)mem_min_start, mem_min_start/block_size_bytes,limit32);
193         
194     
195     // We now need to find <num_blocks> consecutive offlinable memory blocks
196     
197     /* Scan the memory directories */
198     {
199         struct dirent ** namelist = NULL;
200         int size = 0;
201         int i = 0;
202         int j = 0;
203         int last_block = 0;
204         int first_block = mem_min_start/block_size_bytes;
205         int limit_block = 0xffffffff / block_size_bytes; // for 32 bit limiting
206         
207         last_block = scandir(SYS_PATH, &namelist, dir_filter, dir_cmp);
208         bitmap_entries = atoi(namelist[last_block - 1]->d_name + 6) + 1;
209             
210         size = bitmap_entries / 8;
211         if (bitmap_entries % 8) size++;
212             
213         bitmap = malloc(size);
214         if (!bitmap) {
215             printf("ERROR: could not allocate space for bitmap\n");
216             return -1;
217         }
218         
219         memset(bitmap, 0, size);
220         
221         for (i = 0 ; j < bitmap_entries - 1; i++) {
222             struct dirent * tmp_dir = namelist[i];
223             int block_fd = 0;       
224             char status_str[BUF_SIZE];
225             char fname[BUF_SIZE];
226                 
227             memset(status_str, 0, BUF_SIZE);
228             memset(fname, 0, BUF_SIZE);
229                 
230             snprintf(fname, BUF_SIZE, "%s%s/removable", SYS_PATH, tmp_dir->d_name);
231                 
232             j = atoi(tmp_dir->d_name + 6);
233             int major = j / 8;
234             int minor = j % 8;
235                 
236                 
237             if (i<first_block) { 
238                 printf("Skipping %s due to minimum start constraint\n",fname);
239                 continue;
240             } 
241
242             if (limit32 && i>limit_block) { 
243                 printf("Skipping %s due to 32 bit constraint\n",fname);
244                 continue;
245             } 
246                 
247                 
248             printf("Checking %s...", fname);
249                 
250             block_fd = open(fname, O_RDONLY);
251                 
252             if (block_fd == -1) {
253                 printf("Hotpluggable memory not supported...\n");
254                 return -1;
255             }
256                 
257             if (read(block_fd, status_str, BUF_SIZE) <= 0) {
258                 perror("Could not read block status");
259                 return -1;
260             }
261                 
262             close(block_fd);
263                 
264             if (atoi(status_str) == 1) {
265                 printf("Removable\n");
266                 bitmap[major] |= (0x1 << minor);
267             } else {
268                 printf("Not removable\n");
269             }
270         }
271         
272     }
273     
274     while (!mem_ready) {
275         
276         
277         /* Scan bitmap for enough consecutive space */
278         {
279             // num_blocks: The number of blocks we need to find
280             // bitmap: bitmap of blocks (1 == allocatable)
281             // bitmap_entries: number of blocks in the system/number of bits in bitmap
282             // reg_start: The block index where our allocation will start
283                 
284             int i = 0;
285             int run_len = 0;
286             
287             for (i = 0; i < bitmap_entries; i++) {
288                 int i_major = i / 8;
289                 int i_minor = i % 8;
290                 
291                 if (!(bitmap[i_major] & (0x1 << i_minor))) {
292                     reg_start = i + 1; // skip the region start to next entry
293                     run_len = 0;
294                     continue;
295                 }
296                 
297                 run_len++;
298                     
299                 if (run_len >= num_blocks) {
300                     break;
301                 }
302             }
303             
304             
305             if (run_len < num_blocks) {
306                 fprintf(stderr, "Could not find enough consecutive memory blocks... (found %d)\n", run_len);
307                 return -1;
308             }
309         }
310         
311         
312         /* Offline memory blocks starting at reg_start */
313         {
314             int i = 0;
315             
316             for (i = 0; i < num_blocks; i++) {  
317                 FILE * block_file = NULL;
318                 char fname[256];
319                 
320                 memset(fname, 0, 256);
321                 
322                 snprintf(fname, 256, "%smemory%d/state", SYS_PATH, i + reg_start);
323                 
324                 block_file = fopen(fname, "r+");
325                 
326                 if (block_file == NULL) {
327                     perror("Could not open block file");
328                     return -1;
329                 }
330                 
331                     
332                 printf("Offlining block %d (%s)\n", i + reg_start, fname);
333                 fprintf(block_file, "offline\n");
334                 
335                 fclose(block_file);
336             }
337         }
338         
339         
340         /*  We asked to offline set of blocks, but Linux could have lied. 
341          *  To be safe, check whether blocks were offlined and start again if not 
342          */
343         
344         {
345             int i = 0;
346             
347             mem_ready = 1; // Hopefully we are ok...
348             
349             
350             for (i = 0; i < num_blocks; i++) {
351                 int block_fd = 0;
352                 char fname[BUF_SIZE];
353                 char status_buf[BUF_SIZE];
354                 
355                 
356                 memset(fname, 0, BUF_SIZE);
357                 memset(status_buf, 0, BUF_SIZE);
358                 
359                 snprintf(fname, BUF_SIZE, "%smemory%d/state", SYS_PATH, i + reg_start);
360                 
361                 
362                 block_fd = open(fname, O_RDONLY);
363                 
364                 if (block_fd == -1) {
365                     perror("Could not open block file");
366                     return -1;
367                 }
368                 
369                 if (read(block_fd, status_buf, BUF_SIZE) <= 0) {
370                     perror("Could not read block status");
371                     return -1;
372                 }
373                 
374                 printf("Checking offlined block %d (%s)...", i + reg_start, fname);
375                 
376                 int ret = strncmp(status_buf, "offline", strlen("offline"));
377                 
378                 if (ret != 0) {
379                     int j = 0;
380                     int major = (i + reg_start) / 8;
381                     int minor = (i + reg_start) % 8;
382
383                     bitmap[major] &= ~(0x1 << minor); // mark the block as not removable in bitmap
384                     
385                     mem_ready = 0; // Keep searching
386                     
387                     printf("ERROR (%d)\n", ret);
388                     
389                     for (j = 0; j < i; j++) {
390                         FILE * block_file = NULL;
391                         char fname[256];
392                         
393                         memset(fname, 0, 256);
394                         
395                         snprintf(fname, 256, "%smemory%d/state", SYS_PATH, j + reg_start);
396                         
397                         block_file = fopen(fname, "r+");
398                         
399                         if (block_file == NULL) {
400                             perror("Could not open block file");
401                             return -1;
402                         }
403                         
404                         fprintf(block_file, "online\n");
405                         
406                         fclose(block_file);
407                     }
408                     
409                     break;
410                 } 
411                 
412                 printf("OK\n");
413                 
414             }
415             
416             
417         }
418     }
419     
420     free(bitmap);
421     
422     /* Memory is offlined. Calculate size and phys start addr to send to Palacios */
423     *num_bytes = (unsigned long long)(num_blocks) * (unsigned long long)(block_size_bytes);
424     *base_addr = (unsigned long long)(reg_start) * (unsigned long long)(block_size_bytes);
425
426     return 0;
427 }
428