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