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.


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