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.


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