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