debuggers.hg

view tools/libxl/libxl_device.c @ 21067:b4a1832a916f

Update Xen version to 4.0.0-rc6
author Keir Fraser <keir.fraser@citrix.com>
date Tue Mar 09 18:18:05 2010 +0000 (2010-03-09)
parents bdce1894c6a7
children 117c79b7066d
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 static 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 if (!is_valid_device_kind(device->backend_kind) || !is_valid_device_kind(device->kind))
49 return ERROR_INVAL;
51 dom_path_backend = libxl_xs_get_dompath(ctx, device->backend_domid);
52 dom_path = libxl_xs_get_dompath(ctx, device->domid);
54 frontend_path = libxl_sprintf(ctx, "%s/device/%s/%d",
55 dom_path, string_of_kinds[device->kind], device->devid);
56 backend_path = libxl_sprintf(ctx, "%s/backend/%s/%u/%d",
57 dom_path_backend, string_of_kinds[device->backend_kind], device->domid, device->devid);
58 hotplug_path = libxl_sprintf(ctx, "/xapi/%d/hotplug/%s/%d",
59 device->domid, string_of_kinds[device->kind], device->devid);
61 frontend_perms[0].id = device->domid;
62 frontend_perms[0].perms = XS_PERM_NONE;
63 frontend_perms[1].id = device->backend_domid;
64 frontend_perms[1].perms = XS_PERM_READ;
66 backend_perms[0].id = device->backend_domid;
67 backend_perms[0].perms = XS_PERM_NONE;
68 backend_perms[1].id = device->domid;
69 backend_perms[1].perms = XS_PERM_READ;
71 hotplug_perms[0].id = device->backend_domid;
72 hotplug_perms[0].perms = XS_PERM_NONE;
74 retry_transaction:
75 t = xs_transaction_start(ctx->xsh);
76 /* FIXME: read frontend_path and check state before removing stuff */
78 xs_rm(ctx->xsh, t, frontend_path);
79 xs_rm(ctx->xsh, t, backend_path);
81 xs_mkdir(ctx->xsh, t, frontend_path);
82 xs_set_permissions(ctx->xsh, t, frontend_path, frontend_perms, ARRAY_SIZE(frontend_perms));
84 xs_mkdir(ctx->xsh, t, backend_path);
85 xs_set_permissions(ctx->xsh, t, backend_path, backend_perms, ARRAY_SIZE(backend_perms));
87 xs_mkdir(ctx->xsh, t, hotplug_path);
88 xs_set_permissions(ctx->xsh, t, hotplug_path, hotplug_perms, ARRAY_SIZE(hotplug_perms));
90 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/backend", frontend_path), backend_path, strlen(backend_path));
91 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/frontend", backend_path), frontend_path, strlen(frontend_path));
93 /* and write frontend kvs and backend kvs */
94 libxl_xs_writev(ctx, t, backend_path, bents);
95 libxl_xs_writev(ctx, t, frontend_path, fents);
97 if (!xs_transaction_end(ctx->xsh, t, 0)) {
98 if (errno == EAGAIN)
99 goto retry_transaction;
100 else
101 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xs transaction failed");
102 }
103 return 0;
104 }
106 char *device_disk_string_of_phystype(libxl_disk_phystype phystype)
107 {
108 switch (phystype) {
109 case PHYSTYPE_QCOW: return "qcow";
110 case PHYSTYPE_QCOW2: return "qcow2";
111 case PHYSTYPE_VHD: return "vhd";
112 case PHYSTYPE_AIO: return "aio";
113 case PHYSTYPE_FILE: return "file";
114 case PHYSTYPE_PHY: return "phy";
115 default: return NULL;
116 }
117 }
119 char *device_disk_backend_type_of_phystype(libxl_disk_phystype phystype)
120 {
121 switch (phystype) {
122 case PHYSTYPE_QCOW: return "tap";
123 case PHYSTYPE_VHD: return "tap";
124 case PHYSTYPE_AIO: return "tap";
125 /* let's pretend file is tap:aio */
126 case PHYSTYPE_FILE: return "tap";
127 case PHYSTYPE_PHY: return "phy";
128 default: return NULL;
129 }
130 }
132 int device_physdisk_major_minor(char *physpath, int *major, int *minor)
133 {
134 struct stat buf;
135 if (stat(physpath, &buf) < 0)
136 return -1;
137 *major = major(buf.st_rdev);
138 *minor = minor(buf.st_rdev);
139 return 0;
140 }
142 static int device_virtdisk_matches(const char *virtpath, const char *devtype,
143 int *index_r, int max_index,
144 int *partition_r, int max_partition) {
145 const char *p;
146 char *ep;
147 int tl, c;
148 long pl;
150 tl = strlen(devtype);
151 if (memcmp(virtpath, devtype, tl))
152 return 0;
154 /* We decode the drive letter as if it were in base 52
155 * with digits a-zA-Z, more or less */
156 *index_r = -1;
157 p = virtpath + tl;
158 for (;;) {
159 c = *p++;
160 if (c >= 'a' && c <= 'z') {
161 c -= 'a';
162 } else {
163 --p;
164 break;
165 }
166 (*index_r)++;
167 (*index_r) *= 26;
168 (*index_r) += c;
170 if (*index_r > max_index)
171 return 0;
172 }
174 if (!*p) {
175 *partition_r = 0;
176 return 1;
177 }
179 if (*p=='0')
180 return 0; /* leading zeroes not permitted in partition number */
182 pl = strtoul(p, &ep, 10);
183 if (pl > max_partition || *ep)
184 return 0;
186 *partition_r = pl;
187 return 1;
188 }
190 int device_disk_dev_number(char *virtpath)
191 {
192 int disk, partition;
193 char *ep;
194 unsigned long ul;
195 int chrused;
197 chrused = -1;
198 if ((sscanf(virtpath, "d%ip%i%n", &disk, &partition, &chrused) >= 2
199 && chrused == strlen(virtpath) && disk < (1<<20) && partition < 256)
200 ||
201 device_virtdisk_matches(virtpath, "xvd",
202 &disk, (1<<20)-1,
203 &partition, 255)) {
204 if (disk <= 15 && partition <= 15)
205 return (202 << 8) | (disk << 4) | partition;
206 else
207 return (1 << 28) | (disk << 8) | partition;
208 }
210 errno = 0;
211 ul = strtoul(virtpath, &ep, 0);
212 if (!errno && !*ep && ul <= INT_MAX)
213 return ul;
215 if (device_virtdisk_matches(virtpath, "hd",
216 &disk, 3,
217 &partition, 63)) {
218 return ((disk<2 ? 3 : 22) << 8) | ((disk & 1) << 6) | partition;
219 }
220 if (device_virtdisk_matches(virtpath, "sd",
221 &disk, 15,
222 &partition, 15)) {
223 return (8 << 8) | (disk << 4) | partition;
224 }
225 return -1;
226 }
228 int libxl_device_destroy(struct libxl_ctx *ctx, char *be_path, int force)
229 {
230 xs_transaction_t t;
231 char *state_path = libxl_sprintf(ctx, "%s/state", be_path);
232 char *state = libxl_xs_read(ctx, XBT_NULL, state_path);
233 if (!state)
234 return 0;
235 if (atoi(state) != 4) {
236 xs_rm(ctx->xsh, XBT_NULL, be_path);
237 return 0;
238 }
240 retry_transaction:
241 t = xs_transaction_start(ctx->xsh);
242 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/online", be_path), "0", strlen("0"));
243 xs_write(ctx->xsh, t, state_path, "5", strlen("5"));
244 if (!xs_transaction_end(ctx->xsh, t, 0)) {
245 if (errno == EAGAIN)
246 goto retry_transaction;
247 else
248 return -1;
249 }
250 if (!force) {
251 xs_watch(ctx->xsh, state_path, be_path);
252 return 1;
253 } else
254 return 0;
255 }
257 int wait_for_dev_destroy(struct libxl_ctx *ctx, struct timeval *tv)
258 {
259 int nfds, rc;
260 unsigned int n;
261 fd_set rfds;
262 char **l1 = NULL;
264 rc = 1;
265 nfds = xs_fileno(ctx->xsh) + 1;
266 FD_ZERO(&rfds);
267 FD_SET(xs_fileno(ctx->xsh), &rfds);
268 if (select(nfds, &rfds, NULL, NULL, tv) > 0) {
269 l1 = xs_read_watch(ctx->xsh, &n);
270 if (l1 != NULL) {
271 char *state = libxl_xs_read(ctx, XBT_NULL, l1[XS_WATCH_PATH]);
272 if (!state || atoi(state) == 6) {
273 xs_unwatch(ctx->xsh, l1[0], l1[1]);
274 xs_rm(ctx->xsh, XBT_NULL, l1[XS_WATCH_TOKEN]);
275 XL_LOG(ctx, XL_LOG_DEBUG, "Destroyed device backend at %s", l1[XS_WATCH_TOKEN]);
276 rc = 0;
277 }
278 libxl_free(ctx, state);
279 free(l1);
280 }
281 }
282 return rc;
283 }
285 int libxl_devices_destroy(struct libxl_ctx *ctx, uint32_t domid, int force)
286 {
287 char *path, *be_path, *fe_path;
288 unsigned int num1, num2;
289 char **l1 = NULL, **l2 = NULL;
290 int i, j, n = 0, n_watches = 0;
291 flexarray_t *toremove;
292 struct libxl_ctx clone;
294 if (libxl_ctx_init(&clone, LIBXL_VERSION)) {
295 return -1;
296 }
298 toremove = flexarray_make(16, 1);
299 path = libxl_sprintf(&clone, "/local/domain/%d/device", domid);
300 l1 = libxl_xs_directory(&clone, XBT_NULL, path, &num1);
301 if (!l1) {
302 XL_LOG(&clone, XL_LOG_ERROR, "%s is empty", path);
303 libxl_ctx_free(&clone);
304 return -1;
305 }
306 for (i = 0; i < num1; i++) {
307 if (!strcmp("vfs", l1[i]))
308 continue;
309 path = libxl_sprintf(&clone, "/local/domain/%d/device/%s", domid, l1[i]);
310 l2 = libxl_xs_directory(&clone, XBT_NULL, path, &num2);
311 if (!l2)
312 continue;
313 for (j = 0; j < num2; j++) {
314 fe_path = libxl_sprintf(&clone, "/local/domain/%d/device/%s/%s", domid, l1[i], l2[j]);
315 be_path = libxl_xs_read(&clone, XBT_NULL, libxl_sprintf(&clone, "%s/backend", fe_path));
316 if (be_path != NULL) {
317 if (libxl_device_destroy(&clone, be_path, force) > 0)
318 n_watches++;
319 flexarray_set(toremove, n++, libxl_dirname(&clone, be_path));
320 } else {
321 xs_rm(clone.xsh, XBT_NULL, path);
322 }
323 }
324 }
325 if (!force) {
326 /* Linux-ism. Most implementations leave the timeout
327 * untouched after select. Linux, however, will chip
328 * away the elapsed time from it, which is what we
329 * need to enforce a single time span waiting for
330 * device destruction. */
331 struct timeval tv;
332 tv.tv_sec = LIBXL_DESTROY_TIMEOUT;
333 tv.tv_usec = 0;
334 while (n_watches > 0) {
335 if (wait_for_dev_destroy(&clone, &tv)) {
336 break;
337 } else {
338 n_watches--;
339 }
340 }
341 }
342 for (i = 0; i < n; i++) {
343 flexarray_get(toremove, i, (void**) &path);
344 xs_rm(clone.xsh, XBT_NULL, path);
345 }
346 flexarray_free(toremove);
347 libxl_ctx_free(&clone);
348 return 0;
349 }
351 int libxl_device_del(struct libxl_ctx *ctx, libxl_device *dev, int wait)
352 {
353 char *dom_path_backend, *backend_path, *hotplug_path;
354 int rc;
355 struct libxl_ctx clone;
357 if (libxl_ctx_init(&clone, LIBXL_VERSION)) {
358 return -1;
359 }
361 /* Create strings */
362 dom_path_backend = libxl_xs_get_dompath(&clone, dev->backend_domid);
363 backend_path = libxl_sprintf(&clone, "%s/backend/%s/%u/%d",
364 dom_path_backend,
365 string_of_kinds[dev->backend_kind],
366 dev->domid, dev->devid);
367 hotplug_path = libxl_sprintf(&clone, "/xapi/%d/hotplug/%s/%d",
368 dev->domid,
369 string_of_kinds[dev->kind],
370 dev->devid);
371 libxl_free(&clone, dom_path_backend);
373 rc = libxl_device_destroy(&clone, backend_path, !wait);
374 if (rc == -1) {
375 libxl_ctx_free(&clone);
376 return ERROR_FAIL;
377 }
379 if (wait) {
380 struct timeval tv;
381 tv.tv_sec = LIBXL_DESTROY_TIMEOUT;
382 tv.tv_usec = 0;
383 (void)wait_for_dev_destroy(&clone, &tv);
384 }
386 xs_rm(clone.xsh, XBT_NULL, hotplug_path);
387 libxl_ctx_free(&clone);
388 return 0;
389 }
391 int libxl_device_pci_flr(struct libxl_ctx *ctx, unsigned int domain, unsigned int bus,
392 unsigned int dev, unsigned int func)
393 {
394 char *do_flr = "/sys/bus/pci/drivers/pciback/do_flr";
395 FILE *fd;
397 fd = fopen(do_flr, "w");
398 if (fd != NULL) {
399 fprintf(fd, PCI_BDF, domain, bus, dev, func);
400 fclose(fd);
401 return 0;
402 }
403 if (errno == ENOENT) {
404 XL_LOG(ctx, XL_LOG_ERROR, "Pciback doesn't support do_flr, cannot flr the device");
405 } else {
406 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "Failed to access pciback path %s", do_flr);
407 }
408 return -1;
409 }
411 int libxl_wait_for_device_model(struct libxl_ctx *ctx,
412 uint32_t domid, char *state,
413 int (*check_callback)(struct libxl_ctx *ctx,
414 void *userdata),
415 void *check_callback_userdata)
416 {
417 char *path;
418 char *p;
419 unsigned int len;
420 int rc;
421 struct xs_handle *xsh;
422 int nfds;
423 fd_set rfds;
424 struct timeval tv;
425 unsigned int num;
426 char **l = NULL;
428 xsh = xs_daemon_open();
429 path = libxl_sprintf(ctx, "/local/domain/0/device-model/%d/state", domid);
430 xs_watch(xsh, path, path);
431 tv.tv_sec = LIBXL_DEVICE_MODEL_START_TIMEOUT;
432 tv.tv_usec = 0;
433 nfds = xs_fileno(xsh) + 1;
434 while (tv.tv_sec > 0) {
435 FD_ZERO(&rfds);
436 FD_SET(xs_fileno(xsh), &rfds);
437 if (select(nfds, &rfds, NULL, NULL, &tv) > 0) {
438 l = xs_read_watch(xsh, &num);
439 if (l != NULL) {
440 free(l);
441 p = xs_read(xsh, XBT_NULL, path, &len);
442 if (!p)
443 continue;
444 if (!state || !strcmp(state, p)) {
445 free(p);
446 xs_unwatch(xsh, path, path);
447 xs_daemon_close(xsh);
448 if (check_callback) {
449 rc = check_callback(ctx, check_callback_userdata);
450 if (rc) return rc;
451 }
452 return 0;
453 }
454 free(p);
455 }
456 }
457 }
458 xs_unwatch(xsh, path, path);
459 xs_daemon_close(xsh);
460 XL_LOG(ctx, XL_LOG_ERROR, "Device Model not ready");
461 return -1;
462 }
464 int libxl_wait_for_backend(struct libxl_ctx *ctx, char *be_path, char *state)
465 {
466 int watchdog = 100;
467 unsigned int len;
468 char *p;
469 char *path = libxl_sprintf(ctx, "%s/state", be_path);
471 while (watchdog > 0) {
472 p = xs_read(ctx->xsh, XBT_NULL, path, &len);
473 if (p == NULL) {
474 if (errno == ENOENT) {
475 XL_LOG(ctx, XL_LOG_ERROR, "Backend %s does not exist",
476 be_path);
477 } else {
478 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "Failed to access backend %s",
479 be_path);
480 }
481 return -1;
482 } else {
483 if (!strcmp(p, state)) {
484 return 0;
485 } else {
486 usleep(100000);
487 watchdog--;
488 }
489 }
490 }
491 XL_LOG(ctx, XL_LOG_ERROR, "Backend %s not ready", be_path);
492 return -1;
493 }