1 #include <stdlib.h>
2 #include <string.h>
3 #include <unistd.h>
4 #include <xenevtchn.h>
5 #include <xenctrl.h>
6 #include <xenguest.h>
7 #include <xenstore.h>
8 #include <xen-tools/common-macros.h>
9
10 static xc_interface *xch;
11
show_help(void)12 void show_help(void)
13 {
14 fprintf(stderr,
15 "xen-hptool: Xen CPU/memory hotplug tool\n"
16 "Usage: xen-hptool <command> [args]\n"
17 "Commands:\n"
18 " help display this help\n"
19 " cpu-online <cpuid> online CPU <cpuid>\n"
20 " cpu-offline <cpuid> offline CPU <cpuid>\n"
21 " mem-online <mfn> online MEMORY <mfn>\n"
22 " mem-offline <mfn> offline MEMORY <mfn>\n"
23 " mem-status <mfn> query Memory status<mfn>\n"
24 " smt-enable onlines all SMT threads\n"
25 " smt-disable offlines all SMT threads\n"
26 );
27 }
28
29 /* wrapper function */
help_func(int argc,char * argv[])30 static int help_func(int argc, char *argv[])
31 {
32 show_help();
33 return 0;
34 }
35
hp_mem_online_func(int argc,char * argv[])36 static int hp_mem_online_func(int argc, char *argv[])
37 {
38 uint32_t status;
39 int ret;
40 unsigned long mfn;
41
42 if (argc != 1)
43 {
44 show_help();
45 return -1;
46 }
47
48 sscanf(argv[0], "%lx", &mfn);
49 printf("Prepare to online MEMORY mfn %lx\n", mfn);
50
51 ret = xc_mark_page_online(xch, mfn, mfn, &status);
52
53 if (ret < 0)
54 fprintf(stderr, "Onlining page mfn %lx failed, error %x", mfn, errno);
55 else if (status & (PG_ONLINE_FAILED |PG_ONLINE_BROKEN)) {
56 fprintf(stderr, "Onlining page mfn %lx is broken, "
57 "Memory online failed\n", mfn);
58 ret = -1;
59 }
60 else if (status & PG_ONLINE_ONLINED)
61 printf("Memory mfn %lx onlined successfully\n", mfn);
62 else
63 printf("Memory is already onlined!\n");
64
65 return ret;
66 }
67
hp_mem_query_func(int argc,char * argv[])68 static int hp_mem_query_func(int argc, char *argv[])
69 {
70 uint32_t status;
71 int ret;
72 unsigned long mfn;
73
74 if (argc != 1)
75 {
76 show_help();
77 return -1;
78 }
79
80 sscanf(argv[0], "%lx", &mfn);
81 printf("Querying MEMORY mfn %lx status\n", mfn);
82 ret = xc_query_page_offline_status(xch, mfn, mfn, &status);
83
84 if (ret < 0)
85 fprintf(stderr, "Querying page mfn %lx failed, error %x", mfn, errno);
86 else
87 {
88 printf("Memory Status %x: [", status);
89 if ( status & PG_OFFLINE_STATUS_OFFLINE_PENDING)
90 printf(" PAGE_OFFLINE_PENDING ");
91 if ( status & PG_OFFLINE_STATUS_BROKEN )
92 printf(" PAGE_BROKEND ");
93 if ( status & PG_OFFLINE_STATUS_OFFLINED )
94 printf(" PAGE_OFFLINED ");
95 else
96 printf(" PAGE_ONLINED ");
97 printf("]\n");
98 }
99
100 return ret;
101 }
102
suspend_guest(xc_interface * xch,xenevtchn_handle * xce,int domid,int * evtchn,int * lockfd)103 static int suspend_guest(xc_interface *xch, xenevtchn_handle *xce, int domid,
104 int *evtchn, int *lockfd)
105 {
106 int port, rc, suspend_evtchn = -1;
107
108 *lockfd = -1;
109
110 if (!evtchn)
111 return -1;
112
113 port = xs_suspend_evtchn_port(domid);
114 if (port < 0)
115 {
116 fprintf(stderr, "DOM%d: No suspend port, try live migration\n", domid);
117 goto failed;
118 }
119 suspend_evtchn = xc_suspend_evtchn_init_exclusive(xch, xce, domid,
120 port, lockfd);
121 if (suspend_evtchn < 0)
122 {
123 fprintf(stderr, "Suspend evtchn initialization failed\n");
124 goto failed;
125 }
126 *evtchn = suspend_evtchn;
127
128 rc = xenevtchn_notify(xce, suspend_evtchn);
129 if (rc < 0)
130 {
131 fprintf(stderr, "Failed to notify suspend channel: errno %d\n", rc);
132 goto failed;
133 }
134 if (xc_await_suspend(xch, xce, suspend_evtchn) < 0)
135 {
136 fprintf(stderr, "Suspend Failed\n");
137 goto failed;
138 }
139 return 0;
140
141 failed:
142 if (suspend_evtchn != -1)
143 xc_suspend_evtchn_release(xch, xce, domid,
144 suspend_evtchn, lockfd);
145
146 return -1;
147 }
148
hp_mem_offline_func(int argc,char * argv[])149 static int hp_mem_offline_func(int argc, char *argv[])
150 {
151 uint32_t status, domid;
152 int ret;
153 unsigned long mfn;
154
155 if (argc != 1)
156 {
157 show_help();
158 return -1;
159 }
160
161 sscanf(argv[0], "%lx", &mfn);
162 printf("Prepare to offline MEMORY mfn %lx\n", mfn);
163 ret = xc_mark_page_offline(xch, mfn, mfn, &status);
164 if (ret < 0) {
165 fprintf(stderr, "Offlining page mfn %lx failed, error %x\n", mfn, errno);
166 if (status & (PG_OFFLINE_XENPAGE | PG_OFFLINE_FAILED))
167 fprintf(stderr, "XEN_PAGE is not permitted be offlined\n");
168 else if (status & (PG_OFFLINE_FAILED | PG_OFFLINE_NOT_CONV_RAM))
169 fprintf(stderr, "RESERVED RAM is not permitted to be offlined\n");
170 }
171 else
172 {
173 switch(status & PG_OFFLINE_STATUS_MASK)
174 {
175 case PG_OFFLINE_OFFLINED:
176 {
177 printf("Memory mfn %lx offlined successfully, current state is"
178 " [PG_OFFLINE_OFFLINED]\n", mfn);
179 if (status & PG_OFFLINE_BROKEN)
180 printf("And this offlined PAGE is already marked broken"
181 " before!\n");
182 break;
183 }
184 case PG_OFFLINE_FAILED:
185 {
186 fprintf(stderr, "Memory mfn %lx offline failed\n", mfn);
187 if ( status & PG_OFFLINE_ANONYMOUS)
188 fprintf(stderr, "the memory is an anonymous page!\n");
189 ret = -1;
190 break;
191 }
192 case PG_OFFLINE_PENDING:
193 {
194 if (status & PG_OFFLINE_XENPAGE) {
195 ret = -1;
196 fprintf(stderr, "Memory mfn %lx offlined succssefully,"
197 "this page is xen page, current state is"
198 " [PG_OFFLINE_PENDING, PG_OFFLINE_XENPAGE]\n", mfn);
199 }
200 else if (status & PG_OFFLINE_OWNED)
201 {
202 int result, suspend_evtchn = -1, suspend_lockfd = -1;
203 xenevtchn_handle *xce;
204 xce = xenevtchn_open(NULL, 0);
205
206 if (xce == NULL)
207 {
208 fprintf(stderr, "When exchange page, fail"
209 " to open evtchn\n");
210 return -1;
211 }
212
213 domid = status >> PG_OFFLINE_OWNER_SHIFT;
214 if (suspend_guest(xch, xce, domid,
215 &suspend_evtchn, &suspend_lockfd))
216 {
217 fprintf(stderr, "Failed to suspend guest %d for"
218 " mfn %lx\n", domid, mfn);
219 xenevtchn_close(xce);
220 return -1;
221 }
222
223 result = xc_exchange_page(xch, domid, mfn);
224
225 /* Exchange page successfully */
226 if (result == 0)
227 printf("Memory mfn %lx offlined successfully, this "
228 "page is DOM%d page and being swapped "
229 "successfully, current state is "
230 "[PG_OFFLINE_OFFLINED, PG_OFFLINE_OWNED]\n",
231 mfn, domid);
232 else {
233 ret = -1;
234 fprintf(stderr, "Memory mfn %lx offlined successfully"
235 " , this page is DOM%d page yet failed to be "
236 "exchanged. current state is "
237 "[PG_OFFLINE_PENDING, PG_OFFLINE_OWNED]\n",
238 mfn, domid);
239 }
240 xc_domain_resume(xch, domid, 1);
241 xc_suspend_evtchn_release(xch, xce, domid,
242 suspend_evtchn, &suspend_lockfd);
243 xenevtchn_close(xce);
244 }
245 break;
246 }
247 }//end of switch
248 }//end of if
249
250 return ret;
251 }
252
exec_cpu_hp_fn(int (* hp_fn)(xc_interface *,int),int cpu)253 static int exec_cpu_hp_fn(int (*hp_fn)(xc_interface *, int), int cpu)
254 {
255 int ret;
256
257 for ( ; ; )
258 {
259 ret = (*hp_fn)(xch, cpu);
260 if ( (ret >= 0) || (errno != EBUSY) )
261 break;
262 usleep(100000); /* 100ms */
263 }
264
265 return ret;
266 }
267
hp_cpu_online_func(int argc,char * argv[])268 static int hp_cpu_online_func(int argc, char *argv[])
269 {
270 int cpu, ret;
271
272 if ( argc != 1 )
273 {
274 show_help();
275 return -1;
276 }
277
278 cpu = atoi(argv[0]);
279 printf("Prepare to online CPU %d\n", cpu);
280 ret = exec_cpu_hp_fn(xc_cpu_online, cpu);
281 if (ret < 0)
282 fprintf(stderr, "CPU %d online failed (error %d: %s)\n",
283 cpu, errno, strerror(errno));
284 else
285 printf("CPU %d onlined successfully\n", cpu);
286
287 return ret;
288
289 }
hp_cpu_offline_func(int argc,char * argv[])290 static int hp_cpu_offline_func(int argc, char *argv[])
291 {
292 int cpu, ret;
293
294 if (argc != 1 )
295 {
296 show_help();
297 return -1;
298 }
299 cpu = atoi(argv[0]);
300 printf("Prepare to offline CPU %d\n", cpu);
301 ret = exec_cpu_hp_fn(xc_cpu_offline, cpu);
302 if (ret < 0)
303 fprintf(stderr, "CPU %d offline failed (error %d: %s)\n",
304 cpu, errno, strerror(errno));
305 else
306 printf("CPU %d offlined successfully\n", cpu);
307
308 return ret;
309 }
310
main_smt_enable(int argc,char * argv[])311 static int main_smt_enable(int argc, char *argv[])
312 {
313 int ret;
314
315 if ( argc )
316 {
317 show_help();
318 return -1;
319 }
320
321 for ( ;; )
322 {
323 ret = xc_smt_enable(xch);
324 if ( (ret >= 0) || (errno != EBUSY) )
325 break;
326 }
327
328 if ( ret < 0 )
329 fprintf(stderr, "Unable to enable SMT: errno %d, %s\n",
330 errno, strerror(errno));
331 else
332 printf("Enabled SMT\n");
333
334 return ret;
335 }
336
main_smt_disable(int argc,char * argv[])337 static int main_smt_disable(int argc, char *argv[])
338 {
339 int ret;
340
341 if ( argc )
342 {
343 show_help();
344 return -1;
345 }
346
347 for ( ;; )
348 {
349 ret = xc_smt_disable(xch);
350 if ( (ret >= 0) || (errno != EBUSY) )
351 break;
352 }
353
354 if ( ret < 0 )
355 fprintf(stderr, "Unable to disable SMT: errno %d, %s\n",
356 errno, strerror(errno));
357 else
358 printf("Disabled SMT\n");
359
360 return ret;
361 }
362
363 struct {
364 const char *name;
365 int (*function)(int argc, char *argv[]);
366 } main_options[] = {
367 { "help", help_func },
368 { "cpu-online", hp_cpu_online_func },
369 { "cpu-offline", hp_cpu_offline_func },
370 { "mem-status", hp_mem_query_func},
371 { "mem-online", hp_mem_online_func},
372 { "mem-offline", hp_mem_offline_func},
373 { "smt-enable", main_smt_enable },
374 { "smt-disable", main_smt_disable },
375 };
376
377
main(int argc,char * argv[])378 int main(int argc, char *argv[])
379 {
380 int i, ret;
381
382 if (argc < 2)
383 {
384 show_help();
385 return 0;
386 }
387
388 xch = xc_interface_open(0,0,0);
389 if ( !xch )
390 {
391 fprintf(stderr, "failed to get the handler\n");
392 return 0;
393 }
394
395 for ( i = 0; i < ARRAY_SIZE(main_options); i++ )
396 if (!strncmp(main_options[i].name, argv[1], strlen(argv[1])))
397 break;
398 if ( i == ARRAY_SIZE(main_options) )
399 {
400 fprintf(stderr, "Unrecognised command '%s' -- try "
401 "'xen-hptool help'\n", argv[1]);
402 return 1;
403 }
404
405 ret = main_options[i].function(argc -2, argv + 2);
406
407 xc_interface_close(xch);
408
409 return !!ret;
410 }
411