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.


Paranoid error checking in userspace utils
[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 int dir_filter(const struct dirent * dir) {
24     if (strncmp("memory", dir->d_name, 6) == 0) {
25         return 1;
26     }
27
28     return 0;
29 }
30
31
32
33 int dir_cmp(const void * d1, const void * d2) {
34     const struct dirent ** dir1 = (const struct dirent **)d1;
35     const struct dirent ** dir2 = (const struct dirent **)d2;
36     int num1 = atoi((*dir1)->d_name + 6);
37     int num2 = atoi((*dir2)->d_name + 6);
38
39     return num1 - num2;
40 }
41
42
43
44 int main(int argc, char * argv[]) {
45     unsigned long long mem_size_bytes = 0;
46     unsigned int block_size_bytes = 0;
47     int bitmap_entries = 0;
48     unsigned char * bitmap = NULL;
49     int num_blocks = 0;    
50     int reg_start = 0;
51     int mem_ready = 0;
52
53     if (argc != 2) {
54         printf("usage: v3_mem <memory size (MB)>\n");
55         return -1;
56     }
57
58
59     mem_size_bytes = atoll(argv[1]) * (1024 * 1024);
60
61     printf("Trying to find %dMB (%d bytes) of memory\n", atoll(argv[1]), mem_size_bytes);
62
63     /* Figure out the block size */
64     {
65         int tmp_fd = 0;
66         char tmp_buf[BUF_SIZE];
67
68         tmp_fd = open(SYS_PATH "block_size_bytes", O_RDONLY);
69
70         if (tmp_fd == -1) {
71             perror("Could not open block size file: " SYS_PATH "block_size_bytes");
72             return -1;
73         }
74         
75         if (read(tmp_fd, tmp_buf, BUF_SIZE) <= 0) {
76             perror("Could not read block size file: " SYS_PATH "block_size_bytes");
77             return -1;
78         }
79         
80         close(tmp_fd);
81
82         block_size_bytes = strtoll(tmp_buf, NULL, 16);
83
84         printf("Memory block size is %dMB (%d bytes)\n", block_size_bytes / (1024 * 1024), block_size_bytes);
85     }
86     
87
88     num_blocks =  mem_size_bytes / block_size_bytes;
89     if (mem_size_bytes % block_size_bytes) num_blocks++;
90
91     printf("Looking for %d blocks of memory\n", num_blocks);
92
93
94     // We now need to find <num_blocks> consecutive offlinable memory blocks
95
96     /* Scan the memory directories */
97     {
98         struct dirent ** namelist = NULL;
99         int size = 0;
100         int i = 0;
101         int j = 0;
102         int last_block = 0;
103
104         last_block = scandir(SYS_PATH, &namelist, dir_filter, dir_cmp);
105         bitmap_entries = atoi(namelist[last_block - 1]->d_name + 6) + 1;
106
107         size = bitmap_entries / 8;
108         if (bitmap_entries % 8) size++;
109
110         bitmap = malloc(size);
111     if (!bitmap) {
112             printf("ERROR: could not allocate space for bitmap\n");
113             return -1;
114     }
115
116         memset(bitmap, 0, size);
117
118         for (i = 0; j < bitmap_entries - 1; i++) {
119             struct dirent * tmp_dir = namelist[i];
120             int block_fd = 0;       
121             char status_str[BUF_SIZE];
122             char fname[BUF_SIZE];
123
124             memset(status_str, 0, BUF_SIZE);
125             memset(fname, 0, BUF_SIZE);
126
127             snprintf(fname, BUF_SIZE, "%s%s/removable", SYS_PATH, tmp_dir->d_name);
128
129             j = atoi(tmp_dir->d_name + 6);
130             int major = j / 8;
131             int minor = j % 8;
132
133             printf("Checking %s...", fname);
134
135             block_fd = open(fname, O_RDONLY);
136             
137             if (block_fd == -1) {
138                 printf("Hotpluggable memory not supported...\n");
139                 return -1;
140             }
141
142             if (read(block_fd, status_str, BUF_SIZE) <= 0) {
143                 perror("Could not read block status");
144                 return -1;
145             }
146
147             close(block_fd);
148             
149             if (atoi(status_str) == 1) {
150                 printf("Removable\n");
151                 bitmap[major] |= (0x1 << minor);
152             } else {
153                 printf("Not removable\n");
154             }
155         }
156
157     }
158     
159     while (!mem_ready) {
160
161
162         /* Scan bitmap for enough consecutive space */
163         {
164             // num_blocks: The number of blocks we need to find
165             // bitmap: bitmap of blocks (1 == allocatable)
166             // bitmap_entries: number of blocks in the system/number of bits in bitmap
167             // reg_start: The block index where our allocation will start
168             
169             int i = 0;
170             int run_len = 0;
171             
172             for (i = 0; i < bitmap_entries; i++) {
173                 int i_major = i / 8;
174                 int i_minor = i % 8;
175             
176                 if (!(bitmap[i_major] & (0x1 << i_minor))) {
177                     reg_start = i + 1; // skip the region start to next entry
178                     run_len = 0;
179                     continue;
180                 }
181             
182                 run_len++;
183
184                 if (run_len >= num_blocks) {
185                     break;
186                 }
187             }
188
189             
190             if (run_len < num_blocks) {
191                 fprintf(stderr, "Could not find enough consecutive memory blocks... (found %d)\n", run_len);
192                 return -1;
193             }
194         }
195     
196
197         /* Offline memory blocks starting at reg_start */
198         {
199             int i = 0;
200
201             for (i = 0; i < num_blocks; i++) {  
202                 FILE * block_file = NULL;
203                 char fname[256];
204
205                 memset(fname, 0, 256);
206
207                 snprintf(fname, 256, "%smemory%d/state", SYS_PATH, i + reg_start);
208                 
209                 block_file = fopen(fname, "r+");
210
211                 if (block_file == NULL) {
212                     perror("Could not open block file");
213                     return -1;
214                 }
215
216
217                 printf("Offlining block %d (%s)\n", i + reg_start, fname);
218                 fprintf(block_file, "offline\n");
219
220                 fclose(block_file);
221             }
222         }
223
224
225         /*  We asked to offline set of blocks, but Linux could have lied. 
226          *  To be safe, check whether blocks were offlined and start again if not 
227          */
228
229         {
230             int i = 0;
231
232             mem_ready = 1; // Hopefully we are ok...
233
234
235             for (i = 0; i < num_blocks; i++) {
236                 int block_fd = 0;
237                 char fname[BUF_SIZE];
238                 char status_buf[BUF_SIZE];
239
240
241                 memset(fname, 0, BUF_SIZE);
242                 memset(status_buf, 0, BUF_SIZE);
243
244                 snprintf(fname, BUF_SIZE, "%smemory%d/state", SYS_PATH, i + reg_start);
245
246                 
247                 block_fd = open(fname, O_RDONLY);
248                 
249                 if (block_fd == -1) {
250                     perror("Could not open block file");
251                     return -1;
252                 }
253                 
254                 if (read(block_fd, status_buf, BUF_SIZE) <= 0) {
255                     perror("Could not read block status");
256                     return -1;
257                 }
258
259                 printf("Checking offlined block %d (%s)...", i + reg_start, fname);
260
261                 int ret = strncmp(status_buf, "offline", strlen("offline"));
262
263                 if (ret != 0) {
264                     int j = 0;
265                     int major = (i + reg_start) / 8;
266                     int minor = (i + reg_start) % 8;
267
268                     bitmap[major] &= ~(0x1 << minor); // mark the block as not removable in bitmap
269
270                     mem_ready = 0; // Keep searching
271
272                     printf("ERROR (%d)\n", ret);
273
274                     for (j = 0; j < i; j++) {
275                         FILE * block_file = NULL;
276                         char fname[256];
277                         
278                         memset(fname, 0, 256);
279                         
280                         snprintf(fname, 256, "%smemory%d/state", SYS_PATH, j + reg_start);
281                         
282                         block_file = fopen(fname, "r+");
283                         
284                         if (block_file == NULL) {
285                             perror("Could not open block file");
286                             return -1;
287                         }
288
289                         fprintf(block_file, "online\n");
290                         
291                         fclose(block_file);
292                     }
293
294                     break;
295                 } 
296                 
297                 printf("OK\n");
298                 
299             }
300             
301             
302         }
303     }
304
305     free(bitmap);
306
307     /* Memory is offlined. Calculate size and phys start addr to send to Palacios */
308
309     {
310         int v3_fd = 0;
311         struct v3_mem_region mem;
312         unsigned long long num_bytes = (unsigned long long)(num_blocks) * (unsigned long long)(block_size_bytes);
313         unsigned long long base_addr = (unsigned long long)(reg_start) * (unsigned long long)(block_size_bytes);
314
315         printf("Giving Palacios %lluMB of memory at (%p) \n", 
316                num_bytes / (1024 * 1024), base_addr);
317
318         mem.base_addr = base_addr;
319         mem.num_pages = num_bytes / 4096;
320
321         v3_fd = open(v3_dev, O_RDONLY);
322
323         if (v3_fd == -1) {
324             printf("Error opening V3Vee control device\n");
325             return -1;
326         }
327
328         ioctl(v3_fd, V3_ADD_MEMORY, &mem); 
329
330         /* Close the file descriptor.  */ 
331         close(v3_fd);   
332     }
333
334     return 0; 
335