xref: /openbmc/qemu/hw/block/xen-block.c (revision 5cc8767d)
1 /*
2  * Copyright (c) 2018  Citrix Systems Inc.
3  *
4  * This work is licensed under the terms of the GNU GPL, version 2 or later.
5  * See the COPYING file in the top-level directory.
6  */
7 
8 #include "qemu/osdep.h"
9 #include "qemu/cutils.h"
10 #include "qemu/module.h"
11 #include "qemu/option.h"
12 #include "qapi/error.h"
13 #include "qapi/qapi-commands-block-core.h"
14 #include "qapi/qapi-commands-qom.h"
15 #include "qapi/qapi-visit-block-core.h"
16 #include "qapi/qobject-input-visitor.h"
17 #include "qapi/visitor.h"
18 #include "qapi/qmp/qdict.h"
19 #include "qapi/qmp/qstring.h"
20 #include "hw/hw.h"
21 #include "hw/xen/xen_common.h"
22 #include "hw/block/xen_blkif.h"
23 #include "hw/xen/xen-block.h"
24 #include "hw/xen/xen-backend.h"
25 #include "sysemu/blockdev.h"
26 #include "sysemu/block-backend.h"
27 #include "sysemu/iothread.h"
28 #include "dataplane/xen-block.h"
29 #include "trace.h"
30 
31 static char *xen_block_get_name(XenDevice *xendev, Error **errp)
32 {
33     XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev);
34     XenBlockVdev *vdev = &blockdev->props.vdev;
35 
36     return g_strdup_printf("%lu", vdev->number);
37 }
38 
39 static void xen_block_disconnect(XenDevice *xendev, Error **errp)
40 {
41     XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev);
42     const char *type = object_get_typename(OBJECT(blockdev));
43     XenBlockVdev *vdev = &blockdev->props.vdev;
44 
45     trace_xen_block_disconnect(type, vdev->disk, vdev->partition);
46 
47     xen_block_dataplane_stop(blockdev->dataplane);
48 }
49 
50 static void xen_block_connect(XenDevice *xendev, Error **errp)
51 {
52     XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev);
53     const char *type = object_get_typename(OBJECT(blockdev));
54     XenBlockVdev *vdev = &blockdev->props.vdev;
55     BlockConf *conf = &blockdev->props.conf;
56     unsigned int feature_large_sector_size;
57     unsigned int order, nr_ring_ref, *ring_ref, event_channel, protocol;
58     char *str;
59 
60     trace_xen_block_connect(type, vdev->disk, vdev->partition);
61 
62     if (xen_device_frontend_scanf(xendev, "feature-large-sector-size", "%u",
63                                   &feature_large_sector_size) != 1) {
64         feature_large_sector_size = 0;
65     }
66 
67     if (feature_large_sector_size != 1 &&
68         conf->logical_block_size != XEN_BLKIF_SECTOR_SIZE) {
69         error_setg(errp, "logical_block_size != %u not supported by frontend",
70                    XEN_BLKIF_SECTOR_SIZE);
71         return;
72     }
73 
74     if (xen_device_frontend_scanf(xendev, "ring-page-order", "%u",
75                                   &order) != 1) {
76         nr_ring_ref = 1;
77         ring_ref = g_new(unsigned int, nr_ring_ref);
78 
79         if (xen_device_frontend_scanf(xendev, "ring-ref", "%u",
80                                       &ring_ref[0]) != 1) {
81             error_setg(errp, "failed to read ring-ref");
82             g_free(ring_ref);
83             return;
84         }
85     } else if (order <= blockdev->props.max_ring_page_order) {
86         unsigned int i;
87 
88         nr_ring_ref = 1 << order;
89         ring_ref = g_new(unsigned int, nr_ring_ref);
90 
91         for (i = 0; i < nr_ring_ref; i++) {
92             const char *key = g_strdup_printf("ring-ref%u", i);
93 
94             if (xen_device_frontend_scanf(xendev, key, "%u",
95                                           &ring_ref[i]) != 1) {
96                 error_setg(errp, "failed to read %s", key);
97                 g_free((gpointer)key);
98                 g_free(ring_ref);
99                 return;
100             }
101 
102             g_free((gpointer)key);
103         }
104     } else {
105         error_setg(errp, "invalid ring-page-order (%d)", order);
106         return;
107     }
108 
109     if (xen_device_frontend_scanf(xendev, "event-channel", "%u",
110                                   &event_channel) != 1) {
111         error_setg(errp, "failed to read event-channel");
112         g_free(ring_ref);
113         return;
114     }
115 
116     if (xen_device_frontend_scanf(xendev, "protocol", "%ms",
117                                   &str) != 1) {
118         protocol = BLKIF_PROTOCOL_NATIVE;
119     } else {
120         if (strcmp(str, XEN_IO_PROTO_ABI_X86_32) == 0) {
121             protocol = BLKIF_PROTOCOL_X86_32;
122         } else if (strcmp(str, XEN_IO_PROTO_ABI_X86_64) == 0) {
123             protocol = BLKIF_PROTOCOL_X86_64;
124         } else {
125             protocol = BLKIF_PROTOCOL_NATIVE;
126         }
127 
128         free(str);
129     }
130 
131     xen_block_dataplane_start(blockdev->dataplane, ring_ref, nr_ring_ref,
132                               event_channel, protocol, errp);
133 
134     g_free(ring_ref);
135 }
136 
137 static void xen_block_unrealize(XenDevice *xendev, Error **errp)
138 {
139     XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev);
140     XenBlockDeviceClass *blockdev_class =
141         XEN_BLOCK_DEVICE_GET_CLASS(xendev);
142     const char *type = object_get_typename(OBJECT(blockdev));
143     XenBlockVdev *vdev = &blockdev->props.vdev;
144 
145     if (vdev->type == XEN_BLOCK_VDEV_TYPE_INVALID) {
146         return;
147     }
148 
149     trace_xen_block_unrealize(type, vdev->disk, vdev->partition);
150 
151     /* Disconnect from the frontend in case this has not already happened */
152     xen_block_disconnect(xendev, NULL);
153 
154     xen_block_dataplane_destroy(blockdev->dataplane);
155     blockdev->dataplane = NULL;
156 
157     if (blockdev_class->unrealize) {
158         blockdev_class->unrealize(blockdev, errp);
159     }
160 }
161 
162 static void xen_block_set_size(XenBlockDevice *blockdev)
163 {
164     const char *type = object_get_typename(OBJECT(blockdev));
165     XenBlockVdev *vdev = &blockdev->props.vdev;
166     BlockConf *conf = &blockdev->props.conf;
167     int64_t sectors = blk_getlength(conf->blk) / conf->logical_block_size;
168     XenDevice *xendev = XEN_DEVICE(blockdev);
169 
170     trace_xen_block_size(type, vdev->disk, vdev->partition, sectors);
171 
172     xen_device_backend_printf(xendev, "sectors", "%"PRIi64, sectors);
173 }
174 
175 static void xen_block_resize_cb(void *opaque)
176 {
177     XenBlockDevice *blockdev = opaque;
178     XenDevice *xendev = XEN_DEVICE(blockdev);
179     enum xenbus_state state = xen_device_backend_get_state(xendev);
180 
181     xen_block_set_size(blockdev);
182 
183     /*
184      * Mimic the behaviour of Linux xen-blkback and re-write the state
185      * to trigger the frontend watch.
186      */
187     xen_device_backend_printf(xendev, "state", "%u", state);
188 }
189 
190 static const BlockDevOps xen_block_dev_ops = {
191     .resize_cb = xen_block_resize_cb,
192 };
193 
194 static void xen_block_realize(XenDevice *xendev, Error **errp)
195 {
196     XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev);
197     XenBlockDeviceClass *blockdev_class =
198         XEN_BLOCK_DEVICE_GET_CLASS(xendev);
199     const char *type = object_get_typename(OBJECT(blockdev));
200     XenBlockVdev *vdev = &blockdev->props.vdev;
201     BlockConf *conf = &blockdev->props.conf;
202     BlockBackend *blk = conf->blk;
203     Error *local_err = NULL;
204 
205     if (vdev->type == XEN_BLOCK_VDEV_TYPE_INVALID) {
206         error_setg(errp, "vdev property not set");
207         return;
208     }
209 
210     trace_xen_block_realize(type, vdev->disk, vdev->partition);
211 
212     if (blockdev_class->realize) {
213         blockdev_class->realize(blockdev, &local_err);
214         if (local_err) {
215             error_propagate(errp, local_err);
216             return;
217         }
218     }
219 
220     /*
221      * The blkif protocol does not deal with removable media, so it must
222      * always be present, even for CDRom devices.
223      */
224     assert(blk);
225     if (!blk_is_inserted(blk)) {
226         error_setg(errp, "device needs media, but drive is empty");
227         return;
228     }
229 
230     if (!blkconf_apply_backend_options(conf, blockdev->info & VDISK_READONLY,
231                                        true, errp)) {
232         return;
233     }
234 
235     if (!(blockdev->info & VDISK_CDROM) &&
236         !blkconf_geometry(conf, NULL, 65535, 255, 255, errp)) {
237         return;
238     }
239 
240     blkconf_blocksizes(conf);
241 
242     if (conf->logical_block_size > conf->physical_block_size) {
243         error_setg(
244             errp, "logical_block_size > physical_block_size not supported");
245         return;
246     }
247 
248     blk_set_dev_ops(blk, &xen_block_dev_ops, blockdev);
249     blk_set_guest_block_size(blk, conf->logical_block_size);
250 
251     if (conf->discard_granularity == -1) {
252         conf->discard_granularity = conf->physical_block_size;
253     }
254 
255     if (blk_get_flags(blk) & BDRV_O_UNMAP) {
256         xen_device_backend_printf(xendev, "feature-discard", "%u", 1);
257         xen_device_backend_printf(xendev, "discard-granularity", "%u",
258                                   conf->discard_granularity);
259     }
260 
261     xen_device_backend_printf(xendev, "feature-flush-cache", "%u", 1);
262     xen_device_backend_printf(xendev, "max-ring-page-order", "%u",
263                               blockdev->props.max_ring_page_order);
264     xen_device_backend_printf(xendev, "info", "%u", blockdev->info);
265 
266     xen_device_frontend_printf(xendev, "virtual-device", "%lu",
267                                vdev->number);
268     xen_device_frontend_printf(xendev, "device-type", "%s",
269                                blockdev->device_type);
270 
271     xen_device_backend_printf(xendev, "sector-size", "%u",
272                               conf->logical_block_size);
273 
274     xen_block_set_size(blockdev);
275 
276     blockdev->dataplane =
277         xen_block_dataplane_create(xendev, blk, conf->logical_block_size,
278                                    blockdev->props.iothread);
279 }
280 
281 static void xen_block_frontend_changed(XenDevice *xendev,
282                                        enum xenbus_state frontend_state,
283                                        Error **errp)
284 {
285     enum xenbus_state backend_state = xen_device_backend_get_state(xendev);
286     Error *local_err = NULL;
287 
288     switch (frontend_state) {
289     case XenbusStateInitialised:
290     case XenbusStateConnected:
291         if (backend_state == XenbusStateConnected) {
292             break;
293         }
294 
295         xen_block_disconnect(xendev, &local_err);
296         if (local_err) {
297             error_propagate(errp, local_err);
298             break;
299         }
300 
301         xen_block_connect(xendev, &local_err);
302         if (local_err) {
303             error_propagate(errp, local_err);
304             break;
305         }
306 
307         xen_device_backend_set_state(xendev, XenbusStateConnected);
308         break;
309 
310     case XenbusStateClosing:
311         xen_device_backend_set_state(xendev, XenbusStateClosing);
312         break;
313 
314     case XenbusStateClosed:
315         xen_block_disconnect(xendev, &local_err);
316         if (local_err) {
317             error_propagate(errp, local_err);
318             break;
319         }
320 
321         xen_device_backend_set_state(xendev, XenbusStateClosed);
322         break;
323 
324     default:
325         break;
326     }
327 }
328 
329 static char *disk_to_vbd_name(unsigned int disk)
330 {
331     char *name, *prefix = (disk >= 26) ?
332         disk_to_vbd_name((disk / 26) - 1) : g_strdup("");
333 
334     name = g_strdup_printf("%s%c", prefix, 'a' + disk % 26);
335     g_free(prefix);
336 
337     return name;
338 }
339 
340 static void xen_block_get_vdev(Object *obj, Visitor *v, const char *name,
341                                void *opaque, Error **errp)
342 {
343     DeviceState *dev = DEVICE(obj);
344     Property *prop = opaque;
345     XenBlockVdev *vdev = qdev_get_prop_ptr(dev, prop);
346     char *str;
347 
348     switch (vdev->type) {
349     case XEN_BLOCK_VDEV_TYPE_DP:
350         str = g_strdup_printf("d%lup%lu", vdev->disk, vdev->partition);
351         break;
352 
353     case XEN_BLOCK_VDEV_TYPE_XVD:
354     case XEN_BLOCK_VDEV_TYPE_HD:
355     case XEN_BLOCK_VDEV_TYPE_SD: {
356         char *name = disk_to_vbd_name(vdev->disk);
357 
358         str = g_strdup_printf("%s%s%lu",
359                               (vdev->type == XEN_BLOCK_VDEV_TYPE_XVD) ?
360                               "xvd" :
361                               (vdev->type == XEN_BLOCK_VDEV_TYPE_HD) ?
362                               "hd" :
363                               "sd",
364                               name, vdev->partition);
365         g_free(name);
366         break;
367     }
368     default:
369         error_setg(errp, "invalid vdev type");
370         return;
371     }
372 
373     visit_type_str(v, name, &str, errp);
374     g_free(str);
375 }
376 
377 static int vbd_name_to_disk(const char *name, const char **endp,
378                             unsigned long *disk)
379 {
380     unsigned int n = 0;
381 
382     while (*name != '\0') {
383         if (!g_ascii_isalpha(*name) || !g_ascii_islower(*name)) {
384             break;
385         }
386 
387         n *= 26;
388         n += *name++ - 'a' + 1;
389     }
390     *endp = name;
391 
392     if (!n) {
393         return -1;
394     }
395 
396     *disk = n - 1;
397 
398     return 0;
399 }
400 
401 static void xen_block_set_vdev(Object *obj, Visitor *v, const char *name,
402                                void *opaque, Error **errp)
403 {
404     DeviceState *dev = DEVICE(obj);
405     Property *prop = opaque;
406     XenBlockVdev *vdev = qdev_get_prop_ptr(dev, prop);
407     Error *local_err = NULL;
408     char *str, *p;
409     const char *end;
410 
411     if (dev->realized) {
412         qdev_prop_set_after_realize(dev, name, errp);
413         return;
414     }
415 
416     visit_type_str(v, name, &str, &local_err);
417     if (local_err) {
418         error_propagate(errp, local_err);
419         return;
420     }
421 
422     p = strchr(str, 'd');
423     if (!p) {
424         goto invalid;
425     }
426 
427     *p++ = '\0';
428     if (*str == '\0') {
429         vdev->type = XEN_BLOCK_VDEV_TYPE_DP;
430     } else if (strcmp(str, "xv") == 0) {
431         vdev->type = XEN_BLOCK_VDEV_TYPE_XVD;
432     } else if (strcmp(str, "h") == 0) {
433         vdev->type = XEN_BLOCK_VDEV_TYPE_HD;
434     } else if (strcmp(str, "s") == 0) {
435         vdev->type = XEN_BLOCK_VDEV_TYPE_SD;
436     } else {
437         goto invalid;
438     }
439 
440     if (vdev->type == XEN_BLOCK_VDEV_TYPE_DP) {
441         if (qemu_strtoul(p, &end, 10, &vdev->disk)) {
442             goto invalid;
443         }
444 
445         if (*end == 'p') {
446             if (*(++end) == '\0') {
447                 goto invalid;
448             }
449         }
450     } else {
451         if (vbd_name_to_disk(p, &end, &vdev->disk)) {
452             goto invalid;
453         }
454     }
455 
456     if (*end != '\0') {
457         p = (char *)end;
458 
459         if (qemu_strtoul(p, &end, 10, &vdev->partition)) {
460             goto invalid;
461         }
462 
463         if (*end != '\0') {
464             goto invalid;
465         }
466     } else {
467         vdev->partition = 0;
468     }
469 
470     switch (vdev->type) {
471     case XEN_BLOCK_VDEV_TYPE_DP:
472     case XEN_BLOCK_VDEV_TYPE_XVD:
473         if (vdev->disk < (1 << 4) && vdev->partition < (1 << 4)) {
474             vdev->number = (202 << 8) | (vdev->disk << 4) |
475                 vdev->partition;
476         } else if (vdev->disk < (1 << 20) && vdev->partition < (1 << 8)) {
477             vdev->number = (1 << 28) | (vdev->disk << 8) |
478                 vdev->partition;
479         } else {
480             goto invalid;
481         }
482         break;
483 
484     case XEN_BLOCK_VDEV_TYPE_HD:
485         if ((vdev->disk == 0 || vdev->disk == 1) &&
486             vdev->partition < (1 << 6)) {
487             vdev->number = (3 << 8) | (vdev->disk << 6) | vdev->partition;
488         } else if ((vdev->disk == 2 || vdev->disk == 3) &&
489                    vdev->partition < (1 << 6)) {
490             vdev->number = (22 << 8) | ((vdev->disk - 2) << 6) |
491                 vdev->partition;
492         } else {
493             goto invalid;
494         }
495         break;
496 
497     case XEN_BLOCK_VDEV_TYPE_SD:
498         if (vdev->disk < (1 << 4) && vdev->partition < (1 << 4)) {
499             vdev->number = (8 << 8) | (vdev->disk << 4) | vdev->partition;
500         } else {
501             goto invalid;
502         }
503         break;
504 
505     default:
506         goto invalid;
507     }
508 
509     g_free(str);
510     return;
511 
512 invalid:
513     error_setg(errp, "invalid virtual disk specifier");
514 
515     vdev->type = XEN_BLOCK_VDEV_TYPE_INVALID;
516     g_free(str);
517 }
518 
519 /*
520  * This property deals with 'vdev' names adhering to the Xen VBD naming
521  * scheme described in:
522  *
523  * https://xenbits.xen.org/docs/unstable/man/xen-vbd-interface.7.html
524  */
525 const PropertyInfo xen_block_prop_vdev = {
526     .name  = "str",
527     .description = "Virtual Disk specifier: d*p*/xvd*/hd*/sd*",
528     .get = xen_block_get_vdev,
529     .set = xen_block_set_vdev,
530 };
531 
532 static Property xen_block_props[] = {
533     DEFINE_PROP("vdev", XenBlockDevice, props.vdev,
534                 xen_block_prop_vdev, XenBlockVdev),
535     DEFINE_BLOCK_PROPERTIES(XenBlockDevice, props.conf),
536     DEFINE_PROP_UINT32("max-ring-page-order", XenBlockDevice,
537                        props.max_ring_page_order, 4),
538     DEFINE_PROP_LINK("iothread", XenBlockDevice, props.iothread,
539                      TYPE_IOTHREAD, IOThread *),
540     DEFINE_PROP_END_OF_LIST()
541 };
542 
543 static void xen_block_class_init(ObjectClass *class, void *data)
544 {
545     DeviceClass *dev_class = DEVICE_CLASS(class);
546     XenDeviceClass *xendev_class = XEN_DEVICE_CLASS(class);
547 
548     xendev_class->backend = "qdisk";
549     xendev_class->device = "vbd";
550     xendev_class->get_name = xen_block_get_name;
551     xendev_class->realize = xen_block_realize;
552     xendev_class->frontend_changed = xen_block_frontend_changed;
553     xendev_class->unrealize = xen_block_unrealize;
554 
555     dev_class->props = xen_block_props;
556 }
557 
558 static const TypeInfo xen_block_type_info = {
559     .name = TYPE_XEN_BLOCK_DEVICE,
560     .parent = TYPE_XEN_DEVICE,
561     .instance_size = sizeof(XenBlockDevice),
562     .abstract = true,
563     .class_size = sizeof(XenBlockDeviceClass),
564     .class_init = xen_block_class_init,
565 };
566 
567 static void xen_disk_unrealize(XenBlockDevice *blockdev, Error **errp)
568 {
569     trace_xen_disk_unrealize();
570 }
571 
572 static void xen_disk_realize(XenBlockDevice *blockdev, Error **errp)
573 {
574     BlockConf *conf = &blockdev->props.conf;
575 
576     trace_xen_disk_realize();
577 
578     blockdev->device_type = "disk";
579 
580     if (!conf->blk) {
581         error_setg(errp, "drive property not set");
582         return;
583     }
584 
585     blockdev->info = blk_is_read_only(conf->blk) ? VDISK_READONLY : 0;
586 }
587 
588 static void xen_disk_class_init(ObjectClass *class, void *data)
589 {
590     DeviceClass *dev_class = DEVICE_CLASS(class);
591     XenBlockDeviceClass *blockdev_class = XEN_BLOCK_DEVICE_CLASS(class);
592 
593     blockdev_class->realize = xen_disk_realize;
594     blockdev_class->unrealize = xen_disk_unrealize;
595 
596     dev_class->desc = "Xen Disk Device";
597 }
598 
599 static const TypeInfo xen_disk_type_info = {
600     .name = TYPE_XEN_DISK_DEVICE,
601     .parent = TYPE_XEN_BLOCK_DEVICE,
602     .instance_size = sizeof(XenDiskDevice),
603     .class_init = xen_disk_class_init,
604 };
605 
606 static void xen_cdrom_unrealize(XenBlockDevice *blockdev, Error **errp)
607 {
608     trace_xen_cdrom_unrealize();
609 }
610 
611 static void xen_cdrom_realize(XenBlockDevice *blockdev, Error **errp)
612 {
613     BlockConf *conf = &blockdev->props.conf;
614 
615     trace_xen_cdrom_realize();
616 
617     blockdev->device_type = "cdrom";
618 
619     if (!conf->blk) {
620         int rc;
621 
622         /* Set up an empty drive */
623         conf->blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
624 
625         rc = blk_attach_dev(conf->blk, DEVICE(blockdev));
626         if (!rc) {
627             error_setg_errno(errp, -rc, "failed to create drive");
628             return;
629         }
630     }
631 
632     blockdev->info = VDISK_READONLY | VDISK_CDROM;
633 }
634 
635 static void xen_cdrom_class_init(ObjectClass *class, void *data)
636 {
637     DeviceClass *dev_class = DEVICE_CLASS(class);
638     XenBlockDeviceClass *blockdev_class = XEN_BLOCK_DEVICE_CLASS(class);
639 
640     blockdev_class->realize = xen_cdrom_realize;
641     blockdev_class->unrealize = xen_cdrom_unrealize;
642 
643     dev_class->desc = "Xen CD-ROM Device";
644 }
645 
646 static const TypeInfo xen_cdrom_type_info = {
647     .name = TYPE_XEN_CDROM_DEVICE,
648     .parent = TYPE_XEN_BLOCK_DEVICE,
649     .instance_size = sizeof(XenCDRomDevice),
650     .class_init = xen_cdrom_class_init,
651 };
652 
653 static void xen_block_register_types(void)
654 {
655     type_register_static(&xen_block_type_info);
656     type_register_static(&xen_disk_type_info);
657     type_register_static(&xen_cdrom_type_info);
658 }
659 
660 type_init(xen_block_register_types)
661 
662 static void xen_block_blockdev_del(const char *node_name, Error **errp)
663 {
664     trace_xen_block_blockdev_del(node_name);
665 
666     qmp_blockdev_del(node_name, errp);
667 }
668 
669 static char *xen_block_blockdev_add(const char *id, QDict *qdict,
670                                     Error **errp)
671 {
672     const char *driver = qdict_get_try_str(qdict, "driver");
673     BlockdevOptions *options = NULL;
674     Error *local_err = NULL;
675     char *node_name;
676     Visitor *v;
677 
678     if (!driver) {
679         error_setg(errp, "no 'driver' parameter");
680         return NULL;
681     }
682 
683     node_name = g_strdup_printf("%s-%s", id, driver);
684     qdict_put_str(qdict, "node-name", node_name);
685 
686     trace_xen_block_blockdev_add(node_name);
687 
688     v = qobject_input_visitor_new(QOBJECT(qdict));
689     visit_type_BlockdevOptions(v, NULL, &options, &local_err);
690     visit_free(v);
691 
692     if (local_err) {
693         error_propagate(errp, local_err);
694         goto fail;
695     }
696 
697     qmp_blockdev_add(options, &local_err);
698 
699     if (local_err) {
700         error_propagate(errp, local_err);
701         goto fail;
702     }
703 
704     qapi_free_BlockdevOptions(options);
705 
706     return node_name;
707 
708 fail:
709     if (options) {
710         qapi_free_BlockdevOptions(options);
711     }
712     g_free(node_name);
713 
714     return NULL;
715 }
716 
717 static void xen_block_drive_destroy(XenBlockDrive *drive, Error **errp)
718 {
719     char *node_name = drive->node_name;
720 
721     if (node_name) {
722         Error *local_err = NULL;
723 
724         xen_block_blockdev_del(node_name, &local_err);
725         if (local_err) {
726             error_propagate(errp, local_err);
727             return;
728         }
729         g_free(node_name);
730         drive->node_name = NULL;
731     }
732     g_free(drive->id);
733     g_free(drive);
734 }
735 
736 static XenBlockDrive *xen_block_drive_create(const char *id,
737                                              const char *device_type,
738                                              QDict *opts, Error **errp)
739 {
740     const char *params = qdict_get_try_str(opts, "params");
741     const char *mode = qdict_get_try_str(opts, "mode");
742     const char *direct_io_safe = qdict_get_try_str(opts, "direct-io-safe");
743     const char *discard_enable = qdict_get_try_str(opts, "discard-enable");
744     char *driver = NULL;
745     char *filename = NULL;
746     XenBlockDrive *drive = NULL;
747     Error *local_err = NULL;
748     QDict *file_layer;
749     QDict *driver_layer;
750 
751     if (params) {
752         char **v = g_strsplit(params, ":", 2);
753 
754         if (v[1] == NULL) {
755             filename = g_strdup(v[0]);
756             driver = g_strdup("raw");
757         } else {
758             if (strcmp(v[0], "aio") == 0) {
759                 driver = g_strdup("raw");
760             } else if (strcmp(v[0], "vhd") == 0) {
761                 driver = g_strdup("vpc");
762             } else {
763                 driver = g_strdup(v[0]);
764             }
765             filename = g_strdup(v[1]);
766         }
767 
768         g_strfreev(v);
769     } else {
770         error_setg(errp, "no params");
771         goto done;
772     }
773 
774     assert(filename);
775     assert(driver);
776 
777     drive = g_new0(XenBlockDrive, 1);
778     drive->id = g_strdup(id);
779 
780     file_layer = qdict_new();
781     driver_layer = qdict_new();
782 
783     qdict_put_str(file_layer, "driver", "file");
784     qdict_put_str(file_layer, "filename", filename);
785     g_free(filename);
786 
787     if (mode && *mode != 'w') {
788         qdict_put_bool(file_layer, "read-only", true);
789     }
790 
791     if (direct_io_safe) {
792         unsigned long value;
793 
794         if (!qemu_strtoul(direct_io_safe, NULL, 2, &value) && !!value) {
795             QDict *cache_qdict = qdict_new();
796 
797             qdict_put_bool(cache_qdict, "direct", true);
798             qdict_put(file_layer, "cache", cache_qdict);
799 
800             qdict_put_str(file_layer, "aio", "native");
801         }
802     }
803 
804     if (discard_enable) {
805         unsigned long value;
806 
807         if (!qemu_strtoul(discard_enable, NULL, 2, &value) && !!value) {
808             qdict_put_str(file_layer, "discard", "unmap");
809             qdict_put_str(driver_layer, "discard", "unmap");
810         }
811     }
812 
813     /*
814      * It is necessary to turn file locking off as an emulated device
815      * may have already opened the same image file.
816      */
817     qdict_put_str(file_layer, "locking", "off");
818 
819     qdict_put_str(driver_layer, "driver", driver);
820     g_free(driver);
821 
822     qdict_put(driver_layer, "file", file_layer);
823 
824     g_assert(!drive->node_name);
825     drive->node_name = xen_block_blockdev_add(drive->id, driver_layer,
826                                               &local_err);
827 
828     qobject_unref(driver_layer);
829 
830 done:
831     if (local_err) {
832         error_propagate(errp, local_err);
833         xen_block_drive_destroy(drive, NULL);
834         return NULL;
835     }
836 
837     return drive;
838 }
839 
840 static const char *xen_block_drive_get_node_name(XenBlockDrive *drive)
841 {
842     return drive->node_name ? drive->node_name : "";
843 }
844 
845 static void xen_block_iothread_destroy(XenBlockIOThread *iothread,
846                                        Error **errp)
847 {
848     qmp_object_del(iothread->id, errp);
849 
850     g_free(iothread->id);
851     g_free(iothread);
852 }
853 
854 static XenBlockIOThread *xen_block_iothread_create(const char *id,
855                                                    Error **errp)
856 {
857     XenBlockIOThread *iothread = g_new(XenBlockIOThread, 1);
858     Error *local_err = NULL;
859 
860     iothread->id = g_strdup(id);
861 
862     qmp_object_add(TYPE_IOTHREAD, id, false, NULL, &local_err);
863     if (local_err) {
864         error_propagate(errp, local_err);
865 
866         g_free(iothread->id);
867         g_free(iothread);
868         return NULL;
869     }
870 
871     return iothread;
872 }
873 
874 static void xen_block_device_create(XenBackendInstance *backend,
875                                     QDict *opts, Error **errp)
876 {
877     XenBus *xenbus = xen_backend_get_bus(backend);
878     const char *name = xen_backend_get_name(backend);
879     unsigned long number;
880     const char *vdev, *device_type;
881     XenBlockDrive *drive = NULL;
882     XenBlockIOThread *iothread = NULL;
883     XenDevice *xendev = NULL;
884     Error *local_err = NULL;
885     const char *type;
886     XenBlockDevice *blockdev;
887 
888     if (qemu_strtoul(name, NULL, 10, &number)) {
889         error_setg(errp, "failed to parse name '%s'", name);
890         goto fail;
891     }
892 
893     trace_xen_block_device_create(number);
894 
895     vdev = qdict_get_try_str(opts, "dev");
896     if (!vdev) {
897         error_setg(errp, "no dev parameter");
898         goto fail;
899     }
900 
901     device_type = qdict_get_try_str(opts, "device-type");
902     if (!device_type) {
903         error_setg(errp, "no device-type parameter");
904         goto fail;
905     }
906 
907     if (!strcmp(device_type, "disk")) {
908         type = TYPE_XEN_DISK_DEVICE;
909     } else if (!strcmp(device_type, "cdrom")) {
910         type = TYPE_XEN_CDROM_DEVICE;
911     } else {
912         error_setg(errp, "invalid device-type parameter '%s'", device_type);
913         goto fail;
914     }
915 
916     drive = xen_block_drive_create(vdev, device_type, opts, &local_err);
917     if (!drive) {
918         error_propagate_prepend(errp, local_err, "failed to create drive: ");
919         goto fail;
920     }
921 
922     iothread = xen_block_iothread_create(vdev, &local_err);
923     if (local_err) {
924         error_propagate_prepend(errp, local_err,
925                                 "failed to create iothread: ");
926         goto fail;
927     }
928 
929     xendev = XEN_DEVICE(qdev_create(BUS(xenbus), type));
930     blockdev = XEN_BLOCK_DEVICE(xendev);
931 
932     object_property_set_str(OBJECT(xendev), vdev, "vdev", &local_err);
933     if (local_err) {
934         error_propagate_prepend(errp, local_err, "failed to set 'vdev': ");
935         goto fail;
936     }
937 
938     object_property_set_str(OBJECT(xendev),
939                             xen_block_drive_get_node_name(drive), "drive",
940                             &local_err);
941     if (local_err) {
942         error_propagate_prepend(errp, local_err, "failed to set 'drive': ");
943         goto fail;
944     }
945 
946     object_property_set_str(OBJECT(xendev), iothread->id, "iothread",
947                             &local_err);
948     if (local_err) {
949         error_propagate_prepend(errp, local_err,
950                                 "failed to set 'iothread': ");
951         goto fail;
952     }
953 
954     blockdev->iothread = iothread;
955     blockdev->drive = drive;
956 
957     object_property_set_bool(OBJECT(xendev), true, "realized", &local_err);
958     if (local_err) {
959         error_propagate_prepend(errp, local_err,
960                                 "realization of device %s failed: ",
961                                 type);
962         goto fail;
963     }
964 
965     xen_backend_set_device(backend, xendev);
966     return;
967 
968 fail:
969     if (xendev) {
970         object_unparent(OBJECT(xendev));
971     }
972 
973     if (iothread) {
974         xen_block_iothread_destroy(iothread, NULL);
975     }
976 
977     if (drive) {
978         xen_block_drive_destroy(drive, NULL);
979     }
980 }
981 
982 static void xen_block_device_destroy(XenBackendInstance *backend,
983                                      Error **errp)
984 {
985     XenDevice *xendev = xen_backend_get_device(backend);
986     XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev);
987     XenBlockVdev *vdev = &blockdev->props.vdev;
988     XenBlockDrive *drive = blockdev->drive;
989     XenBlockIOThread *iothread = blockdev->iothread;
990 
991     trace_xen_block_device_destroy(vdev->number);
992 
993     object_unparent(OBJECT(xendev));
994 
995     if (iothread) {
996         Error *local_err = NULL;
997 
998         xen_block_iothread_destroy(iothread, &local_err);
999         if (local_err) {
1000             error_propagate_prepend(errp, local_err,
1001                                 "failed to destroy iothread: ");
1002             return;
1003         }
1004     }
1005 
1006     if (drive) {
1007         Error *local_err = NULL;
1008 
1009         xen_block_drive_destroy(drive, &local_err);
1010         if (local_err) {
1011             error_propagate_prepend(errp, local_err,
1012                                 "failed to destroy drive: ");
1013         }
1014     }
1015 }
1016 
1017 static const XenBackendInfo xen_block_backend_info = {
1018     .type = "qdisk",
1019     .create = xen_block_device_create,
1020     .destroy = xen_block_device_destroy,
1021 };
1022 
1023 static void xen_block_register_backend(void)
1024 {
1025     xen_backend_register(&xen_block_backend_info);
1026 }
1027 
1028 xen_backend_init(xen_block_register_backend);
1029