debuggers.hg

view tools/libxl/libxl_device.c @ 20637:91555131e235

libxenlight: implement cdrom insert/eject

This patch implements functions in libxenlight to change the cdrom in
a VM at run time and to handle cdrom eject requests from guests.

This patch adds two new commands to xl: cd-insert and cd-eject; it
also modifies xl to handle cdrom eject requests coming from guests
(actually coming from qemu).

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Dec 08 07:47:52 2009 +0000 (2009-12-08)
parents 696f94dfad26
children 9417aa2c7380
line source
1 /*
2 * Copyright (C) 2009 Citrix Ltd.
3 * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
4 * Author Stefano Stabellini <stefano.stabellini@eu.citrix.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published
8 * by the Free Software Foundation; version 2.1 only. with the special
9 * exception on linking described in file LICENSE.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 */
17 #include "libxl_osdeps.h"
19 #include <string.h>
20 #include <stdio.h>
21 #include <sys/time.h> /* for struct timeval */
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <unistd.h>
26 #include "libxl.h"
27 #include "libxl_internal.h"
29 const char *string_of_kinds[] = {
30 [DEVICE_VIF] = "vif",
31 [DEVICE_VBD] = "vbd",
32 [DEVICE_TAP] = "tap",
33 [DEVICE_PCI] = "pci",
34 [DEVICE_VFB] = "vfb",
35 [DEVICE_VKBD] = "vkbd",
36 [DEVICE_CONSOLE] = "console",
37 };
39 int libxl_device_generic_add(struct libxl_ctx *ctx, libxl_device *device,
40 char **bents, char **fents)
41 {
42 char *dom_path_backend, *dom_path, *frontend_path, *backend_path, *hotplug_path;
43 xs_transaction_t t;
44 struct xs_permissions frontend_perms[2];
45 struct xs_permissions backend_perms[2];
46 struct xs_permissions hotplug_perms[1];
48 dom_path_backend = libxl_xs_get_dompath(ctx, device->backend_domid);
49 dom_path = libxl_xs_get_dompath(ctx, device->domid);
51 frontend_path = libxl_sprintf(ctx, "%s/device/%s/%d",
52 dom_path, string_of_kinds[device->kind], device->devid);
53 backend_path = libxl_sprintf(ctx, "%s/backend/%s/%u/%d",
54 dom_path_backend, string_of_kinds[device->backend_kind], device->domid, device->devid);
55 hotplug_path = libxl_sprintf(ctx, "/xapi/%d/hotplug/%s/%d",
56 device->domid, string_of_kinds[device->kind], device->devid);
58 frontend_perms[0].id = device->domid;
59 frontend_perms[0].perms = XS_PERM_NONE;
60 frontend_perms[1].id = device->backend_domid;
61 frontend_perms[1].perms = XS_PERM_READ;
63 backend_perms[0].id = device->backend_domid;
64 backend_perms[0].perms = XS_PERM_NONE;
65 backend_perms[1].id = device->domid;
66 backend_perms[1].perms = XS_PERM_READ;
68 hotplug_perms[0].id = device->backend_domid;
69 hotplug_perms[0].perms = XS_PERM_NONE;
71 retry_transaction:
72 t = xs_transaction_start(ctx->xsh);
73 /* FIXME: read frontend_path and check state before removing stuff */
75 xs_rm(ctx->xsh, t, frontend_path);
76 xs_rm(ctx->xsh, t, backend_path);
78 xs_mkdir(ctx->xsh, t, frontend_path);
79 xs_set_permissions(ctx->xsh, t, frontend_path, frontend_perms, ARRAY_SIZE(frontend_perms));
81 xs_mkdir(ctx->xsh, t, backend_path);
82 xs_set_permissions(ctx->xsh, t, backend_path, backend_perms, ARRAY_SIZE(backend_perms));
84 xs_mkdir(ctx->xsh, t, hotplug_path);
85 xs_set_permissions(ctx->xsh, t, hotplug_path, hotplug_perms, ARRAY_SIZE(hotplug_perms));
87 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/backend", frontend_path), backend_path, strlen(backend_path));
88 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/frontend", backend_path), frontend_path, strlen(frontend_path));
90 /* and write frontend kvs and backend kvs */
91 libxl_xs_writev(ctx, t, backend_path, bents);
92 libxl_xs_writev(ctx, t, frontend_path, fents);
94 if (!xs_transaction_end(ctx->xsh, t, 0)) {
95 if (errno == EAGAIN)
96 goto retry_transaction;
97 else
98 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xs transaction failed");
99 }
100 return 0;
101 }
103 char *device_disk_string_of_phystype(libxl_disk_phystype phystype)
104 {
105 switch (phystype) {
106 case PHYSTYPE_QCOW: return "qcow";
107 case PHYSTYPE_QCOW2: return "qcow2";
108 case PHYSTYPE_VHD: return "vhd";
109 case PHYSTYPE_AIO: return "aio";
110 case PHYSTYPE_FILE: return "file";
111 case PHYSTYPE_PHY: return "phy";
112 default: return NULL;
113 }
114 }
116 char *device_disk_backend_type_of_phystype(libxl_disk_phystype phystype)
117 {
118 switch (phystype) {
119 case PHYSTYPE_QCOW: return "tap";
120 case PHYSTYPE_VHD: return "tap";
121 case PHYSTYPE_AIO: return "tap";
122 /* let's pretend file is tap:aio */
123 case PHYSTYPE_FILE: return "tap";
124 case PHYSTYPE_PHY: return "phy";
125 default: return NULL;
126 }
127 }
129 int device_physdisk_major_minor(char *physpath, int *major, int *minor)
130 {
131 struct stat buf;
132 if (stat(physpath, &buf) < 0)
133 return -1;
134 *major = major(buf.st_rdev);
135 *minor = minor(buf.st_rdev);
136 return 0;
137 }
139 int device_virtdisk_major_minor(char *virtpath, int *major, int *minor)
140 {
141 if (strstr(virtpath, "sd") == virtpath) {
142 return -1;
143 } else if (strstr(virtpath, "xvd") == virtpath) {
144 return -1;
145 } else if (strstr(virtpath, "hd") == virtpath) {
146 char letter, letter2;
148 *major = 0; *minor = 0;
149 letter = virtpath[2];
150 if (letter < 'a' || letter > 't')
151 return -1;
152 letter2 = virtpath[3];
154 *major = letter - 'a';
155 *minor = atoi(virtpath + 3);
156 return 0;
157 } else {
158 return -1;
159 }
160 }
162 int device_disk_dev_number(char *virtpath)
163 {
164 int majors_table[] = { 3, 22, 33, 34, 56, 57, 88, 89, 90, 91 };
165 int major, minor;
167 if (strstr(virtpath, "hd") == virtpath) {
168 if (device_virtdisk_major_minor(virtpath, &major, &minor))
169 return -1;
170 return majors_table[major / 2] * 256 + (64 * (major % 2)) + minor;
171 } else if (strstr(virtpath, "xvd") == virtpath) {
172 return (202 << 8) + ((virtpath[3] - 'a') << 4) + (virtpath[4] ? (virtpath[4] - '0') : 0);
173 }
174 return -1;
175 }
177 int libxl_device_destroy(struct libxl_ctx *ctx, char *be_path, int force)
178 {
179 xs_transaction_t t;
180 char *state_path = libxl_sprintf(ctx, "%s/state", be_path);
181 char *state = libxl_xs_read(ctx, XBT_NULL, state_path);
182 if (!state)
183 return 0;
184 if (atoi(state) != 4) {
185 xs_rm(ctx->xsh, XBT_NULL, be_path);
186 return 0;
187 }
189 retry_transaction:
190 t = xs_transaction_start(ctx->xsh);
191 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/online", be_path), "0", strlen("0"));
192 xs_write(ctx->xsh, t, state_path, "5", strlen("5"));
193 if (!xs_transaction_end(ctx->xsh, t, 0)) {
194 if (errno == EAGAIN)
195 goto retry_transaction;
196 else
197 return -1;
198 }
199 if (!force) {
200 xs_watch(ctx->xsh, state_path, be_path);
201 return 1;
202 } else
203 return 0;
204 }
206 int wait_for_dev_destroy(struct libxl_ctx *ctx, struct timeval *tv)
207 {
208 int nfds, rc;
209 unsigned int n;
210 fd_set rfds;
211 char **l1 = NULL;
213 rc = 1;
214 nfds = xs_fileno(ctx->xsh) + 1;
215 FD_ZERO(&rfds);
216 FD_SET(xs_fileno(ctx->xsh), &rfds);
217 if (select(nfds, &rfds, NULL, NULL, tv) > 0) {
218 l1 = xs_read_watch(ctx->xsh, &n);
219 if (l1 != NULL) {
220 char *state = libxl_xs_read(ctx, XBT_NULL, l1[XS_WATCH_PATH]);
221 if (!state || atoi(state) == 6) {
222 xs_unwatch(ctx->xsh, l1[0], l1[1]);
223 xs_rm(ctx->xsh, XBT_NULL, l1[XS_WATCH_TOKEN]);
224 XL_LOG(ctx, XL_LOG_DEBUG, "Destroyed device backend at %s", l1[XS_WATCH_TOKEN]);
225 rc = 0;
226 }
227 libxl_free(ctx, state);
228 free(l1);
229 }
230 }
231 return rc;
232 }
234 int libxl_devices_destroy(struct libxl_ctx *ctx, uint32_t domid, int force)
235 {
236 char *path, *be_path, *fe_path;
237 unsigned int num1, num2;
238 char **l1 = NULL, **l2 = NULL;
239 int i, j, n = 0, n_watches = 0;
240 flexarray_t *toremove;
241 struct libxl_ctx clone;
243 if (libxl_clone_context_xs(ctx, &clone)) {
244 XL_LOG(ctx, XL_LOG_ERROR, "Out of memory when cloning context");
245 return ERROR_NOMEM;
246 }
248 toremove = flexarray_make(16, 1);
249 path = libxl_sprintf(&clone, "/local/domain/%d/device", domid);
250 l1 = libxl_xs_directory(&clone, XBT_NULL, path, &num1);
251 if (!l1) {
252 XL_LOG(&clone, XL_LOG_ERROR, "%s is empty", path);
253 libxl_discard_cloned_context_xs(&clone);
254 return -1;
255 }
256 for (i = 0; i < num1; i++) {
257 if (!strcmp("vfs", l1[i]))
258 continue;
259 path = libxl_sprintf(&clone, "/local/domain/%d/device/%s", domid, l1[i]);
260 l2 = libxl_xs_directory(&clone, XBT_NULL, path, &num2);
261 if (!l2)
262 continue;
263 for (j = 0; j < num2; j++) {
264 fe_path = libxl_sprintf(&clone, "/local/domain/%d/device/%s/%s", domid, l1[i], l2[j]);
265 be_path = libxl_xs_read(&clone, XBT_NULL, libxl_sprintf(&clone, "%s/backend", fe_path));
266 if (be_path != NULL) {
267 if (libxl_device_destroy(&clone, be_path, force) > 0)
268 n_watches++;
269 flexarray_set(toremove, n++, libxl_dirname(&clone, be_path));
270 } else {
271 xs_rm(clone.xsh, XBT_NULL, path);
272 }
273 }
274 }
275 if (!force) {
276 /* Linux-ism. Most implementations leave the timeout
277 * untouched after select. Linux, however, will chip
278 * away the elapsed time from it, which is what we
279 * need to enforce a single time span waiting for
280 * device destruction. */
281 struct timeval tv;
282 tv.tv_sec = LIBXL_DESTROY_TIMEOUT;
283 tv.tv_usec = 0;
284 while (n_watches > 0) {
285 if (wait_for_dev_destroy(&clone, &tv)) {
286 break;
287 } else {
288 n_watches--;
289 }
290 }
291 }
292 for (i = 0; i < n; i++) {
293 flexarray_get(toremove, i, (void**) &path);
294 xs_rm(clone.xsh, XBT_NULL, path);
295 }
296 flexarray_free(toremove);
297 libxl_discard_cloned_context_xs(&clone);
298 return 0;
299 }
301 int libxl_device_del(struct libxl_ctx *ctx, libxl_device *dev, int wait)
302 {
303 char *dom_path_backend, *backend_path, *hotplug_path;
304 int rc;
305 struct libxl_ctx clone;
307 if (libxl_clone_context_xs(ctx, &clone)) {
308 XL_LOG(ctx, XL_LOG_ERROR, "Out of memory when cloning context");
309 return ERROR_NOMEM;
310 }
312 /* Create strings */
313 dom_path_backend = libxl_xs_get_dompath(&clone, dev->backend_domid);
314 backend_path = libxl_sprintf(&clone, "%s/backend/%s/%u/%d",
315 dom_path_backend,
316 string_of_kinds[dev->backend_kind],
317 dev->domid, dev->devid);
318 hotplug_path = libxl_sprintf(&clone, "/xapi/%d/hotplug/%s/%d",
319 dev->domid,
320 string_of_kinds[dev->kind],
321 dev->devid);
322 libxl_free(&clone, dom_path_backend);
324 rc = libxl_device_destroy(&clone, backend_path, !wait);
325 if (rc == -1) {
326 libxl_discard_cloned_context_xs(&clone);
327 return ERROR_FAIL;
328 }
330 if (wait) {
331 struct timeval tv;
332 tv.tv_sec = LIBXL_DESTROY_TIMEOUT;
333 tv.tv_usec = 0;
334 (void)wait_for_dev_destroy(&clone, &tv);
335 }
337 xs_rm(clone.xsh, XBT_NULL, hotplug_path);
338 libxl_free(&clone, hotplug_path);
339 libxl_free(&clone, backend_path);
340 libxl_discard_cloned_context_xs(&clone);
341 return 0;
342 }
344 int libxl_device_pci_flr(struct libxl_ctx *ctx, unsigned int domain, unsigned int bus,
345 unsigned int dev, unsigned int func)
346 {
347 char *do_flr= "/sys/bus/pci/drivers/pciback/do_flr";
348 FILE *fd;
350 fd = fopen(do_flr, "w");
351 if (fd != NULL) {
352 fprintf(fd, PCI_BDF, domain, bus, dev, func);
353 fclose(fd);
354 return 0;
355 }
356 if (errno == ENOENT) {
357 XL_LOG(ctx, XL_LOG_ERROR, "Pciback doesn't support do_flr, cannot flr the device");
358 } else {
359 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "Failed to access pciback path %s", do_flr);
360 }
361 return -1;
362 }
364 int libxl_wait_for_device_model(struct libxl_ctx *ctx,
365 uint32_t domid, char *state,
366 int (*check_callback)(struct libxl_ctx *ctx,
367 void *userdata),
368 void *check_callback_userdata)
369 {
370 char path[50];
371 char *p;
372 unsigned int len;
373 int rc;
374 struct xs_handle *xsh;
375 int nfds;
376 fd_set rfds;
377 struct timeval tv;
378 unsigned int num;
379 char **l = NULL;
381 xsh = xs_daemon_open();
382 snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/state", domid);
383 xs_watch(xsh, path, path);
384 tv.tv_sec = LIBXL_DEVICE_MODEL_START_TIMEOUT;
385 tv.tv_usec = 0;
386 nfds = xs_fileno(xsh) + 1;
387 while (tv.tv_sec > 0) {
388 FD_ZERO(&rfds);
389 FD_SET(xs_fileno(xsh), &rfds);
390 if (select(nfds, &rfds, NULL, NULL, &tv) > 0) {
391 l = xs_read_watch(xsh, &num);
392 if (l != NULL) {
393 free(l);
394 p = xs_read(xsh, XBT_NULL, path, &len);
395 if (!p)
396 continue;
397 if (!state || !strcmp(state, p)) {
398 free(p);
399 xs_unwatch(xsh, path, path);
400 xs_daemon_close(xsh);
401 if (check_callback) {
402 rc = check_callback(ctx, check_callback_userdata);
403 if (rc) return rc;
404 }
405 return 0;
406 }
407 free(p);
408 }
409 }
410 }
411 xs_unwatch(xsh, path, path);
412 xs_daemon_close(xsh);
413 XL_LOG(ctx, XL_LOG_ERROR, "Device Model not ready");
414 return -1;
415 }
417 int libxl_wait_for_backend(struct libxl_ctx *ctx, char *be_path, char *state)
418 {
419 int watchdog = 100;
420 unsigned int len;
421 char *p;
422 char *path = libxl_sprintf(ctx, "%s/state", be_path);
424 while (watchdog > 0) {
425 p = xs_read(ctx->xsh, XBT_NULL, path, &len);
426 if (p == NULL) {
427 if (errno == ENOENT) {
428 XL_LOG(ctx, XL_LOG_ERROR, "Backend %s does not exist",
429 be_path);
430 } else {
431 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "Failed to access backend %s",
432 be_path);
433 }
434 return -1;
435 } else {
436 if (!strcmp(p, state)) {
437 return 0;
438 } else {
439 usleep(100000);
440 watchdog--;
441 }
442 }
443 }
444 XL_LOG(ctx, XL_LOG_ERROR, "Backend %s not ready", be_path);
445 return -1;
446 }