debuggers.hg

view tools/libxl/libxl_dom.c @ 20647:2c6a04fdf8fb

libxenlight: implement libxl_set_memory_target

This patch adds a target_memkb parameter to libxl_domain_build_info to
set the target memory for the VM at build time and a new function
called libxl_set_memory_target to dynamically modify the memory target
of a VM at run time. Finally a new command "mem-set" is added to xl
that calls directly libxl_set_memory_target.

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Dec 09 10:44:11 2009 +0000 (2009-12-09)
parents e0351b16a747
children 9575425fdebd
line source
1 /*
2 * Copyright (C) 2009 Citrix Ltd.
3 * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as published
7 * by the Free Software Foundation; version 2.1 only. with the special
8 * exception on linking described in file LICENSE.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 */
16 #include "libxl_osdeps.h"
18 #include <stdio.h>
19 #include <inttypes.h>
20 #include <string.h>
21 #include <sys/time.h> /* for struct timeval */
22 #include <unistd.h> /* for sleep(2) */
24 #include <xenctrl.h>
25 #include <xc_dom.h>
26 #include <xenguest.h>
28 #include "libxl.h"
29 #include "libxl_internal.h"
31 int is_hvm(struct libxl_ctx *ctx, uint32_t domid)
32 {
33 xc_domaininfo_t info;
34 int ret;
36 ret = xc_domain_getinfolist(ctx->xch, domid, 1, &info);
37 if (ret != 1)
38 return -1;
39 if (info.domain != domid)
40 return -1;
41 return !!(info.flags & XEN_DOMINF_hvm_guest);
42 }
44 int build_pre(struct libxl_ctx *ctx, uint32_t domid,
45 libxl_domain_build_info *info, libxl_domain_build_state *state)
46 {
47 if (info->timer_mode != -1)
48 xc_set_hvm_param(ctx->xch, domid, HVM_PARAM_TIMER_MODE,
49 (unsigned long) info->timer_mode);
50 if (info->hpet != -1)
51 xc_set_hvm_param(ctx->xch, domid, HVM_PARAM_HPET_ENABLED, (unsigned long) info->hpet);
52 if (info->vpt_align != -1)
53 xc_set_hvm_param(ctx->xch, domid, HVM_PARAM_VPT_ALIGN, (unsigned long) info->vpt_align);
54 xc_domain_max_vcpus(ctx->xch, domid, info->max_vcpus);
55 xc_domain_setmaxmem(ctx->xch, domid, info->target_memkb + LIBXL_MAXMEM_CONSTANT);
56 xc_domain_set_memmap_limit(ctx->xch, domid,
57 (info->hvm) ? info->max_memkb :
58 (info->max_memkb + info->u.pv.slack_memkb));
60 if (info->hvm) {
61 unsigned long shadow;
62 shadow = (info->shadow_memkb + 1023) / 1024;
63 xc_shadow_control(ctx->xch, domid, XEN_DOMCTL_SHADOW_OP_SET_ALLOCATION, NULL, 0, &shadow, 0, NULL);
64 }
66 state->store_port = xc_evtchn_alloc_unbound(ctx->xch, domid, 0);
67 state->console_port = xc_evtchn_alloc_unbound(ctx->xch, domid, 0);
68 return 0;
69 }
71 int build_post(struct libxl_ctx *ctx, uint32_t domid,
72 libxl_domain_build_info *info, libxl_domain_build_state *state,
73 char **vms_ents, char **local_ents)
74 {
75 char *dom_path, *vm_path;
76 xs_transaction_t t;
77 char **ents;
78 int i;
80 ents = libxl_calloc(ctx, (10 + info->max_vcpus) * 2, sizeof(char *));
81 ents[0] = "memory/static-max";
82 ents[1] = libxl_sprintf(ctx, "%d", info->max_memkb);
83 ents[2] = "memory/target";
84 ents[3] = libxl_sprintf(ctx, "%d", info->target_memkb);
85 ents[2] = "memory/videoram";
86 ents[3] = libxl_sprintf(ctx, "%d", info->video_memkb);
87 ents[4] = "domid";
88 ents[5] = libxl_sprintf(ctx, "%d", domid);
89 ents[6] = "store/port";
90 ents[7] = libxl_sprintf(ctx, "%"PRIu32, state->store_port);
91 ents[8] = "store/ring-ref";
92 ents[9] = libxl_sprintf(ctx, "%lu", state->store_mfn);
93 for (i = 0; i < info->max_vcpus; i++) {
94 ents[10+(i*2)] = libxl_sprintf(ctx, "cpu/%d/availability", i);
95 ents[10+(i*2)+1] = (i && info->cur_vcpus && (i >= info->cur_vcpus))
96 ? "offline" : "online";
97 }
99 dom_path = libxl_xs_get_dompath(ctx, domid);
100 if (!dom_path)
101 return ERROR_FAIL;
103 vm_path = xs_read(ctx->xsh, XBT_NULL, libxl_sprintf(ctx, "%s/vm", dom_path), NULL);
104 retry_transaction:
105 t = xs_transaction_start(ctx->xsh);
107 libxl_xs_writev(ctx, t, dom_path, ents);
108 libxl_xs_writev(ctx, t, dom_path, local_ents);
109 libxl_xs_writev(ctx, t, vm_path, vms_ents);
111 if (!xs_transaction_end(ctx->xsh, t, 0))
112 if (errno == EAGAIN)
113 goto retry_transaction;
114 xs_introduce_domain(ctx->xsh, domid, state->store_mfn, state->store_port);
115 free(vm_path);
116 libxl_free(ctx, ents);
117 libxl_free(ctx, dom_path);
118 return 0;
119 }
121 int build_pv(struct libxl_ctx *ctx, uint32_t domid,
122 libxl_domain_build_info *info, libxl_domain_build_state *state)
123 {
124 struct xc_dom_image *dom;
125 int ret;
126 int flags = 0;
128 dom = xc_dom_allocate(info->u.pv.cmdline, info->u.pv.features);
129 if (!dom) {
130 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xc_dom_allocate failed");
131 return -1;
132 }
133 if ((ret = xc_dom_linux_build(ctx->xch, dom, domid, info->max_memkb / 1024,
134 info->kernel, info->u.pv.ramdisk, flags,
135 state->store_port, &state->store_mfn,
136 state->console_port, &state->console_mfn)) != 0) {
137 xc_dom_release(dom);
138 XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, ret, "xc_dom_linux_build failed");
139 return -2;
140 }
141 xc_dom_release(dom);
142 return 0;
143 }
145 int build_hvm(struct libxl_ctx *ctx, uint32_t domid,
146 libxl_domain_build_info *info, libxl_domain_build_state *state)
147 {
148 int ret;
150 ret = xc_hvm_build_target_mem(ctx->xch, domid, (info->max_memkb - info->video_memkb) / 1024, (info->target_memkb - info->video_memkb) / 1024, info->kernel);
151 if (ret) {
152 XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, ret, "hvm building failed");
153 return ERROR_FAIL;
154 }
155 ret = hvm_build_set_params(ctx->xch, domid, info->u.hvm.apic, info->u.hvm.acpi,
156 info->u.hvm.pae, info->u.hvm.nx, info->u.hvm.viridian,
157 info->max_vcpus,
158 state->store_port, &state->store_mfn);
159 if (ret) {
160 XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, ret, "hvm build set params failed");
161 return ERROR_FAIL;
162 }
163 #if defined(__i386__) || defined(__x86_64__)
164 xc_cpuid_apply_policy(ctx->xch, domid);
165 #endif
166 return 0;
167 }
169 int restore_common(struct libxl_ctx *ctx, uint32_t domid,
170 libxl_domain_build_info *info, libxl_domain_build_state *state,
171 int fd)
172 {
173 /* read signature */
174 xc_domain_restore(ctx->xch, fd, domid,
175 state->store_port, &state->store_mfn,
176 state->console_port, &state->console_mfn,
177 info->hvm, info->u.hvm.pae, 0);
178 #if defined(__i386__) || defined(__x86_64__)
179 xc_cpuid_apply_policy(ctx->xch, domid);
180 #endif
181 return 0;
182 }
184 struct suspendinfo {
185 struct libxl_ctx *ctx;
186 int xce; /* event channel handle */
187 int suspend_eventchn;
188 int domid;
189 int hvm;
190 unsigned int flags;
191 };
193 static void core_suspend_switch_qemu_logdirty(int domid, unsigned int enable)
194 {
195 struct xs_handle *xsh;
196 char path[64];
198 snprintf(path, sizeof(path), "/local/domain/0/device-model/%u/logdirty/cmd", domid);
200 xsh = xs_daemon_open();
202 if (enable)
203 xs_write(xsh, XBT_NULL, path, "enable", strlen("enable"));
204 else
205 xs_write(xsh, XBT_NULL, path, "disable", strlen("disable"));
207 xs_daemon_close(xsh);
208 }
210 static int core_suspend_callback(void *data)
211 {
212 struct suspendinfo *si = data;
213 unsigned long s_state = 0;
214 int ret;
215 char *path, *state = "suspend";
216 int watchdog = 60;
218 if (si->hvm)
219 xc_get_hvm_param(si->ctx->xch, si->domid, HVM_PARAM_ACPI_S_STATE, &s_state);
220 if ((s_state == 0) && (si->suspend_eventchn >= 0)) {
221 ret = xc_evtchn_notify(si->xce, si->suspend_eventchn);
222 if (ret < 0) {
223 XL_LOG(si->ctx, XL_LOG_ERROR, "xc_evtchn_notify failed ret=%d", ret);
224 return 0;
225 }
226 ret = xc_await_suspend(si->xce, si->suspend_eventchn);
227 if (ret < 0) {
228 XL_LOG(si->ctx, XL_LOG_ERROR, "xc_await_suspend failed ret=%d", ret);
229 return 0;
230 }
231 return 1;
232 }
233 path = libxl_sprintf(si->ctx, "%s/control/shutdown", libxl_xs_get_dompath(si->ctx, si->domid));
234 libxl_xs_write(si->ctx, XBT_NULL, path, "suspend", strlen("suspend"));
235 if (si->hvm) {
236 unsigned long hvm_pvdrv, hvm_s_state;
237 xc_get_hvm_param(si->ctx->xch, si->domid, HVM_PARAM_CALLBACK_IRQ, &hvm_pvdrv);
238 xc_get_hvm_param(si->ctx->xch, si->domid, HVM_PARAM_ACPI_S_STATE, &hvm_s_state);
239 if (!hvm_pvdrv || hvm_s_state) {
240 XL_LOG(si->ctx, XL_LOG_DEBUG, "Calling xc_domain_shutdown on the domain");
241 xc_domain_shutdown(si->ctx->xch, si->domid, SHUTDOWN_suspend);
242 }
243 }
244 XL_LOG(si->ctx, XL_LOG_DEBUG, "wait for the guest to suspend");
245 while (!strcmp(state, "suspend") && watchdog > 0) {
246 int nb_domain, i;
247 xc_dominfo_t *list = NULL;
248 usleep(100000);
249 list = libxl_domain_infolist(si->ctx, &nb_domain);
250 for (i = 0; i < nb_domain; i++) {
251 if (si->domid == list[i].domid) {
252 if (list[i].shutdown != 0 && list[i].shutdown_reason == SHUTDOWN_suspend) {
253 free(list);
254 return 1;
255 }
256 }
257 }
258 free(list);
259 state = libxl_xs_read(si->ctx, XBT_NULL, path);
260 watchdog--;
261 }
262 if (!strcmp(state, "suspend")) {
263 XL_LOG(si->ctx, XL_LOG_ERROR, "guest didn't suspend in time");
264 libxl_xs_write(si->ctx, XBT_NULL, path, "", 1);
265 }
266 return 1;
267 }
269 int core_suspend(struct libxl_ctx *ctx, uint32_t domid, int fd,
270 int hvm, int live, int debug)
271 {
272 int flags;
273 int port;
274 struct save_callbacks callbacks;
275 struct suspendinfo si;
277 flags = (live) ? XCFLAGS_LIVE : 0
278 | (debug) ? XCFLAGS_DEBUG : 0
279 | (hvm) ? XCFLAGS_HVM : 0;
281 si.domid = domid;
282 si.flags = flags;
283 si.hvm = hvm;
284 si.ctx = ctx;
285 si.suspend_eventchn = -1;
287 si.xce = xc_evtchn_open();
288 if (si.xce < 0)
289 return -1;
291 if (si.xce > 0) {
292 port = xs_suspend_evtchn_port(si.domid);
294 if (port < 0) {
295 XL_LOG(ctx, XL_LOG_WARNING, "Failed to get the suspend evtchn port");
296 } else {
297 si.suspend_eventchn = xc_suspend_evtchn_init(si.ctx->xch, si.xce, si.domid, port);
299 if (si.suspend_eventchn < 0)
300 XL_LOG(ctx, XL_LOG_WARNING, "Suspend event channel initialization failed");
301 }
302 }
304 memset(&callbacks, 0, sizeof(callbacks));
305 callbacks.suspend = core_suspend_callback;
306 callbacks.data = &si;
308 xc_domain_save(ctx->xch, fd, domid, 0, 0, flags,
309 &callbacks, hvm,
310 &core_suspend_switch_qemu_logdirty);
312 if (si.suspend_eventchn > 0)
313 xc_suspend_evtchn_release(si.xce, si.suspend_eventchn);
314 if (si.xce > 0)
315 xc_evtchn_close(si.xce);
317 return 0;
318 }