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