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 */
16
17 #include "libxl_osdeps.h" /* must come before any other headers */
18
19 #include "libxl_internal.h"
20
libxl__device_frontend_path(libxl__gc * gc,libxl__device * device)21 static char *libxl__device_frontend_path(libxl__gc *gc, libxl__device *device)
22 {
23 char *dom_path = libxl__xs_get_dompath(gc, device->domid);
24
25 /* Console 0 is a special case */
26 if (device->kind == LIBXL__DEVICE_KIND_CONSOLE && device->devid == 0)
27 return GCSPRINTF("%s/console", dom_path);
28
29 if (device->kind == LIBXL__DEVICE_KIND_VUART)
30 return GCSPRINTF("%s/vuart/%d", dom_path, device->devid);
31
32 return GCSPRINTF("%s/device/%s/%d", dom_path,
33 libxl__device_kind_to_string(device->kind),
34 device->devid);
35 }
36
libxl__device_backend_path(libxl__gc * gc,libxl__device * device)37 char *libxl__device_backend_path(libxl__gc *gc, libxl__device *device)
38 {
39 char *dom_path = libxl__xs_get_dompath(gc, device->backend_domid);
40
41 return GCSPRINTF("%s/backend/%s/%u/%d", dom_path,
42 libxl__device_kind_to_string(device->backend_kind),
43 device->domid, device->devid);
44 }
45
libxl__device_libxl_path(libxl__gc * gc,libxl__device * device)46 char *libxl__device_libxl_path(libxl__gc *gc, libxl__device *device)
47 {
48 char *libxl_dom_path = libxl__xs_libxl_path(gc, device->domid);
49
50 return GCSPRINTF("%s/device/%s/%d", libxl_dom_path,
51 libxl__device_kind_to_string(device->kind),
52 device->devid);
53 }
54
55 /* Returns 1 if device exists, 0 if not, ERROR_* (<0) on error. */
libxl__device_exists(libxl__gc * gc,xs_transaction_t t,libxl__device * device)56 int libxl__device_exists(libxl__gc *gc, xs_transaction_t t,
57 libxl__device *device)
58 {
59 int rc;
60 char *be_path = libxl__device_libxl_path(gc, device);
61 const char *dir;
62
63 rc = libxl__xs_read_checked(gc, t, be_path, &dir);
64
65 if (rc)
66 return rc;
67
68 if (dir)
69 return 1;
70 return 0;
71 }
72
libxl__parse_backend_path(libxl__gc * gc,const char * path,libxl__device * dev)73 int libxl__parse_backend_path(libxl__gc *gc,
74 const char *path,
75 libxl__device *dev)
76 {
77 /* /local/domain/<domid>/backend/<kind>/<domid>/<devid> */
78 char strkind[16]; /* Longest is actually "console" */
79 int rc = sscanf(path, "/local/domain/%d/backend/%15[^/]/%u/%d",
80 &dev->backend_domid,
81 strkind,
82 &dev->domid,
83 &dev->devid);
84
85 if (rc != 4)
86 return ERROR_FAIL;
87
88 return libxl__device_kind_from_string(strkind, &dev->backend_kind);
89 }
90
libxl__nic_type(libxl__gc * gc,libxl__device * dev,libxl_nic_type * nictype)91 int libxl__nic_type(libxl__gc *gc, libxl__device *dev, libxl_nic_type *nictype)
92 {
93 char *snictype, *be_path;
94 int rc = 0;
95
96 be_path = libxl__device_backend_path(gc, dev);
97 snictype = libxl__xs_read(gc, XBT_NULL,
98 GCSPRINTF("%s/%s", be_path, "type"));
99 if (!snictype) {
100 LOGED(ERROR, dev->domid, "unable to read nictype from %s", be_path);
101 rc = ERROR_FAIL;
102 goto out;
103 }
104 rc = libxl_nic_type_from_string(snictype, nictype);
105 if (rc) {
106 LOGED(ERROR, dev->domid, "unable to parse nictype from %s", be_path);
107 goto out;
108 }
109
110 rc = 0;
111
112 out:
113 return rc;
114 }
115
libxl__device_generic_add(libxl__gc * gc,xs_transaction_t t,libxl__device * device,char ** bents,char ** fents,char ** ro_fents)116 int libxl__device_generic_add(libxl__gc *gc, xs_transaction_t t,
117 libxl__device *device, char **bents, char **fents, char **ro_fents)
118 {
119 libxl_ctx *ctx = libxl__gc_owner(gc);
120 char *frontend_path = NULL, *backend_path = NULL, *libxl_path;
121 struct xs_permissions frontend_perms[2];
122 struct xs_permissions ro_frontend_perms[2];
123 struct xs_permissions backend_perms[2];
124 int create_transaction = t == XBT_NULL;
125 int libxl_only = device->backend_kind == LIBXL__DEVICE_KIND_NONE;
126 int rc;
127
128 if (libxl_only) {
129 /* bents should be set as this is used to setup libxl_path content. */
130 assert(!fents && !ro_fents);
131 } else {
132 frontend_path = libxl__device_frontend_path(gc, device);
133 backend_path = libxl__device_backend_path(gc, device);
134 }
135 libxl_path = libxl__device_libxl_path(gc, device);
136
137 frontend_perms[0].id = device->domid;
138 frontend_perms[0].perms = XS_PERM_NONE;
139 frontend_perms[1].id = device->backend_domid;
140 frontend_perms[1].perms = XS_PERM_READ;
141
142 ro_frontend_perms[0].id = backend_perms[0].id = device->backend_domid;
143 ro_frontend_perms[0].perms = backend_perms[0].perms = XS_PERM_NONE;
144 ro_frontend_perms[1].id = backend_perms[1].id = device->domid;
145 ro_frontend_perms[1].perms = backend_perms[1].perms = XS_PERM_READ;
146
147 retry_transaction:
148 if (create_transaction)
149 t = xs_transaction_start(ctx->xsh);
150
151 /* FIXME: read frontend_path and check state before removing stuff */
152
153 rc = libxl__xs_rm_checked(gc, t, libxl_path);
154 if (rc) goto out;
155
156 if (!libxl_only) {
157 rc = libxl__xs_write_checked(gc, t, GCSPRINTF("%s/frontend",libxl_path),
158 frontend_path);
159 if (rc) goto out;
160
161 rc = libxl__xs_write_checked(gc, t, GCSPRINTF("%s/backend",libxl_path),
162 backend_path);
163 if (rc) goto out;
164 }
165
166 /* xxx much of this function lacks error checks! */
167
168 if (fents || ro_fents) {
169 xs_rm(ctx->xsh, t, frontend_path);
170 xs_mkdir(ctx->xsh, t, frontend_path);
171 /* Console 0 is a special case. It doesn't use the regular PV
172 * state machine but also the frontend directory has
173 * historically contained other information, such as the
174 * vnc-port, which we don't want the guest fiddling with.
175 */
176 if ((device->kind == LIBXL__DEVICE_KIND_CONSOLE && device->devid == 0) ||
177 (device->kind == LIBXL__DEVICE_KIND_VUART))
178 xs_set_permissions(ctx->xsh, t, frontend_path,
179 ro_frontend_perms, ARRAY_SIZE(ro_frontend_perms));
180 else
181 xs_set_permissions(ctx->xsh, t, frontend_path,
182 frontend_perms, ARRAY_SIZE(frontend_perms));
183 xs_write(ctx->xsh, t, GCSPRINTF("%s/backend", frontend_path),
184 backend_path, strlen(backend_path));
185 if (fents)
186 libxl__xs_writev_perms(gc, t, frontend_path, fents,
187 frontend_perms, ARRAY_SIZE(frontend_perms));
188 if (ro_fents)
189 libxl__xs_writev_perms(gc, t, frontend_path, ro_fents,
190 ro_frontend_perms, ARRAY_SIZE(ro_frontend_perms));
191 }
192
193 if (bents) {
194 if (!libxl_only) {
195 xs_rm(ctx->xsh, t, backend_path);
196 xs_mkdir(ctx->xsh, t, backend_path);
197 xs_set_permissions(ctx->xsh, t, backend_path, backend_perms,
198 ARRAY_SIZE(backend_perms));
199 xs_write(ctx->xsh, t, GCSPRINTF("%s/frontend", backend_path),
200 frontend_path, strlen(frontend_path));
201 libxl__xs_writev(gc, t, backend_path, bents);
202 }
203
204 /*
205 * We make a copy of everything for the backend in the libxl
206 * path as well. This means we don't need to trust the
207 * backend. Ideally this information would not be used and we
208 * would use the information from the json configuration
209 * instead. But there are still places in libxl that try to
210 * reconstruct a config from xenstore.
211 *
212 * For devices without PV backend (e.g. USB devices emulated via qemu)
213 * only the libxl path is written.
214 *
215 * This duplication will typically produces duplicate keys
216 * which will go out of date, but that's OK because nothing
217 * reads those. For example, there is usually
218 * /libxl/$guest/device/$kind/$devid/state
219 * which starts out containing XenbusStateInitialising ("1")
220 * just like the copy in
221 * /local/domain/$driverdom/backend/$guest/$kind/$devid/state
222 * but which won't ever be updated.
223 *
224 * This duplication is superfluous and messy but as discussed
225 * the proper fix is more intrusive than we want to do now.
226 */
227 rc = libxl__xs_writev(gc, t, libxl_path, bents);
228 if (rc) goto out;
229 }
230
231 if (!create_transaction)
232 return 0;
233
234 if (!xs_transaction_end(ctx->xsh, t, 0)) {
235 if (errno == EAGAIN)
236 goto retry_transaction;
237 else {
238 LOGED(ERROR, device->domid, "xs transaction failed");
239 return ERROR_FAIL;
240 }
241 }
242 return 0;
243
244 out:
245 if (create_transaction && t)
246 libxl__xs_transaction_abort(gc, &t);
247 return rc;
248 }
249
250 typedef struct {
251 libxl__gc *gc;
252 libxl_device_disk *disk;
253 struct stat stab;
254 } disk_try_backend_args;
255
disk_try_backend(disk_try_backend_args * a,libxl_disk_backend backend)256 static int disk_try_backend(disk_try_backend_args *a,
257 libxl_disk_backend backend)
258 {
259 libxl__gc *gc = a->gc;
260 /* returns 0 (ie, DISK_BACKEND_UNKNOWN) on failure, or
261 * backend on success */
262
263 switch (backend) {
264 case LIBXL_DISK_BACKEND_PHY:
265 if (a->disk->format != LIBXL_DISK_FORMAT_RAW) {
266 goto bad_format;
267 }
268
269 if (libxl_defbool_val(a->disk->colo_enable))
270 goto bad_colo;
271
272 if (a->disk->backend_domid != LIBXL_TOOLSTACK_DOMID) {
273 LOG(DEBUG, "Disk vdev=%s, is using a storage driver domain, "
274 "skipping physical device check", a->disk->vdev);
275 return backend;
276 }
277
278 if (a->disk->script) {
279 LOG(DEBUG, "Disk vdev=%s, uses script=... assuming phy backend",
280 a->disk->vdev);
281 return backend;
282 }
283
284 if (libxl__try_phy_backend(a->stab.st_mode))
285 return backend;
286
287 LOG(DEBUG, "Disk vdev=%s, backend phy unsuitable as phys path not a "
288 "block device", a->disk->vdev);
289 return 0;
290
291 case LIBXL_DISK_BACKEND_TAP:
292 if (a->disk->script) goto bad_script;
293
294 if (libxl_defbool_val(a->disk->colo_enable))
295 goto bad_colo;
296
297 if (a->disk->is_cdrom) {
298 LOG(DEBUG, "Disk vdev=%s, backend tap unsuitable for cdroms",
299 a->disk->vdev);
300 return 0;
301 }
302 if (!libxl__blktap_enabled(a->gc)) {
303 LOG(DEBUG, "Disk vdev=%s, backend tap unsuitable because blktap "
304 "not available", a->disk->vdev);
305 return 0;
306 }
307 if (!(a->disk->format == LIBXL_DISK_FORMAT_RAW ||
308 a->disk->format == LIBXL_DISK_FORMAT_VHD)) {
309 goto bad_format;
310 }
311 return backend;
312
313 case LIBXL_DISK_BACKEND_QDISK:
314 if (a->disk->script) goto bad_script;
315 return backend;
316
317 default:
318 LOG(DEBUG, "Disk vdev=%s, backend %d unknown", a->disk->vdev, backend);
319 return 0;
320
321 }
322 abort(); /* notreached */
323
324 bad_format:
325 LOG(DEBUG, "Disk vdev=%s, backend %s unsuitable due to format %s",
326 a->disk->vdev,
327 libxl_disk_backend_to_string(backend),
328 libxl_disk_format_to_string(a->disk->format));
329 return 0;
330
331 bad_script:
332 LOG(DEBUG, "Disk vdev=%s, backend %s not compatible with script=...",
333 a->disk->vdev, libxl_disk_backend_to_string(backend));
334 return 0;
335
336 bad_colo:
337 LOG(DEBUG, "Disk vdev=%s, backend %s not compatible with colo",
338 a->disk->vdev, libxl_disk_backend_to_string(backend));
339 return 0;
340 }
341
libxl__backendpath_parse_domid(libxl__gc * gc,const char * be_path,libxl_domid * domid_out)342 int libxl__backendpath_parse_domid(libxl__gc *gc, const char *be_path,
343 libxl_domid *domid_out) {
344 int r;
345 unsigned int domid_sc;
346 char delim_sc;
347
348 r = sscanf(be_path, "/local/domain/%u%c", &domid_sc, &delim_sc);
349 if (!(r==2 && delim_sc=='/')) {
350 LOG(ERROR, "internal error: backend path %s unparseable!", be_path);
351 return ERROR_FAIL;
352 }
353 *domid_out = domid_sc;
354 return 0;
355 }
356
libxl__device_disk_set_backend(libxl__gc * gc,libxl_device_disk * disk)357 int libxl__device_disk_set_backend(libxl__gc *gc, libxl_device_disk *disk) {
358 libxl_disk_backend ok;
359 disk_try_backend_args a;
360
361 a.gc = gc;
362 a.disk = disk;
363
364 LOG(DEBUG, "Disk vdev=%s spec.backend=%s", disk->vdev,
365 libxl_disk_backend_to_string(disk->backend));
366
367 if (disk->format == LIBXL_DISK_FORMAT_EMPTY) {
368 if (!disk->is_cdrom) {
369 LOG(ERROR, "Disk vdev=%s is empty but not cdrom", disk->vdev);
370 return ERROR_INVAL;
371 }
372 if (disk->pdev_path != NULL && strcmp(disk->pdev_path, "")) {
373 LOG(ERROR,
374 "Disk vdev=%s is empty but an image has been provided: %s",
375 disk->vdev, disk->pdev_path);
376 return ERROR_INVAL;
377 }
378 memset(&a.stab, 0, sizeof(a.stab));
379 } else if ((disk->backend == LIBXL_DISK_BACKEND_UNKNOWN ||
380 disk->backend == LIBXL_DISK_BACKEND_PHY) &&
381 disk->backend_domid == LIBXL_TOOLSTACK_DOMID &&
382 !disk->script) {
383 if (stat(disk->pdev_path, &a.stab)) {
384 LOGE(ERROR, "Disk vdev=%s failed to stat: %s",
385 disk->vdev, disk->pdev_path);
386 return ERROR_INVAL;
387 }
388 }
389
390 if (disk->backend != LIBXL_DISK_BACKEND_UNKNOWN) {
391 ok= disk_try_backend(&a, disk->backend);
392 } else {
393 ok=
394 disk_try_backend(&a, LIBXL_DISK_BACKEND_PHY) ?:
395 disk_try_backend(&a, LIBXL_DISK_BACKEND_QDISK) ?:
396 disk_try_backend(&a, LIBXL_DISK_BACKEND_TAP);
397 if (ok)
398 LOG(DEBUG, "Disk vdev=%s, using backend %s",
399 disk->vdev,
400 libxl_disk_backend_to_string(ok));
401 }
402 if (!ok) {
403 LOG(ERROR, "no suitable backend for disk %s", disk->vdev);
404 return ERROR_INVAL;
405 }
406 disk->backend = ok;
407 return 0;
408 }
409
libxl__device_disk_string_of_format(libxl_disk_format format)410 char *libxl__device_disk_string_of_format(libxl_disk_format format)
411 {
412 switch (format) {
413 case LIBXL_DISK_FORMAT_QCOW: return "qcow";
414 case LIBXL_DISK_FORMAT_QCOW2: return "qcow2";
415 case LIBXL_DISK_FORMAT_VHD: return "vhd";
416 case LIBXL_DISK_FORMAT_RAW:
417 case LIBXL_DISK_FORMAT_EMPTY: return "aio";
418 case LIBXL_DISK_FORMAT_QED: return "qed";
419 default: return NULL;
420 }
421 }
422
libxl__device_disk_string_of_backend(libxl_disk_backend backend)423 char *libxl__device_disk_string_of_backend(libxl_disk_backend backend)
424 {
425 switch (backend) {
426 case LIBXL_DISK_BACKEND_QDISK: return "qdisk";
427 case LIBXL_DISK_BACKEND_TAP: return "phy";
428 case LIBXL_DISK_BACKEND_PHY: return "phy";
429 default: return NULL;
430 }
431 }
432
libxl__device_physdisk_major_minor(const char * physpath,int * major,int * minor)433 int libxl__device_physdisk_major_minor(const char *physpath, int *major, int *minor)
434 {
435 struct stat buf;
436 if (stat(physpath, &buf) < 0)
437 return -1;
438 if (!S_ISBLK(buf.st_mode))
439 return -1;
440 *major = major(buf.st_rdev);
441 *minor = minor(buf.st_rdev);
442 return 0;
443 }
444
device_virtdisk_matches(const char * virtpath,const char * devtype,int * index_r,int max_index,int * partition_r,int max_partition)445 static int device_virtdisk_matches(const char *virtpath, const char *devtype,
446 int *index_r, int max_index,
447 int *partition_r, int max_partition) {
448 const char *p;
449 char *ep;
450 int tl, c;
451 long pl;
452
453 tl = strlen(devtype);
454 if (memcmp(virtpath, devtype, tl))
455 return 0;
456
457 /* We decode the drive letter as if it were in base 52
458 * with digits a-zA-Z, more or less */
459 *index_r = -1;
460 p = virtpath + tl;
461 for (;;) {
462 c = *p++;
463 if (c >= 'a' && c <= 'z') {
464 c -= 'a';
465 } else {
466 --p;
467 break;
468 }
469 (*index_r)++;
470 (*index_r) *= 26;
471 (*index_r) += c;
472
473 if (*index_r > max_index)
474 return 0;
475 }
476
477 if (!*p) {
478 *partition_r = 0;
479 return 1;
480 }
481
482 if (*p=='0')
483 return 0; /* leading zeroes not permitted in partition number */
484
485 pl = strtoul(p, &ep, 10);
486 if (pl > max_partition || *ep)
487 return 0;
488
489 *partition_r = pl;
490 return 1;
491 }
492
libxl__device_disk_dev_number(const char * virtpath,int * pdisk,int * ppartition)493 int libxl__device_disk_dev_number(const char *virtpath, int *pdisk,
494 int *ppartition)
495 {
496 int disk, partition;
497 char *ep;
498 unsigned long ul;
499 int chrused;
500
501 chrused = -1;
502 if ((sscanf(virtpath, "d%ip%i%n", &disk, &partition, &chrused) >= 2
503 && chrused == strlen(virtpath) && disk < (1<<20) && partition < 256)
504 ||
505 device_virtdisk_matches(virtpath, "xvd",
506 &disk, (1<<20)-1,
507 &partition, 255)) {
508 if (pdisk) *pdisk = disk;
509 if (ppartition) *ppartition = partition;
510 if (disk <= 15 && partition <= 15)
511 return (202 << 8) | (disk << 4) | partition;
512 else
513 return (1 << 28) | (disk << 8) | partition;
514 }
515
516 errno = 0;
517 ul = strtoul(virtpath, &ep, 0);
518 if (!errno && !*ep && ul <= INT_MAX) {
519 /* FIXME: should parse ul to determine these. */
520 if (pdisk || ppartition)
521 return -1;
522 return ul;
523 }
524
525 if (device_virtdisk_matches(virtpath, "hd",
526 &disk, 3,
527 &partition, 63)) {
528 if (pdisk) *pdisk = disk;
529 if (ppartition) *ppartition = partition;
530 return ((disk<2 ? 3 : 22) << 8) | ((disk & 1) << 6) | partition;
531 }
532 if (device_virtdisk_matches(virtpath, "sd",
533 &disk, 15,
534 &partition, 15)) {
535 if (pdisk) *pdisk = disk;
536 if (ppartition) *ppartition = partition;
537 return (8 << 8) | (disk << 4) | partition;
538 }
539 return -1;
540 }
541
encode_disk_name(char * ptr,unsigned int n)542 static char *encode_disk_name(char *ptr, unsigned int n)
543 {
544 if (n >= 26)
545 ptr = encode_disk_name(ptr, n / 26 - 1);
546 *ptr = 'a' + n % 26;
547 return ptr + 1;
548 }
549
libxl__devid_to_vdev(libxl__gc * gc,int devid)550 char *libxl__devid_to_vdev(libxl__gc *gc, int devid)
551 {
552 unsigned int minor;
553 int offset;
554 int nr_parts;
555 char *ptr = NULL;
556 /* Same as in Linux.
557 * encode_disk_name might end up using up to 29 bytes (BUFFER_SIZE - 3)
558 * including the trailing \0.
559 *
560 * The code is safe because 26 raised to the power of 28 (that is the
561 * maximum offset that can be stored in the allocated buffer as a
562 * string) is far greater than UINT_MAX on 64 bits so offset cannot be
563 * big enough to exhaust the available bytes in ret. */
564 #define BUFFER_SIZE 32
565 char *ret = libxl__zalloc(gc, BUFFER_SIZE);
566
567 #define EXT_SHIFT 28
568 #define EXTENDED (1<<EXT_SHIFT)
569 #define VDEV_IS_EXTENDED(dev) ((dev)&(EXTENDED))
570 #define BLKIF_MINOR_EXT(dev) ((dev)&(~EXTENDED))
571 /* the size of the buffer to store the device name is 32 bytes to match the
572 * equivalent buffer in the Linux kernel code */
573
574 if (!VDEV_IS_EXTENDED(devid)) {
575 minor = devid & 0xff;
576 nr_parts = 16;
577 } else {
578 minor = BLKIF_MINOR_EXT(devid);
579 nr_parts = 256;
580 }
581 offset = minor / nr_parts;
582
583 strcpy(ret, "xvd");
584 ptr = encode_disk_name(ret + 3, offset);
585 if (minor % nr_parts == 0)
586 *ptr = 0;
587 else
588 /* overflow cannot happen, thanks to the upper bound */
589 snprintf(ptr, ret + 32 - ptr,
590 "%d", minor & (nr_parts - 1));
591 return ret;
592 #undef BUFFER_SIZE
593 #undef EXT_SHIFT
594 #undef EXTENDED
595 #undef VDEV_IS_EXTENDED
596 #undef BLKIF_MINOR_EXT
597 }
598
599 /* Device AO operations */
600
libxl__prepare_ao_device(libxl__ao * ao,libxl__ao_device * aodev)601 void libxl__prepare_ao_device(libxl__ao *ao, libxl__ao_device *aodev)
602 {
603 aodev->ao = ao;
604 aodev->rc = 0;
605 aodev->dev = NULL;
606 aodev->num_exec = 0;
607 /* Initialize timer for QEMU Bodge */
608 libxl__ev_time_init(&aodev->timeout);
609 /*
610 * Initialize xs_watch, because it's not used on all possible
611 * execution paths, but it's unconditionally destroyed when finished.
612 */
613 libxl__xswait_init(&aodev->xswait);
614 aodev->active = 1;
615 /* We init this here because we might call device_hotplug_done
616 * without actually calling any hotplug script */
617 libxl__async_exec_init(&aodev->aes);
618 libxl__ev_child_init(&aodev->child);
619 }
620
621 /* multidev */
622
libxl__multidev_begin(libxl__ao * ao,libxl__multidev * multidev)623 void libxl__multidev_begin(libxl__ao *ao, libxl__multidev *multidev)
624 {
625 AO_GC;
626
627 multidev->ao = ao;
628 multidev->array = 0;
629 multidev->used = multidev->allocd = 0;
630
631 /* We allocate an aodev to represent the operation of preparing
632 * all of the other operations. This operation is completed when
633 * we have started all the others (ie, when the user calls
634 * _prepared). That arranges automatically that
635 * (i) we do not think we have finished even if one of the
636 * operations completes while we are still preparing
637 * (ii) if we are starting zero operations, we do still
638 * make the callback as soon as we know this fact
639 * (iii) we have a nice consistent way to deal with any
640 * error that might occur while deciding what to initiate
641 */
642 multidev->preparation = libxl__multidev_prepare(multidev);
643 }
644
libxl__multidev_prepare_with_aodev(libxl__multidev * multidev,libxl__ao_device * aodev)645 void libxl__multidev_prepare_with_aodev(libxl__multidev *multidev,
646 libxl__ao_device *aodev) {
647 STATE_AO_GC(multidev->ao);
648
649 aodev->multidev = multidev;
650 aodev->callback = libxl__multidev_one_callback;
651 libxl__prepare_ao_device(ao, aodev);
652
653 if (multidev->used >= multidev->allocd) {
654 multidev->allocd = multidev->used * 2 + 5;
655 GCREALLOC_ARRAY(multidev->array, multidev->allocd);
656 }
657 multidev->array[multidev->used++] = aodev;
658 }
659
libxl__multidev_prepare(libxl__multidev * multidev)660 libxl__ao_device *libxl__multidev_prepare(libxl__multidev *multidev) {
661 STATE_AO_GC(multidev->ao);
662 libxl__ao_device *aodev;
663
664 GCNEW(aodev);
665 libxl__multidev_prepare_with_aodev(multidev, aodev);
666
667 return aodev;
668 }
669
libxl__multidev_one_callback(libxl__egc * egc,libxl__ao_device * aodev)670 void libxl__multidev_one_callback(libxl__egc *egc, libxl__ao_device *aodev)
671 {
672 STATE_AO_GC(aodev->ao);
673 libxl__multidev *multidev = aodev->multidev;
674 int i, error = 0;
675
676 aodev->active = 0;
677
678 for (i = 0; i < multidev->used; i++) {
679 if (multidev->array[i]->active)
680 return;
681
682 if (multidev->array[i]->rc)
683 error = multidev->array[i]->rc;
684 }
685
686 multidev->callback(egc, multidev, error);
687 return;
688 }
689
libxl__multidev_prepared(libxl__egc * egc,libxl__multidev * multidev,int rc)690 void libxl__multidev_prepared(libxl__egc *egc,
691 libxl__multidev *multidev, int rc)
692 {
693 multidev->preparation->rc = rc;
694 libxl__multidev_one_callback(egc, multidev->preparation);
695 }
696
697 /******************************************************************************/
698
libxl__device_destroy(libxl__gc * gc,libxl__device * dev)699 int libxl__device_destroy(libxl__gc *gc, libxl__device *dev)
700 {
701 const char *be_path = NULL;
702 const char *fe_path = NULL;
703 const char *libxl_path = libxl__device_libxl_path(gc, dev);
704 const char *tapdisk_path = NULL;
705 const char *tapdisk_params = NULL;
706 xs_transaction_t t = 0;
707 int rc;
708 uint32_t domid;
709 int libxl_only = dev->backend_kind == LIBXL__DEVICE_KIND_NONE;
710
711 if (!libxl_only) {
712 be_path = libxl__device_backend_path(gc, dev);
713 fe_path = libxl__device_frontend_path(gc, dev);
714 tapdisk_path = GCSPRINTF("%s/%s", be_path, "tapdisk-params");
715 }
716
717 rc = libxl__get_domid(gc, &domid);
718 if (rc) goto out;
719
720 for (;;) {
721 rc = libxl__xs_transaction_start(gc, &t);
722 if (rc) goto out;
723
724 /* May not exist if this is not a tap device */
725 if (tapdisk_path) {
726 rc = libxl__xs_read_checked(gc, t, tapdisk_path, &tapdisk_params);
727 if (rc) goto out;
728 }
729
730 if (domid == LIBXL_TOOLSTACK_DOMID) {
731 /*
732 * The toolstack domain is in charge of removing the
733 * frontend and libxl paths.
734 */
735 if (!libxl_only)
736 libxl__xs_path_cleanup(gc, t, fe_path);
737 libxl__xs_path_cleanup(gc, t, libxl_path);
738 }
739 if (dev->backend_domid == domid && !libxl_only) {
740 /*
741 * The driver domain is in charge of removing what it can
742 * from the backend path.
743 */
744 libxl__xs_path_cleanup(gc, t, be_path);
745 }
746
747 rc = libxl__xs_transaction_commit(gc, &t);
748 if (!rc) break;
749 if (rc < 0) goto out;
750 }
751
752 if (tapdisk_params)
753 rc = libxl__device_destroy_tapdisk(gc, tapdisk_params);
754
755 out:
756 libxl__xs_transaction_abort(gc, &t);
757 return rc;
758 }
759
760 /* Callback for device destruction */
761
762 static void devices_remove_callback(libxl__egc *egc,
763 libxl__multidev *multidev, int rc);
764
libxl__devices_destroy(libxl__egc * egc,libxl__devices_remove_state * drs)765 void libxl__devices_destroy(libxl__egc *egc, libxl__devices_remove_state *drs)
766 {
767 STATE_AO_GC(drs->ao);
768 uint32_t domid = drs->domid;
769 char *path;
770 unsigned int num_kinds, num_dev_xsentries;
771 char **kinds = NULL, **devs = NULL;
772 int i, j, rc = 0;
773 libxl__device *dev;
774 libxl__multidev *multidev = &drs->multidev;
775 libxl__ao_device *aodev;
776 libxl__device_kind kind;
777
778 libxl__multidev_begin(ao, multidev);
779 multidev->callback = devices_remove_callback;
780
781 path = GCSPRINTF("/libxl/%d/device", domid);
782 kinds = libxl__xs_directory(gc, XBT_NULL, path, &num_kinds);
783 if (!kinds) {
784 if (errno != ENOENT) {
785 LOGE(ERROR, "unable to get xenstore device listing %s", path);
786 goto out;
787 }
788 num_kinds = 0;
789 }
790 for (i = 0; i < num_kinds; i++) {
791 if (libxl__device_kind_from_string(kinds[i], &kind))
792 continue;
793
794 path = GCSPRINTF("/libxl/%d/device/%s", domid, kinds[i]);
795 devs = libxl__xs_directory(gc, XBT_NULL, path, &num_dev_xsentries);
796 if (!devs)
797 continue;
798 for (j = 0; j < num_dev_xsentries; j++) {
799 path = GCSPRINTF("/libxl/%d/device/%s/%s/backend",
800 domid, kinds[i], devs[j]);
801 path = libxl__xs_read(gc, XBT_NULL, path);
802 GCNEW(dev);
803 if (path && libxl__parse_backend_path(gc, path, dev) == 0) {
804 dev->domid = domid;
805 dev->kind = kind;
806 dev->devid = atoi(devs[j]);
807 if (dev->backend_kind == LIBXL__DEVICE_KIND_CONSOLE ||
808 dev->backend_kind == LIBXL__DEVICE_KIND_VUART) {
809 /* Currently console devices can be destroyed
810 * synchronously by just removing xenstore entries,
811 * this is what libxl__device_destroy does.
812 */
813 libxl__device_destroy(gc, dev);
814 continue;
815 }
816 aodev = libxl__multidev_prepare(multidev);
817 aodev->action = LIBXL__DEVICE_ACTION_REMOVE;
818 aodev->dev = dev;
819 aodev->force = drs->force;
820 if (dev->kind == LIBXL__DEVICE_KIND_VUSB)
821 libxl__initiate_device_usbctrl_remove(egc, aodev);
822 else
823 libxl__initiate_device_generic_remove(egc, aodev);
824 }
825 }
826 }
827
828 out:
829 libxl__multidev_prepared(egc, multidev, rc);
830 }
831
832 /* Callbacks for device related operations */
833
834 /*
835 * device_backend_callback is the main callback entry point, for both device
836 * addition and removal. It gets called if we reach the desired state
837 * (XenbusStateClosed or XenbusStateInitWait). After that, all this
838 * functions get called in the order displayed below.
839 *
840 * If new device types are added, they should only need to modify the
841 * specific hotplug scripts call, which can be found in each OS specific
842 * file. If this new devices don't need a hotplug script, no modification
843 * should be needed.
844 */
845
846 /* This callback is part of the Qemu devices Badge */
847 static void device_qemu_timeout(libxl__egc *egc, libxl__ev_time *ev,
848 const struct timeval *requested_abs, int rc);
849
850 static void device_backend_callback(libxl__egc *egc, libxl__ev_devstate *ds,
851 int rc);
852
853 static void device_backend_cleanup(libxl__gc *gc,
854 libxl__ao_device *aodev);
855
856 static void device_hotplug(libxl__egc *egc, libxl__ao_device *aodev);
857
858 static void device_hotplug_child_death_cb(libxl__egc *egc,
859 libxl__async_exec_state *aes,
860 int rc, int status);
861
862 static void device_destroy_be_watch_cb(libxl__egc *egc,
863 libxl__xswait_state *xswait,
864 int rc, const char *data);
865
866 static void device_hotplug_done(libxl__egc *egc, libxl__ao_device *aodev);
867
868 static void device_hotplug_clean(libxl__gc *gc, libxl__ao_device *aodev);
869
libxl__wait_device_connection(libxl__egc * egc,libxl__ao_device * aodev)870 void libxl__wait_device_connection(libxl__egc *egc, libxl__ao_device *aodev)
871 {
872 STATE_AO_GC(aodev->ao);
873 char *be_path = libxl__device_backend_path(gc, aodev->dev);
874 char *state_path = GCSPRINTF("%s/state", be_path);
875 int rc = 0;
876
877 if (QEMU_BACKEND(aodev->dev)) {
878 /*
879 * If Qemu is not running, there's no point in waiting for
880 * it to change the state of the device.
881 *
882 * If Qemu is running, it will set the state of the device to
883 * 4 directly, without waiting in state 2 for any hotplug execution.
884 */
885 device_hotplug(egc, aodev);
886 return;
887 }
888
889 rc = libxl__ev_devstate_wait(ao, &aodev->backend_ds,
890 device_backend_callback,
891 state_path, XenbusStateInitWait,
892 LIBXL_INIT_TIMEOUT * 1000);
893 if (rc) {
894 LOGD(ERROR, aodev->dev->domid, "unable to initialize device %s", be_path);
895 goto out;
896 }
897
898 return;
899
900 out:
901 aodev->rc = rc;
902 device_hotplug_done(egc, aodev);
903 return;
904 }
905
libxl__initiate_device_generic_remove(libxl__egc * egc,libxl__ao_device * aodev)906 void libxl__initiate_device_generic_remove(libxl__egc *egc,
907 libxl__ao_device *aodev)
908 {
909 STATE_AO_GC(aodev->ao);
910 xs_transaction_t t = 0;
911 char *be_path = libxl__device_backend_path(gc, aodev->dev);
912 char *state_path = GCSPRINTF("%s/state", be_path);
913 char *online_path = GCSPRINTF("%s/online", be_path);
914 const char *state;
915 libxl_dominfo info;
916 uint32_t my_domid, domid = aodev->dev->domid;
917 int rc = 0;
918
919 libxl_dominfo_init(&info);
920
921 rc = libxl__get_domid(gc, &my_domid);
922 if (rc) {
923 LOGD(ERROR, domid, "unable to get my domid");
924 goto out;
925 }
926
927 if (my_domid == LIBXL_TOOLSTACK_DOMID) {
928 rc = libxl_domain_info(CTX, &info, domid);
929 if (rc) {
930 LOGD(ERROR, domid, "unable to get info for domain %d", domid);
931 goto out;
932 }
933 if (QEMU_BACKEND(aodev->dev) &&
934 (info.paused || info.dying || info.shutdown)) {
935 /*
936 * TODO: 4.2 Bodge due to QEMU, see comment on top of
937 * libxl__initiate_device_generic_remove in libxl_internal.h
938 */
939 rc = libxl__ev_time_register_rel(ao, &aodev->timeout,
940 device_qemu_timeout,
941 LIBXL_QEMU_BODGE_TIMEOUT * 1000);
942 if (rc) {
943 LOGD(ERROR, domid, "unable to register timeout for Qemu device %s",
944 be_path);
945 goto out;
946 }
947 goto out_success;
948 }
949 }
950
951 for (;;) {
952 rc = libxl__xs_transaction_start(gc, &t);
953 if (rc) {
954 LOGD(ERROR, domid, "unable to start transaction");
955 goto out;
956 }
957
958 if (aodev->force)
959 libxl__xs_path_cleanup(gc, t,
960 libxl__device_frontend_path(gc, aodev->dev));
961
962 rc = libxl__xs_read_checked(gc, t, state_path, &state);
963 if (rc) {
964 LOGD(ERROR, domid, "unable to read device state from path %s", state_path);
965 goto out;
966 }
967
968 rc = libxl__xs_write_checked(gc, t, online_path, "0");
969 if (rc)
970 goto out;
971
972 /*
973 * Check if device is already in "closed" state, in which case
974 * it should not be changed.
975 */
976 if (state && atoi(state) != XenbusStateClosed) {
977 rc = libxl__xs_write_checked(gc, t, state_path, GCSPRINTF("%d", XenbusStateClosing));
978 if (rc) {
979 LOGD(ERROR, domid, "unable to write to xenstore path %s", state_path);
980 goto out;
981 }
982 }
983
984 rc = libxl__xs_transaction_commit(gc, &t);
985 if (!rc) break;
986 if (rc < 0) goto out;
987 }
988
989 rc = libxl__ev_devstate_wait(ao, &aodev->backend_ds,
990 device_backend_callback,
991 state_path, XenbusStateClosed,
992 LIBXL_DESTROY_TIMEOUT * 1000);
993 if (rc) {
994 LOGD(ERROR, domid, "unable to remove device %s", be_path);
995 goto out;
996 }
997
998 out_success:
999 libxl_dominfo_dispose(&info);
1000 return;
1001
1002 out:
1003 aodev->rc = rc;
1004 libxl_dominfo_dispose(&info);
1005 libxl__xs_transaction_abort(gc, &t);
1006 device_hotplug_done(egc, aodev);
1007 return;
1008 }
1009
device_qemu_timeout(libxl__egc * egc,libxl__ev_time * ev,const struct timeval * requested_abs,int rc)1010 static void device_qemu_timeout(libxl__egc *egc, libxl__ev_time *ev,
1011 const struct timeval *requested_abs, int rc)
1012 {
1013 libxl__ao_device *aodev = CONTAINER_OF(ev, *aodev, timeout);
1014 STATE_AO_GC(aodev->ao);
1015 char *be_path = libxl__device_backend_path(gc, aodev->dev);
1016 char *state_path = GCSPRINTF("%s/state", be_path);
1017 const char *xs_state;
1018 xs_transaction_t t = 0;
1019
1020 if (rc != ERROR_TIMEDOUT)
1021 goto out;
1022
1023 libxl__ev_time_deregister(gc, &aodev->timeout);
1024
1025 for (;;) {
1026 rc = libxl__xs_transaction_start(gc, &t);
1027 if (rc) {
1028 LOGD(ERROR, aodev->dev->domid, "unable to start transaction");
1029 goto out;
1030 }
1031
1032 /*
1033 * Check that the state path exists and is actually different than
1034 * 6 before unconditionally setting it. If Qemu runs on a driver
1035 * domain it is possible that the driver domain has already cleaned
1036 * the backend path if the device has reached state 6.
1037 */
1038 rc = libxl__xs_read_checked(gc, XBT_NULL, state_path, &xs_state);
1039 if (rc) goto out;
1040
1041 if (xs_state && atoi(xs_state) != XenbusStateClosed) {
1042 rc = libxl__xs_write_checked(gc, XBT_NULL, state_path, GCSPRINTF("%d", XenbusStateClosed));
1043 if (rc) goto out;
1044 }
1045
1046 rc = libxl__xs_transaction_commit(gc, &t);
1047 if (!rc) break;
1048 if (rc < 0) goto out;
1049 }
1050
1051 device_hotplug(egc, aodev);
1052 return;
1053
1054 out:
1055 libxl__xs_transaction_abort(gc, &t);
1056 aodev->rc = rc;
1057 device_hotplug_done(egc, aodev);
1058 }
1059
device_backend_callback(libxl__egc * egc,libxl__ev_devstate * ds,int rc)1060 static void device_backend_callback(libxl__egc *egc, libxl__ev_devstate *ds,
1061 int rc) {
1062 libxl__ao_device *aodev = CONTAINER_OF(ds, *aodev, backend_ds);
1063 STATE_AO_GC(aodev->ao);
1064
1065 LOGD(DEBUG, aodev->dev->domid, "calling device_backend_cleanup");
1066 device_backend_cleanup(gc, aodev);
1067
1068 if (rc == ERROR_TIMEDOUT &&
1069 aodev->action == LIBXL__DEVICE_ACTION_REMOVE &&
1070 !aodev->force) {
1071 LOGD(DEBUG, aodev->dev->domid, "Timeout reached, initiating forced remove");
1072 aodev->force = 1;
1073 libxl__initiate_device_generic_remove(egc, aodev);
1074 return;
1075 }
1076
1077 if (rc) {
1078 LOGD(ERROR, aodev->dev->domid, "unable to %s device with path %s",
1079 libxl__device_action_to_string(aodev->action),
1080 libxl__device_backend_path(gc, aodev->dev));
1081 goto out;
1082 }
1083
1084 device_hotplug(egc, aodev);
1085 return;
1086
1087 out:
1088 aodev->rc = rc;
1089 device_hotplug_done(egc, aodev);
1090 return;
1091 }
1092
device_backend_cleanup(libxl__gc * gc,libxl__ao_device * aodev)1093 static void device_backend_cleanup(libxl__gc *gc, libxl__ao_device *aodev)
1094 {
1095 if (!aodev) return;
1096 libxl__ev_devstate_cancel(gc, &aodev->backend_ds);
1097 }
1098
device_hotplug(libxl__egc * egc,libxl__ao_device * aodev)1099 static void device_hotplug(libxl__egc *egc, libxl__ao_device *aodev)
1100 {
1101 STATE_AO_GC(aodev->ao);
1102 libxl__async_exec_state *aes = &aodev->aes;
1103 char *be_path = libxl__device_backend_path(gc, aodev->dev);
1104 char **args = NULL, **env = NULL;
1105 int rc = 0;
1106 int hotplug, nullfd = -1;
1107 uint32_t domid;
1108
1109 /*
1110 * If device is attached from a driver domain don't try to execute
1111 * hotplug scripts
1112 */
1113 rc = libxl__get_domid(gc, &domid);
1114 if (rc) {
1115 LOGD(ERROR, aodev->dev->domid, "Failed to get domid");
1116 goto out;
1117 }
1118 if (aodev->dev->backend_domid != domid) {
1119 LOGD(DEBUG, aodev->dev->domid,
1120 "Backend domid %d, domid %d, assuming driver domains",
1121 aodev->dev->backend_domid, domid);
1122
1123 if (aodev->action != LIBXL__DEVICE_ACTION_REMOVE) {
1124 LOG(DEBUG, "Not a remove, not executing hotplug scripts");
1125 goto out;
1126 }
1127
1128 aodev->xswait.ao = ao;
1129 aodev->xswait.what = "removal of backend path";
1130 aodev->xswait.path = be_path;
1131 aodev->xswait.timeout_ms = LIBXL_DESTROY_TIMEOUT * 1000;
1132 aodev->xswait.callback = device_destroy_be_watch_cb;
1133 rc = libxl__xswait_start(gc, &aodev->xswait);
1134 if (rc) {
1135 LOGD(ERROR, aodev->dev->domid,
1136 "Setup of backend removal watch failed (path %s)", be_path);
1137 goto out;
1138 }
1139
1140 return;
1141 }
1142
1143 /* Check if we have to execute hotplug scripts for this device
1144 * and return the necessary args/env vars for execution */
1145 hotplug = libxl__get_hotplug_script_info(gc, aodev->dev, &args, &env,
1146 aodev->action,
1147 aodev->num_exec);
1148 switch (hotplug) {
1149 case 0:
1150 /* no hotplug script to execute */
1151 LOGD(DEBUG, aodev->dev->domid, "No hotplug script to execute");
1152 goto out;
1153 case 1:
1154 /* execute hotplug script */
1155 break;
1156 default:
1157 /* everything else is an error */
1158 LOGD(ERROR, aodev->dev->domid,
1159 "unable to get args/env to execute hotplug script for "
1160 "device %s", libxl__device_backend_path(gc, aodev->dev));
1161 rc = hotplug;
1162 goto out;
1163 }
1164
1165 assert(args != NULL);
1166 LOGD(DEBUG, aodev->dev->domid, "calling hotplug script: %s %s", args[0], args[1]);
1167 LOGD(DEBUG, aodev->dev->domid, "extra args:");
1168 {
1169 const char *arg;
1170 unsigned int x;
1171
1172 for (x = 2; (arg = args[x]); x++)
1173 LOGD(DEBUG, aodev->dev->domid, "\t%s", arg);
1174 }
1175 LOGD(DEBUG, aodev->dev->domid, "env:");
1176 if (env != NULL) {
1177 const char *k, *v;
1178 unsigned int x;
1179
1180 for (x = 0; (k = env[x]); x += 2) {
1181 v = env[x+1];
1182 LOGD(DEBUG, aodev->dev->domid, "\t%s: %s", k, v);
1183 }
1184 }
1185
1186 nullfd = open("/dev/null", O_RDONLY);
1187 if (nullfd < 0) {
1188 LOGD(ERROR, aodev->dev->domid, "unable to open /dev/null for hotplug script");
1189 rc = ERROR_FAIL;
1190 goto out;
1191 }
1192
1193 aes->ao = ao;
1194 aes->what = GCSPRINTF("%s %s", args[0], args[1]);
1195 aes->env = env;
1196 aes->args = args;
1197 aes->callback = device_hotplug_child_death_cb;
1198 aes->timeout_ms = LIBXL_HOTPLUG_TIMEOUT * 1000;
1199 aes->stdfds[0] = nullfd;
1200 aes->stdfds[1] = 2;
1201 aes->stdfds[2] = -1;
1202
1203 rc = libxl__async_exec_start(aes);
1204 if (rc)
1205 goto out;
1206
1207 close(nullfd);
1208 assert(libxl__async_exec_inuse(&aodev->aes));
1209
1210 return;
1211
1212 out:
1213 if (nullfd >= 0) close(nullfd);
1214 aodev->rc = rc;
1215 device_hotplug_done(egc, aodev);
1216 return;
1217 }
1218
device_hotplug_child_death_cb(libxl__egc * egc,libxl__async_exec_state * aes,int rc,int status)1219 static void device_hotplug_child_death_cb(libxl__egc *egc,
1220 libxl__async_exec_state *aes,
1221 int rc, int status)
1222 {
1223 libxl__ao_device *aodev = CONTAINER_OF(aes, *aodev, aes);
1224 STATE_AO_GC(aodev->ao);
1225 char *be_path = libxl__device_backend_path(gc, aodev->dev);
1226 char *hotplug_error;
1227
1228 device_hotplug_clean(gc, aodev);
1229
1230 if (status && !rc) {
1231 hotplug_error = libxl__xs_read(gc, XBT_NULL,
1232 GCSPRINTF("%s/hotplug-error", be_path));
1233 if (hotplug_error)
1234 LOG(ERROR, "script: %s", hotplug_error);
1235 rc = ERROR_FAIL;
1236 }
1237
1238 if (rc) {
1239 if (!aodev->rc)
1240 aodev->rc = rc;
1241 if (aodev->action == LIBXL__DEVICE_ACTION_ADD)
1242 /*
1243 * Only fail on device connection, on disconnection
1244 * ignore error, and continue with the remove process
1245 */
1246 goto error;
1247 }
1248
1249 /* Increase num_exec and call hotplug scripts again if necessary
1250 * If no more executions are needed, device_hotplug will call
1251 * device_hotplug_done breaking the loop.
1252 */
1253 aodev->num_exec++;
1254 device_hotplug(egc, aodev);
1255
1256 return;
1257
1258 error:
1259 assert(aodev->rc);
1260 device_hotplug_done(egc, aodev);
1261 }
1262
device_destroy_be_watch_cb(libxl__egc * egc,libxl__xswait_state * xswait,int rc,const char * dir)1263 static void device_destroy_be_watch_cb(libxl__egc *egc,
1264 libxl__xswait_state *xswait,
1265 int rc, const char *dir)
1266 {
1267 libxl__ao_device *aodev = CONTAINER_OF(xswait, *aodev, xswait);
1268 STATE_AO_GC(aodev->ao);
1269
1270 if (rc) {
1271 if (rc == ERROR_TIMEDOUT)
1272 LOGD(ERROR, aodev->dev->domid,
1273 "timed out while waiting for %s to be removed",
1274 xswait->path);
1275 aodev->rc = rc;
1276 goto out;
1277 }
1278
1279 if (dir) {
1280 /* backend path still exists, wait a little longer... */
1281 return;
1282 }
1283
1284 out:
1285 /* We are done, backend path no longer exists */
1286 device_hotplug_done(egc, aodev);
1287 }
1288
device_hotplug_done(libxl__egc * egc,libxl__ao_device * aodev)1289 static void device_hotplug_done(libxl__egc *egc, libxl__ao_device *aodev)
1290 {
1291 STATE_AO_GC(aodev->ao);
1292 int rc;
1293
1294 device_hotplug_clean(gc, aodev);
1295
1296 /* Clean xenstore if it's a disconnection */
1297 if (aodev->action == LIBXL__DEVICE_ACTION_REMOVE) {
1298 rc = libxl__device_destroy(gc, aodev->dev);
1299 if (!aodev->rc)
1300 aodev->rc = rc;
1301 }
1302
1303 aodev->callback(egc, aodev);
1304 return;
1305 }
1306
device_hotplug_clean(libxl__gc * gc,libxl__ao_device * aodev)1307 static void device_hotplug_clean(libxl__gc *gc, libxl__ao_device *aodev)
1308 {
1309 /* Clean events and check reentrancy */
1310 libxl__ev_time_deregister(gc, &aodev->timeout);
1311 libxl__xswait_stop(gc, &aodev->xswait);
1312 assert(!libxl__async_exec_inuse(&aodev->aes));
1313 }
1314
devices_remove_callback(libxl__egc * egc,libxl__multidev * multidev,int rc)1315 static void devices_remove_callback(libxl__egc *egc,
1316 libxl__multidev *multidev, int rc)
1317 {
1318 libxl__devices_remove_state *drs = CONTAINER_OF(multidev, *drs, multidev);
1319 STATE_AO_GC(drs->ao);
1320
1321 drs->callback(egc, drs, rc);
1322 return;
1323 }
1324
libxl__wait_for_device_model_deprecated(libxl__gc * gc,uint32_t domid,char * state,libxl__spawn_starting * spawning,int (* check_callback)(libxl__gc * gc,uint32_t domid,const char * state,void * userdata),void * check_callback_userdata)1325 int libxl__wait_for_device_model_deprecated(libxl__gc *gc,
1326 uint32_t domid, char *state,
1327 libxl__spawn_starting *spawning,
1328 int (*check_callback)(libxl__gc *gc,
1329 uint32_t domid,
1330 const char *state,
1331 void *userdata),
1332 void *check_callback_userdata)
1333 {
1334 char *path;
1335 uint32_t dm_domid = libxl_get_stubdom_id(CTX, domid);
1336
1337 path = DEVICE_MODEL_XS_PATH(gc, dm_domid, domid, "/state");
1338 return libxl__xenstore_child_wait_deprecated(gc, domid,
1339 LIBXL_DEVICE_MODEL_START_TIMEOUT,
1340 "Device Model", path, state, spawning,
1341 check_callback, check_callback_userdata);
1342 }
1343
libxl__wait_for_backend(libxl__gc * gc,const char * be_path,const char * state)1344 int libxl__wait_for_backend(libxl__gc *gc, const char *be_path,
1345 const char *state)
1346 {
1347 int watchdog = 100;
1348 const char *p, *path = GCSPRINTF("%s/state", be_path);
1349 int rc;
1350
1351 while (watchdog-- > 0) {
1352 rc = libxl__xs_read_checked(gc, XBT_NULL, path, &p);
1353 if (rc) return rc;
1354
1355 if (p == NULL) {
1356 LOG(ERROR, "Backend %s does not exist", be_path);
1357 return ERROR_FAIL;
1358 }
1359
1360 if (!strcmp(p, state))
1361 return 0;
1362
1363 usleep(100000);
1364 }
1365
1366 LOG(ERROR, "Backend %s not ready", be_path);
1367 return ERROR_FAIL;
1368 }
1369
1370 /* generic callback for devices that only need to set ao_complete */
device_addrm_aocomplete(libxl__egc * egc,libxl__ao_device * aodev)1371 void device_addrm_aocomplete(libxl__egc *egc, libxl__ao_device *aodev)
1372 {
1373 STATE_AO_GC(aodev->ao);
1374
1375 if (aodev->rc) {
1376 if (aodev->dev) {
1377 LOGD(ERROR, aodev->dev->domid, "Unable to %s %s with id %u",
1378 libxl__device_action_to_string(aodev->action),
1379 libxl__device_kind_to_string(aodev->dev->kind),
1380 aodev->dev->devid);
1381 } else {
1382 LOG(ERROR, "unable to %s device",
1383 libxl__device_action_to_string(aodev->action));
1384 }
1385 goto out;
1386 }
1387
1388 out:
1389 libxl__ao_complete(egc, ao, aodev->rc);
1390 return;
1391 }
1392
1393 /* common function to get next device id */
libxl__device_nextid(libxl__gc * gc,uint32_t domid,char * device)1394 int libxl__device_nextid(libxl__gc *gc, uint32_t domid, char *device)
1395 {
1396 char *libxl_dom_path, **l;
1397 unsigned int nb;
1398 int nextid = -1;
1399
1400 if (!(libxl_dom_path = libxl__xs_libxl_path(gc, domid)))
1401 return nextid;
1402
1403 l = libxl__xs_directory(gc, XBT_NULL,
1404 GCSPRINTF("%s/device/%s", libxl_dom_path, device),
1405 &nb);
1406 if (l == NULL || nb == 0)
1407 nextid = 0;
1408 else
1409 nextid = strtoul(l[nb - 1], NULL, 10) + 1;
1410
1411 return nextid;
1412 }
1413
device_complete(libxl__egc * egc,libxl__ao_device * aodev)1414 static void device_complete(libxl__egc *egc, libxl__ao_device *aodev)
1415 {
1416 STATE_AO_GC(aodev->ao);
1417
1418 LOG(DEBUG, "device %s %s %s",
1419 libxl__device_backend_path(gc, aodev->dev),
1420 libxl__device_action_to_string(aodev->action),
1421 aodev->rc ? "failed" : "succeed");
1422
1423 libxl__nested_ao_free(aodev->ao);
1424 }
1425
qdisk_spawn_outcome(libxl__egc * egc,libxl__dm_spawn_state * dmss,int rc)1426 static void qdisk_spawn_outcome(libxl__egc *egc, libxl__dm_spawn_state *dmss,
1427 int rc)
1428 {
1429 STATE_AO_GC(dmss->spawn.ao);
1430
1431 LOGD(DEBUG, dmss->guest_domid, "qdisk backend spawn %s",
1432 rc ? "failed" : "succeed");
1433
1434 libxl__nested_ao_free(dmss->spawn.ao);
1435 }
1436
1437 /*
1438 * Data structures used to track devices handled by driver domains
1439 */
1440
1441 /*
1442 * Structure that describes a device handled by a driver domain
1443 */
1444 typedef struct libxl__ddomain_device {
1445 libxl__device *dev;
1446 LIBXL_SLIST_ENTRY(struct libxl__ddomain_device) next;
1447 } libxl__ddomain_device;
1448
1449 /*
1450 * Structure that describes a domain and it's associated devices
1451 */
1452 typedef struct libxl__ddomain_guest {
1453 uint32_t domid;
1454 int num_vifs, num_vbds, num_qdisks;
1455 LIBXL_SLIST_HEAD(, struct libxl__ddomain_device) devices;
1456 LIBXL_SLIST_ENTRY(struct libxl__ddomain_guest) next;
1457 } libxl__ddomain_guest;
1458
1459 /*
1460 * Main structure used by a driver domain to keep track of devices
1461 * currently in use
1462 */
1463 typedef struct {
1464 libxl__ao *ao;
1465 libxl__ev_xswatch watch;
1466 LIBXL_SLIST_HEAD(, struct libxl__ddomain_guest) guests;
1467 } libxl__ddomain;
1468
search_for_guest(libxl__ddomain * ddomain,uint32_t domid)1469 static libxl__ddomain_guest *search_for_guest(libxl__ddomain *ddomain,
1470 uint32_t domid)
1471 {
1472 libxl__ddomain_guest *dguest;
1473
1474 LIBXL_SLIST_FOREACH(dguest, &ddomain->guests, next) {
1475 if (dguest->domid == domid)
1476 return dguest;
1477 }
1478 return NULL;
1479 }
1480
search_for_device(libxl__ddomain_guest * dguest,libxl__device * dev)1481 static libxl__ddomain_device *search_for_device(libxl__ddomain_guest *dguest,
1482 libxl__device *dev)
1483 {
1484 libxl__ddomain_device *ddev;
1485
1486 LIBXL_SLIST_FOREACH(ddev, &dguest->devices, next) {
1487 #define LIBXL_DEVICE_CMP(dev1, dev2, entry) (dev1->entry == dev2->entry)
1488 if (LIBXL_DEVICE_CMP(ddev->dev, dev, backend_devid) &&
1489 LIBXL_DEVICE_CMP(ddev->dev, dev, backend_domid) &&
1490 LIBXL_DEVICE_CMP(ddev->dev, dev, devid) &&
1491 LIBXL_DEVICE_CMP(ddev->dev, dev, domid) &&
1492 LIBXL_DEVICE_CMP(ddev->dev, dev, backend_kind) &&
1493 LIBXL_DEVICE_CMP(ddev->dev, dev, kind))
1494 return ddev;
1495 #undef LIBXL_DEVICE_CMP
1496 }
1497
1498 return NULL;
1499 }
1500
check_and_maybe_remove_guest(libxl__gc * gc,libxl__ddomain * ddomain,libxl__ddomain_guest * dguest)1501 static void check_and_maybe_remove_guest(libxl__gc *gc,
1502 libxl__ddomain *ddomain,
1503 libxl__ddomain_guest *dguest)
1504 {
1505 assert(ddomain);
1506
1507 if (dguest != NULL &&
1508 dguest->num_vifs + dguest->num_vbds + dguest->num_qdisks == 0) {
1509 LIBXL_SLIST_REMOVE(&ddomain->guests, dguest, libxl__ddomain_guest,
1510 next);
1511 LOGD(DEBUG, dguest->domid, "Removed domain from the list of active guests");
1512 /* Clear any leftovers in libxl/<domid> */
1513 libxl__xs_rm_checked(gc, XBT_NULL,
1514 GCSPRINTF("libxl/%u", dguest->domid));
1515 free(dguest);
1516 }
1517 }
1518
1519 /*
1520 * The following comment applies to both add_device and remove_device.
1521 *
1522 * If the return value is greater than 0, it means there's no ao dispatched,
1523 * so the free of the nested ao should be done by the parent when it has
1524 * finished.
1525 */
add_device(libxl__egc * egc,libxl__ao * ao,libxl__ddomain_guest * dguest,libxl__device * dev)1526 static int add_device(libxl__egc *egc, libxl__ao *ao,
1527 libxl__ddomain_guest *dguest,
1528 libxl__device *dev)
1529 {
1530 AO_GC;
1531 libxl__ao_device *aodev;
1532 libxl__ddomain_device *ddev;
1533 libxl__dm_spawn_state *dmss;
1534 int rc = 0;
1535
1536 /*
1537 * New device addition, allocate a struct to hold it and add it
1538 * to the list of active devices for a given guest.
1539 */
1540 ddev = libxl__zalloc(NOGC, sizeof(*ddev));
1541 ddev->dev = libxl__zalloc(NOGC, sizeof(*ddev->dev));
1542 *ddev->dev = *dev;
1543 LIBXL_SLIST_INSERT_HEAD(&dguest->devices, ddev, next);
1544 LOGD(DEBUG, dev->domid, "Added device %s to the list of active devices",
1545 libxl__device_backend_path(gc, dev));
1546
1547 switch(dev->backend_kind) {
1548 case LIBXL__DEVICE_KIND_VBD:
1549 case LIBXL__DEVICE_KIND_VIF:
1550 if (dev->backend_kind == LIBXL__DEVICE_KIND_VBD) dguest->num_vbds++;
1551 if (dev->backend_kind == LIBXL__DEVICE_KIND_VIF) dguest->num_vifs++;
1552
1553 GCNEW(aodev);
1554 libxl__prepare_ao_device(ao, aodev);
1555 /*
1556 * Clone the libxl__device to avoid races if remove_device is called
1557 * before the device addition has finished.
1558 */
1559 GCNEW(aodev->dev);
1560 *aodev->dev = *dev;
1561 aodev->action = LIBXL__DEVICE_ACTION_ADD;
1562 aodev->callback = device_complete;
1563 libxl__wait_device_connection(egc, aodev);
1564
1565 break;
1566 case LIBXL__DEVICE_KIND_QDISK:
1567 if (dguest->num_qdisks == 0) {
1568 GCNEW(dmss);
1569 dmss->guest_domid = dev->domid;
1570 dmss->spawn.ao = ao;
1571 dmss->callback = qdisk_spawn_outcome;
1572
1573 libxl__spawn_qdisk_backend(egc, dmss);
1574 }
1575 dguest->num_qdisks++;
1576
1577 break;
1578 default:
1579 rc = 1;
1580 break;
1581 }
1582
1583 return rc;
1584 }
1585
remove_device(libxl__egc * egc,libxl__ao * ao,libxl__ddomain_guest * dguest,libxl__ddomain_device * ddev)1586 static int remove_device(libxl__egc *egc, libxl__ao *ao,
1587 libxl__ddomain_guest *dguest,
1588 libxl__ddomain_device *ddev)
1589 {
1590 AO_GC;
1591 libxl__device *dev = ddev->dev;
1592 libxl__ao_device *aodev;
1593 int rc = 0;
1594
1595 switch(ddev->dev->backend_kind) {
1596 case LIBXL__DEVICE_KIND_VBD:
1597 case LIBXL__DEVICE_KIND_VIF:
1598 if (dev->backend_kind == LIBXL__DEVICE_KIND_VBD) dguest->num_vbds--;
1599 if (dev->backend_kind == LIBXL__DEVICE_KIND_VIF) dguest->num_vifs--;
1600
1601 GCNEW(aodev);
1602 libxl__prepare_ao_device(ao, aodev);
1603 /*
1604 * Clone the libxl__device to avoid races if there's a add_device
1605 * running in parallel.
1606 */
1607 GCNEW(aodev->dev);
1608 *aodev->dev = *dev;
1609 aodev->action = LIBXL__DEVICE_ACTION_REMOVE;
1610 aodev->callback = device_complete;
1611 libxl__initiate_device_generic_remove(egc, aodev);
1612 break;
1613 case LIBXL__DEVICE_KIND_QDISK:
1614 if (--dguest->num_qdisks == 0) {
1615 rc = libxl__destroy_qdisk_backend(gc, dev->domid);
1616 if (rc)
1617 goto out;
1618 }
1619 libxl__device_destroy(gc, dev);
1620 /* Fall through to return > 0, no ao has been dispatched */
1621 default:
1622 rc = 1;
1623 break;
1624 }
1625
1626 /*
1627 * Removal of an active device, remove it from the list and
1628 * free it's data structures if they are no longer needed.
1629 *
1630 * NB: the freeing is safe because all the async ops launched
1631 * above or from add_device make a copy of the data they use, so
1632 * there's no risk of dereferencing.
1633 */
1634 LIBXL_SLIST_REMOVE(&dguest->devices, ddev, libxl__ddomain_device,
1635 next);
1636 LOGD(DEBUG, dev->domid, "Removed device %s from the list of active devices",
1637 libxl__device_backend_path(gc, dev));
1638
1639 free(ddev->dev);
1640 free(ddev);
1641
1642 out:
1643 return rc;
1644 }
1645
backend_watch_callback(libxl__egc * egc,libxl__ev_xswatch * watch,const char * watch_path,const char * event_path)1646 static void backend_watch_callback(libxl__egc *egc, libxl__ev_xswatch *watch,
1647 const char *watch_path,
1648 const char *event_path)
1649 {
1650 libxl__ddomain *ddomain = CONTAINER_OF(watch, *ddomain, watch);
1651 libxl__ao *nested_ao = libxl__nested_ao_create(ddomain->ao);
1652 STATE_AO_GC(nested_ao);
1653 char *p, *path;
1654 const char *sstate, *sonline;
1655 int state, online, rc;
1656 libxl__device *dev;
1657 libxl__ddomain_device *ddev = NULL;
1658 libxl__ddomain_guest *dguest = NULL;
1659 bool free_ao = false;
1660
1661 /* Check if event_path ends with "state" or "online" and truncate it. */
1662 path = libxl__strdup(gc, event_path);
1663 p = strrchr(path, '/');
1664 if (p == NULL)
1665 goto skip;
1666 if (strcmp(p, "/state") != 0 && strcmp(p, "/online") != 0)
1667 goto skip;
1668 /* Truncate the string so it points to the backend directory. */
1669 *p = '\0';
1670
1671 /* Fetch the value of the state and online nodes. */
1672 rc = libxl__xs_read_checked(gc, XBT_NULL, GCSPRINTF("%s/state", path),
1673 &sstate);
1674 if (rc || !sstate)
1675 goto skip;
1676 state = atoi(sstate);
1677
1678 rc = libxl__xs_read_checked(gc, XBT_NULL, GCSPRINTF("%s/online", path),
1679 &sonline);
1680 if (rc || !sonline)
1681 goto skip;
1682 online = atoi(sonline);
1683
1684 GCNEW(dev);
1685 rc = libxl__parse_backend_path(gc, path, dev);
1686 if (rc)
1687 goto skip;
1688
1689 dguest = search_for_guest(ddomain, dev->domid);
1690 if (dguest == NULL && state == XenbusStateClosed) {
1691 /*
1692 * Spurious state change, device has already been disconnected
1693 * or never attached.
1694 */
1695 goto skip;
1696 }
1697 if (dguest == NULL) {
1698 /* Create a new guest struct and initialize it */
1699 dguest = libxl__zalloc(NOGC, sizeof(*dguest));
1700 dguest->domid = dev->domid;
1701 LIBXL_SLIST_INIT(&dguest->devices);
1702 LIBXL_SLIST_INSERT_HEAD(&ddomain->guests, dguest, next);
1703 LOGD(DEBUG, dguest->domid, "Added domain to the list of active guests");
1704 }
1705 ddev = search_for_device(dguest, dev);
1706 if (ddev == NULL && state == XenbusStateClosed) {
1707 /*
1708 * Spurious state change, device has already been disconnected
1709 * or never attached.
1710 */
1711 goto skip;
1712 } else if (ddev == NULL) {
1713 rc = add_device(egc, nested_ao, dguest, dev);
1714 if (rc > 0)
1715 free_ao = true;
1716 } else if (state == XenbusStateClosed && online == 0) {
1717 rc = remove_device(egc, nested_ao, dguest, ddev);
1718 if (rc > 0)
1719 free_ao = true;
1720 check_and_maybe_remove_guest(gc, ddomain, dguest);
1721 }
1722
1723 if (free_ao)
1724 libxl__nested_ao_free(nested_ao);
1725
1726 return;
1727
1728 skip:
1729 libxl__nested_ao_free(nested_ao);
1730 check_and_maybe_remove_guest(gc, ddomain, dguest);
1731 return;
1732 }
1733
1734 /* Handler of events for device driver domains */
libxl_device_events_handler(libxl_ctx * ctx,const libxl_asyncop_how * ao_how)1735 int libxl_device_events_handler(libxl_ctx *ctx,
1736 const libxl_asyncop_how *ao_how)
1737 {
1738 AO_CREATE(ctx, 0, ao_how);
1739 int rc;
1740 uint32_t domid;
1741 libxl__ddomain ddomain;
1742 char *be_path;
1743 char **kinds = NULL, **domains = NULL, **devs = NULL;
1744 const char *sstate;
1745 char *state_path;
1746 int state;
1747 unsigned int nkinds, ndomains, ndevs;
1748 int i, j, k;
1749
1750 ddomain.ao = ao;
1751 LIBXL_SLIST_INIT(&ddomain.guests);
1752
1753 rc = libxl__get_domid(gc, &domid);
1754 if (rc) {
1755 LOG(ERROR, "unable to get domain id");
1756 goto out;
1757 }
1758
1759 /*
1760 * We use absolute paths because we want xswatch to also return
1761 * absolute paths that can be parsed by libxl__parse_backend_path.
1762 */
1763 be_path = GCSPRINTF("/local/domain/%u/backend", domid);
1764 rc = libxl__ev_xswatch_register(gc, &ddomain.watch, backend_watch_callback,
1765 be_path);
1766 if (rc) goto out;
1767
1768 kinds = libxl__xs_directory(gc, XBT_NULL, be_path, &nkinds);
1769 if (kinds) {
1770 for (i = 0; i < nkinds; i++) {
1771 domains = libxl__xs_directory(gc, XBT_NULL,
1772 GCSPRINTF("%s/%s", be_path, kinds[i]), &ndomains);
1773 if (!domains)
1774 continue;
1775 for (j = 0; j < ndomains; j++) {
1776 devs = libxl__xs_directory(gc, XBT_NULL,
1777 GCSPRINTF("%s/%s/%s", be_path, kinds[i], domains[j]), &ndevs);
1778 if (!devs)
1779 continue;
1780 for (k = 0; k < ndevs; k++) {
1781 state_path = GCSPRINTF("%s/%s/%s/%s/state",
1782 be_path, kinds[i], domains[j], devs[k]);
1783 rc = libxl__xs_read_checked(gc, XBT_NULL, state_path, &sstate);
1784 if (rc || !sstate)
1785 continue;
1786 state = atoi(sstate);
1787 if (state == XenbusStateInitWait)
1788 backend_watch_callback(egc, &ddomain.watch,
1789 be_path, state_path);
1790 }
1791 }
1792 }
1793 }
1794
1795 return AO_INPROGRESS;
1796
1797 out:
1798 return AO_CREATE_FAIL(rc);
1799 }
1800
device_add_domain_config(libxl__gc * gc,libxl_domain_config * d_config,const struct libxl_device_type * dt,void * type)1801 void device_add_domain_config(libxl__gc *gc, libxl_domain_config *d_config,
1802 const struct libxl_device_type *dt, void *type)
1803 {
1804 int *num_dev;
1805 unsigned int i;
1806 void *item = NULL;
1807
1808 num_dev = libxl__device_type_get_num(dt, d_config);
1809
1810 /* Check for existing device */
1811 for (i = 0; i < *num_dev; i++) {
1812 if (dt->compare(libxl__device_type_get_elem(dt, d_config, i), type)) {
1813 item = libxl__device_type_get_elem(dt, d_config, i);
1814 }
1815 }
1816
1817 if (!item) {
1818 void **devs = libxl__device_type_get_ptr(dt, d_config);
1819 *devs = libxl__realloc(NOGC, *devs,
1820 dt->dev_elem_size * (*num_dev + 1));
1821 item = libxl__device_type_get_elem(dt, d_config, *num_dev);
1822 (*num_dev)++;
1823 } else {
1824 dt->dispose(item);
1825 }
1826
1827 dt->init(item);
1828 dt->copy(CTX, item, type);
1829 }
1830
libxl__device_add_async(libxl__egc * egc,uint32_t domid,const struct libxl_device_type * dt,void * type,libxl__ao_device * aodev)1831 void libxl__device_add_async(libxl__egc *egc, uint32_t domid,
1832 const struct libxl_device_type *dt, void *type,
1833 libxl__ao_device *aodev)
1834 {
1835 STATE_AO_GC(aodev->ao);
1836 flexarray_t *back;
1837 flexarray_t *front, *ro_front;
1838 libxl__device *device;
1839 xs_transaction_t t = XBT_NULL;
1840 libxl_domain_config d_config;
1841 void *type_saved;
1842 libxl__domain_userdata_lock *lock = NULL;
1843 int rc;
1844
1845 libxl_domain_config_init(&d_config);
1846
1847 type_saved = libxl__malloc(gc, dt->dev_elem_size);
1848
1849 dt->init(type_saved);
1850 dt->copy(CTX, type_saved, type);
1851
1852 if (dt->set_default) {
1853 rc = dt->set_default(gc, domid, type, aodev->update_json);
1854 if (rc) goto out;
1855 }
1856
1857 if (dt->update_devid) {
1858 rc = dt->update_devid(gc, domid, type);
1859 if (rc) goto out;
1860 }
1861
1862 if (dt->update_config)
1863 dt->update_config(gc, type_saved, type);
1864
1865 GCNEW(device);
1866 rc = dt->to_device(gc, domid, type, device);
1867 if (rc) goto out;
1868
1869 if (aodev->update_json) {
1870 lock = libxl__lock_domain_userdata(gc, domid);
1871 if (!lock) {
1872 rc = ERROR_LOCK_FAIL;
1873 goto out;
1874 }
1875
1876 rc = libxl__get_domain_configuration(gc, domid, &d_config);
1877 if (rc) goto out;
1878
1879 device_add_domain_config(gc, &d_config, dt, type_saved);
1880
1881 rc = libxl__dm_check_start(gc, &d_config, domid);
1882 if (rc) goto out;
1883 }
1884
1885 back = flexarray_make(gc, 16, 1);
1886 front = flexarray_make(gc, 16, 1);
1887 ro_front = flexarray_make(gc, 16, 1);
1888
1889 flexarray_append_pair(back, "frontend-id", GCSPRINTF("%d", domid));
1890 flexarray_append_pair(back, "online", "1");
1891 flexarray_append_pair(back, "state",
1892 GCSPRINTF("%d", XenbusStateInitialising));
1893
1894 flexarray_append_pair(front, "backend-id",
1895 GCSPRINTF("%d", device->backend_domid));
1896 flexarray_append_pair(front, "state",
1897 GCSPRINTF("%d", XenbusStateInitialising));
1898
1899 if (dt->set_xenstore_config)
1900 dt->set_xenstore_config(gc, domid, type, back, front, ro_front);
1901
1902 for (;;) {
1903 rc = libxl__xs_transaction_start(gc, &t);
1904 if (rc) goto out;
1905
1906 rc = libxl__device_exists(gc, t, device);
1907 if (rc < 0) goto out;
1908 if (rc == 1) { /* already exists in xenstore */
1909 LOGD(ERROR, domid, "device already exists in xenstore");
1910 aodev->action = LIBXL__DEVICE_ACTION_ADD; /* for error message */
1911 rc = ERROR_DEVICE_EXISTS;
1912 goto out;
1913 }
1914
1915 if (aodev->update_json) {
1916 rc = libxl__set_domain_configuration(gc, domid, &d_config);
1917 if (rc) goto out;
1918 }
1919
1920 libxl__device_generic_add(gc, t, device,
1921 libxl__xs_kvs_of_flexarray(gc, back),
1922 libxl__xs_kvs_of_flexarray(gc, front),
1923 libxl__xs_kvs_of_flexarray(gc, ro_front));
1924
1925 rc = libxl__xs_transaction_commit(gc, &t);
1926 if (!rc) break;
1927 if (rc < 0) goto out;
1928 }
1929
1930 aodev->dev = device;
1931 aodev->action = LIBXL__DEVICE_ACTION_ADD;
1932 libxl__wait_device_connection(egc, aodev);
1933
1934 rc = 0;
1935
1936 out:
1937 libxl__xs_transaction_abort(gc, &t);
1938 if (lock) libxl__unlock_domain_userdata(lock);
1939 dt->dispose(type_saved);
1940 libxl_domain_config_dispose(&d_config);
1941 aodev->rc = rc;
1942 if (rc) aodev->callback(egc, aodev);
1943 return;
1944 }
1945
libxl__device_add(libxl__gc * gc,uint32_t domid,const struct libxl_device_type * dt,void * type)1946 int libxl__device_add(libxl__gc *gc, uint32_t domid,
1947 const struct libxl_device_type *dt, void *type)
1948 {
1949 flexarray_t *back;
1950 flexarray_t *front, *ro_front;
1951 libxl__device *device;
1952 int rc;
1953
1954 if (dt->set_default) {
1955 rc = dt->set_default(gc, domid, type, false);
1956 if (rc) goto out;
1957 }
1958
1959 if (dt->update_devid) {
1960 rc = dt->update_devid(gc, domid, type);
1961 if (rc) goto out;
1962 }
1963
1964 GCNEW(device);
1965 rc = dt->to_device(gc, domid, type, device);
1966 if (rc) goto out;
1967
1968 back = flexarray_make(gc, 16, 1);
1969 front = flexarray_make(gc, 16, 1);
1970 ro_front = flexarray_make(gc, 16, 1);
1971
1972 flexarray_append_pair(back, "frontend-id", GCSPRINTF("%d", domid));
1973 flexarray_append_pair(back, "online", "1");
1974 flexarray_append_pair(back, "state",
1975 GCSPRINTF("%d", XenbusStateInitialising));
1976 flexarray_append_pair(front, "backend-id",
1977 libxl__sprintf(gc, "%d", device->backend_domid));
1978 flexarray_append_pair(front, "state",
1979 GCSPRINTF("%d", XenbusStateInitialising));
1980
1981 if (dt->set_xenstore_config)
1982 dt->set_xenstore_config(gc, domid, type, back, front, ro_front);
1983
1984 rc = libxl__device_generic_add(gc, XBT_NULL, device,
1985 libxl__xs_kvs_of_flexarray(gc, back),
1986 libxl__xs_kvs_of_flexarray(gc, front),
1987 libxl__xs_kvs_of_flexarray(gc, ro_front));
1988 if (rc) goto out;
1989
1990 rc = 0;
1991
1992 out:
1993 return rc;
1994 }
1995
libxl__device_list(libxl__gc * gc,const struct libxl_device_type * dt,uint32_t domid,int * num)1996 void *libxl__device_list(libxl__gc *gc, const struct libxl_device_type *dt,
1997 uint32_t domid, int *num)
1998 {
1999 void *r = NULL;
2000 void *list = NULL;
2001 void *item = NULL;
2002 char *libxl_path;
2003 char **dir = NULL;
2004 unsigned int ndirs = 0;
2005 int rc;
2006
2007 *num = 0;
2008
2009 libxl_path = GCSPRINTF("%s/device/%s",
2010 libxl__xs_libxl_path(gc, domid), dt->entry);
2011
2012 dir = libxl__xs_directory(gc, XBT_NULL, libxl_path, &ndirs);
2013
2014 if (dir && ndirs) {
2015 list = libxl__malloc(NOGC, dt->dev_elem_size * ndirs);
2016 item = list;
2017
2018 while (*num < ndirs) {
2019 dt->init(item);
2020 ++(*num);
2021
2022 if (dt->from_xenstore) {
2023 char *device_libxl_path = GCSPRINTF("%s/%s", libxl_path, *dir);
2024 rc = dt->from_xenstore(gc, device_libxl_path, atoi(*dir), item);
2025 if (rc) goto out;
2026 }
2027
2028 item = (uint8_t *)item + dt->dev_elem_size;
2029 ++dir;
2030 }
2031 }
2032
2033 r = list;
2034 list = NULL;
2035
2036 out:
2037
2038 if (list) {
2039 libxl__device_list_free(dt, list, *num);
2040 *num = 0;
2041 }
2042
2043 return r;
2044 }
2045
libxl__device_list_free(const struct libxl_device_type * dt,void * list,int num)2046 void libxl__device_list_free(const struct libxl_device_type *dt,
2047 void *list, int num)
2048 {
2049 int i;
2050
2051 for (i = 0; i < num; i++)
2052 dt->dispose((uint8_t*)list + i * dt->dev_elem_size);
2053
2054 free(list);
2055 }
2056
2057 /*
2058 * Local variables:
2059 * mode: C
2060 * c-basic-offset: 4
2061 * indent-tabs-mode: nil
2062 * End:
2063 */
2064