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