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