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