2 * Copyright (c) 2018 Citrix Systems Inc.
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.
8 #include "qemu/osdep.h"
9 #include "qemu/cutils.h"
10 #include "qemu/main-loop.h"
11 #include "qemu/module.h"
12 #include "qemu/option.h"
13 #include "qapi/error.h"
14 #include "qapi/qapi-commands-block-core.h"
15 #include "qapi/qapi-commands-qom.h"
16 #include "qapi/qapi-visit-block-core.h"
17 #include "qapi/qobject-input-visitor.h"
18 #include "qapi/visitor.h"
19 #include "qapi/qmp/qdict.h"
20 #include "qapi/qmp/qstring.h"
21 #include "qom/object_interfaces.h"
22 #include "hw/block/xen_blkif.h"
23 #include "hw/qdev-properties.h"
24 #include "hw/xen/xen-block.h"
25 #include "hw/xen/xen-backend.h"
26 #include "sysemu/blockdev.h"
27 #include "sysemu/block-backend.h"
28 #include "sysemu/iothread.h"
29 #include "dataplane/xen-block.h"
30 #include "hw/xen/interface/io/xs_wire.h"
33 #define XVDA_MAJOR 202
34 #define XVDQ_MAJOR (1 << 20)
35 #define XVDBGQCV_MAJOR ((1 << 21) - 1)
41 static int vdev_to_diskno(unsigned int vdev_nr
)
43 switch (vdev_nr
>> 8) {
46 return (vdev_nr
>> 4) & 0x15;
49 return (vdev_nr
>> 6) & 1;
52 return ((vdev_nr
>> 6) & 1) + 2;
54 case XVDQ_MAJOR
... XVDBGQCV_MAJOR
:
55 return (vdev_nr
>> 8) & 0xfffff;
62 #define MAX_AUTO_VDEV 4096
65 * Find a free device name in the xvda → xvdfan range and set it in
66 * blockdev->props.vdev. Our definition of "free" is that there must
67 * be no other disk or partition with the same disk number.
69 * You are technically permitted to have all of hda, hda1, sda, sda1,
70 * xvda and xvda1 as *separate* PV block devices with separate backing
71 * stores. That doesn't make it a good idea. This code will skip xvda
72 * if *any* of those "conflicting" devices already exists.
74 * The limit of xvdfan (disk 4095) is fairly arbitrary just to avoid a
75 * stupidly sized bitmap, but Linux as of v6.6 doesn't support anything
76 * higher than that anyway.
78 static bool xen_block_find_free_vdev(XenBlockDevice
*blockdev
, Error
**errp
)
80 XenBus
*xenbus
= XEN_BUS(qdev_get_parent_bus(DEVICE(blockdev
)));
81 unsigned long used_devs
[BITS_TO_LONGS(MAX_AUTO_VDEV
)];
82 XenBlockVdev
*vdev
= &blockdev
->props
.vdev
;
83 char fe_path
[XENSTORE_ABS_PATH_MAX
+ 1];
84 char **existing_frontends
;
85 unsigned int nr_existing
= 0;
89 snprintf(fe_path
, sizeof(fe_path
), "/local/domain/%u/device/vbd",
90 blockdev
->xendev
.frontend_id
);
92 existing_frontends
= qemu_xen_xs_directory(xenbus
->xsh
, XBT_NULL
, fe_path
,
94 if (!existing_frontends
&& errno
!= ENOENT
) {
95 error_setg_errno(errp
, errno
, "cannot read %s", fe_path
);
99 memset(used_devs
, 0, sizeof(used_devs
));
100 for (i
= 0; i
< nr_existing
; i
++) {
101 if (qemu_strtoui(existing_frontends
[i
], NULL
, 10, &vdev_nr
)) {
102 free(existing_frontends
[i
]);
106 free(existing_frontends
[i
]);
108 disk
= vdev_to_diskno(vdev_nr
);
109 if (disk
< 0 || disk
>= MAX_AUTO_VDEV
) {
113 set_bit(disk
, used_devs
);
115 free(existing_frontends
);
117 disk
= find_first_zero_bit(used_devs
, MAX_AUTO_VDEV
);
118 if (disk
== MAX_AUTO_VDEV
) {
119 error_setg(errp
, "cannot find device vdev for block device");
123 vdev
->type
= XEN_BLOCK_VDEV_TYPE_XVD
;
126 if (disk
< (1 << 4)) {
127 vdev
->number
= (XVDA_MAJOR
<< 8) | (disk
<< 4);
129 vdev
->number
= (XVDQ_MAJOR
<< 8) | (disk
<< 8);
134 static char *xen_block_get_name(XenDevice
*xendev
, Error
**errp
)
136 XenBlockDevice
*blockdev
= XEN_BLOCK_DEVICE(xendev
);
137 XenBlockVdev
*vdev
= &blockdev
->props
.vdev
;
139 if (vdev
->type
== XEN_BLOCK_VDEV_TYPE_INVALID
&&
140 !xen_block_find_free_vdev(blockdev
, errp
)) {
143 return g_strdup_printf("%lu", vdev
->number
);
146 static void xen_block_disconnect(XenDevice
*xendev
, Error
**errp
)
148 XenBlockDevice
*blockdev
= XEN_BLOCK_DEVICE(xendev
);
149 const char *type
= object_get_typename(OBJECT(blockdev
));
150 XenBlockVdev
*vdev
= &blockdev
->props
.vdev
;
152 trace_xen_block_disconnect(type
, vdev
->disk
, vdev
->partition
);
154 xen_block_dataplane_stop(blockdev
->dataplane
);
157 static void xen_block_connect(XenDevice
*xendev
, Error
**errp
)
159 XenBlockDevice
*blockdev
= XEN_BLOCK_DEVICE(xendev
);
160 const char *type
= object_get_typename(OBJECT(blockdev
));
161 XenBlockVdev
*vdev
= &blockdev
->props
.vdev
;
162 BlockConf
*conf
= &blockdev
->props
.conf
;
163 unsigned int feature_large_sector_size
;
164 unsigned int order
, nr_ring_ref
, *ring_ref
, event_channel
, protocol
;
167 trace_xen_block_connect(type
, vdev
->disk
, vdev
->partition
);
169 if (xen_device_frontend_scanf(xendev
, "feature-large-sector-size", "%u",
170 &feature_large_sector_size
) != 1) {
171 feature_large_sector_size
= 0;
174 if (feature_large_sector_size
!= 1 &&
175 conf
->logical_block_size
!= XEN_BLKIF_SECTOR_SIZE
) {
176 error_setg(errp
, "logical_block_size != %u not supported by frontend",
177 XEN_BLKIF_SECTOR_SIZE
);
181 if (xen_device_frontend_scanf(xendev
, "ring-page-order", "%u",
184 ring_ref
= g_new(unsigned int, nr_ring_ref
);
186 if (xen_device_frontend_scanf(xendev
, "ring-ref", "%u",
187 &ring_ref
[0]) != 1) {
188 error_setg(errp
, "failed to read ring-ref");
192 } else if (qemu_xen_gnttab_can_map_multi() &&
193 order
<= blockdev
->props
.max_ring_page_order
) {
196 nr_ring_ref
= 1 << order
;
197 ring_ref
= g_new(unsigned int, nr_ring_ref
);
199 for (i
= 0; i
< nr_ring_ref
; i
++) {
200 const char *key
= g_strdup_printf("ring-ref%u", i
);
202 if (xen_device_frontend_scanf(xendev
, key
, "%u",
203 &ring_ref
[i
]) != 1) {
204 error_setg(errp
, "failed to read %s", key
);
205 g_free((gpointer
)key
);
210 g_free((gpointer
)key
);
213 error_setg(errp
, "invalid ring-page-order (%d)", order
);
217 if (xen_device_frontend_scanf(xendev
, "event-channel", "%u",
218 &event_channel
) != 1) {
219 error_setg(errp
, "failed to read event-channel");
224 if (xen_device_frontend_scanf(xendev
, "protocol", "%ms", &str
) != 1) {
225 /* x86 defaults to the 32-bit protocol even for 64-bit guests. */
226 if (object_dynamic_cast(OBJECT(qdev_get_machine()), "x86-machine")) {
227 protocol
= BLKIF_PROTOCOL_X86_32
;
229 protocol
= BLKIF_PROTOCOL_NATIVE
;
232 if (strcmp(str
, XEN_IO_PROTO_ABI_X86_32
) == 0) {
233 protocol
= BLKIF_PROTOCOL_X86_32
;
234 } else if (strcmp(str
, XEN_IO_PROTO_ABI_X86_64
) == 0) {
235 protocol
= BLKIF_PROTOCOL_X86_64
;
237 protocol
= BLKIF_PROTOCOL_NATIVE
;
243 xen_block_dataplane_start(blockdev
->dataplane
, ring_ref
, nr_ring_ref
,
244 event_channel
, protocol
, errp
);
249 static void xen_block_unrealize(XenDevice
*xendev
)
251 XenBlockDevice
*blockdev
= XEN_BLOCK_DEVICE(xendev
);
252 XenBlockDeviceClass
*blockdev_class
=
253 XEN_BLOCK_DEVICE_GET_CLASS(xendev
);
254 const char *type
= object_get_typename(OBJECT(blockdev
));
255 XenBlockVdev
*vdev
= &blockdev
->props
.vdev
;
257 if (vdev
->type
== XEN_BLOCK_VDEV_TYPE_INVALID
) {
261 trace_xen_block_unrealize(type
, vdev
->disk
, vdev
->partition
);
263 /* Disconnect from the frontend in case this has not already happened */
264 xen_block_disconnect(xendev
, NULL
);
266 xen_block_dataplane_destroy(blockdev
->dataplane
);
267 blockdev
->dataplane
= NULL
;
269 if (blockdev_class
->unrealize
) {
270 blockdev_class
->unrealize(blockdev
);
274 static void xen_block_set_size(XenBlockDevice
*blockdev
)
276 const char *type
= object_get_typename(OBJECT(blockdev
));
277 XenBlockVdev
*vdev
= &blockdev
->props
.vdev
;
278 BlockConf
*conf
= &blockdev
->props
.conf
;
279 int64_t sectors
= blk_getlength(conf
->blk
) / conf
->logical_block_size
;
280 XenDevice
*xendev
= XEN_DEVICE(blockdev
);
282 trace_xen_block_size(type
, vdev
->disk
, vdev
->partition
, sectors
);
284 xen_device_backend_printf(xendev
, "sectors", "%"PRIi64
, sectors
);
287 static void xen_block_resize_cb(void *opaque
)
289 XenBlockDevice
*blockdev
= opaque
;
290 XenDevice
*xendev
= XEN_DEVICE(blockdev
);
291 enum xenbus_state state
= xen_device_backend_get_state(xendev
);
293 xen_block_set_size(blockdev
);
296 * Mimic the behaviour of Linux xen-blkback and re-write the state
297 * to trigger the frontend watch.
299 xen_device_backend_printf(xendev
, "state", "%u", state
);
302 /* Suspend request handling */
303 static void xen_block_drained_begin(void *opaque
)
305 XenBlockDevice
*blockdev
= opaque
;
307 xen_block_dataplane_detach(blockdev
->dataplane
);
310 /* Resume request handling */
311 static void xen_block_drained_end(void *opaque
)
313 XenBlockDevice
*blockdev
= opaque
;
315 xen_block_dataplane_attach(blockdev
->dataplane
);
318 static const BlockDevOps xen_block_dev_ops
= {
319 .resize_cb
= xen_block_resize_cb
,
320 .drained_begin
= xen_block_drained_begin
,
321 .drained_end
= xen_block_drained_end
,
324 static void xen_block_realize(XenDevice
*xendev
, Error
**errp
)
327 XenBlockDevice
*blockdev
= XEN_BLOCK_DEVICE(xendev
);
328 XenBlockDeviceClass
*blockdev_class
=
329 XEN_BLOCK_DEVICE_GET_CLASS(xendev
);
330 const char *type
= object_get_typename(OBJECT(blockdev
));
331 XenBlockVdev
*vdev
= &blockdev
->props
.vdev
;
332 BlockConf
*conf
= &blockdev
->props
.conf
;
333 BlockBackend
*blk
= conf
->blk
;
335 if (vdev
->type
== XEN_BLOCK_VDEV_TYPE_INVALID
) {
336 error_setg(errp
, "vdev property not set");
340 trace_xen_block_realize(type
, vdev
->disk
, vdev
->partition
);
342 if (blockdev_class
->realize
) {
343 blockdev_class
->realize(blockdev
, errp
);
350 * The blkif protocol does not deal with removable media, so it must
351 * always be present, even for CDRom devices.
354 if (!blk_is_inserted(blk
)) {
355 error_setg(errp
, "device needs media, but drive is empty");
359 if (!blkconf_apply_backend_options(conf
, blockdev
->info
& VDISK_READONLY
,
364 if (!(blockdev
->info
& VDISK_CDROM
) &&
365 !blkconf_geometry(conf
, NULL
, 65535, 255, 255, errp
)) {
369 if (!blkconf_blocksizes(conf
, errp
)) {
373 if (conf
->discard_granularity
== -1) {
374 conf
->discard_granularity
= conf
->physical_block_size
;
377 if (blk_get_flags(blk
) & BDRV_O_UNMAP
) {
378 xen_device_backend_printf(xendev
, "feature-discard", "%u", 1);
379 xen_device_backend_printf(xendev
, "discard-granularity", "%u",
380 conf
->discard_granularity
);
381 xen_device_backend_printf(xendev
, "discard-alignment", "%u", 0);
384 xen_device_backend_printf(xendev
, "feature-flush-cache", "%u", 1);
386 if (qemu_xen_gnttab_can_map_multi()) {
387 xen_device_backend_printf(xendev
, "max-ring-page-order", "%u",
388 blockdev
->props
.max_ring_page_order
);
391 xen_device_backend_printf(xendev
, "info", "%u", blockdev
->info
);
393 xen_device_frontend_printf(xendev
, "virtual-device", "%lu",
395 xen_device_frontend_printf(xendev
, "device-type", "%s",
396 blockdev
->device_type
);
398 xen_device_backend_printf(xendev
, "sector-size", "%u",
399 conf
->logical_block_size
);
401 xen_block_set_size(blockdev
);
403 blockdev
->dataplane
=
404 xen_block_dataplane_create(xendev
, blk
, conf
->logical_block_size
,
405 blockdev
->props
.iothread
);
407 blk_set_dev_ops(blk
, &xen_block_dev_ops
, blockdev
);
410 static void xen_block_frontend_changed(XenDevice
*xendev
,
411 enum xenbus_state frontend_state
,
415 enum xenbus_state backend_state
= xen_device_backend_get_state(xendev
);
417 switch (frontend_state
) {
418 case XenbusStateInitialised
:
419 case XenbusStateConnected
:
420 if (backend_state
== XenbusStateConnected
) {
424 xen_block_disconnect(xendev
, errp
);
429 xen_block_connect(xendev
, errp
);
434 xen_device_backend_set_state(xendev
, XenbusStateConnected
);
437 case XenbusStateClosing
:
438 xen_device_backend_set_state(xendev
, XenbusStateClosing
);
441 case XenbusStateClosed
:
442 case XenbusStateUnknown
:
443 xen_block_disconnect(xendev
, errp
);
448 xen_device_backend_set_state(xendev
, XenbusStateClosed
);
456 static char *disk_to_vbd_name(unsigned int disk
)
458 char *name
, *prefix
= (disk
>= 26) ?
459 disk_to_vbd_name((disk
/ 26) - 1) : g_strdup("");
461 name
= g_strdup_printf("%s%c", prefix
, 'a' + disk
% 26);
467 static void xen_block_get_vdev(Object
*obj
, Visitor
*v
, const char *name
,
468 void *opaque
, Error
**errp
)
470 Property
*prop
= opaque
;
471 XenBlockVdev
*vdev
= object_field_prop_ptr(obj
, prop
);
474 switch (vdev
->type
) {
475 case XEN_BLOCK_VDEV_TYPE_DP
:
476 str
= g_strdup_printf("d%lup%lu", vdev
->disk
, vdev
->partition
);
479 case XEN_BLOCK_VDEV_TYPE_XVD
:
480 case XEN_BLOCK_VDEV_TYPE_HD
:
481 case XEN_BLOCK_VDEV_TYPE_SD
: {
482 char *vbd_name
= disk_to_vbd_name(vdev
->disk
);
484 str
= g_strdup_printf("%s%s%lu",
485 (vdev
->type
== XEN_BLOCK_VDEV_TYPE_XVD
) ?
487 (vdev
->type
== XEN_BLOCK_VDEV_TYPE_HD
) ?
490 vbd_name
, vdev
->partition
);
495 error_setg(errp
, "invalid vdev type");
499 visit_type_str(v
, name
, &str
, errp
);
503 static int vbd_name_to_disk(const char *name
, const char **endp
,
508 while (*name
!= '\0') {
509 if (!g_ascii_isalpha(*name
) || !g_ascii_islower(*name
)) {
514 n
+= *name
++ - 'a' + 1;
527 static void xen_block_set_vdev(Object
*obj
, Visitor
*v
, const char *name
,
528 void *opaque
, Error
**errp
)
530 Property
*prop
= opaque
;
531 XenBlockVdev
*vdev
= object_field_prop_ptr(obj
, prop
);
535 if (!visit_type_str(v
, name
, &str
, errp
)) {
539 p
= strchr(str
, 'd');
546 vdev
->type
= XEN_BLOCK_VDEV_TYPE_DP
;
547 } else if (strcmp(str
, "xv") == 0) {
548 vdev
->type
= XEN_BLOCK_VDEV_TYPE_XVD
;
549 } else if (strcmp(str
, "h") == 0) {
550 vdev
->type
= XEN_BLOCK_VDEV_TYPE_HD
;
551 } else if (strcmp(str
, "s") == 0) {
552 vdev
->type
= XEN_BLOCK_VDEV_TYPE_SD
;
557 if (vdev
->type
== XEN_BLOCK_VDEV_TYPE_DP
) {
558 if (qemu_strtoul(p
, &end
, 10, &vdev
->disk
)) {
563 if (*(++end
) == '\0') {
568 if (vbd_name_to_disk(p
, &end
, &vdev
->disk
)) {
576 if (qemu_strtoul(p
, &end
, 10, &vdev
->partition
)) {
587 switch (vdev
->type
) {
588 case XEN_BLOCK_VDEV_TYPE_DP
:
589 case XEN_BLOCK_VDEV_TYPE_XVD
:
590 if (vdev
->disk
< (1 << 4) && vdev
->partition
< (1 << 4)) {
591 vdev
->number
= (XVDA_MAJOR
<< 8) | (vdev
->disk
<< 4) |
593 } else if (vdev
->disk
< (1 << 20) && vdev
->partition
< (1 << 8)) {
594 vdev
->number
= (XVDQ_MAJOR
<< 8) | (vdev
->disk
<< 8) |
601 case XEN_BLOCK_VDEV_TYPE_HD
:
602 if ((vdev
->disk
== 0 || vdev
->disk
== 1) &&
603 vdev
->partition
< (1 << 6)) {
604 vdev
->number
= (HDA_MAJOR
<< 8) | (vdev
->disk
<< 6) |
606 } else if ((vdev
->disk
== 2 || vdev
->disk
== 3) &&
607 vdev
->partition
< (1 << 6)) {
608 vdev
->number
= (HDC_MAJOR
<< 8) | ((vdev
->disk
- 2) << 6) |
615 case XEN_BLOCK_VDEV_TYPE_SD
:
616 if (vdev
->disk
< (1 << 4) && vdev
->partition
< (1 << 4)) {
617 vdev
->number
= (SDA_MAJOR
<< 8) | (vdev
->disk
<< 4) |
632 error_setg(errp
, "invalid virtual disk specifier");
634 vdev
->type
= XEN_BLOCK_VDEV_TYPE_INVALID
;
639 * This property deals with 'vdev' names adhering to the Xen VBD naming
640 * scheme described in:
642 * https://xenbits.xen.org/docs/unstable/man/xen-vbd-interface.7.html
644 const PropertyInfo xen_block_prop_vdev
= {
646 .description
= "Virtual Disk specifier: d*p*/xvd*/hd*/sd*",
647 .get
= xen_block_get_vdev
,
648 .set
= xen_block_set_vdev
,
651 static Property xen_block_props
[] = {
652 DEFINE_PROP("vdev", XenBlockDevice
, props
.vdev
,
653 xen_block_prop_vdev
, XenBlockVdev
),
654 DEFINE_BLOCK_PROPERTIES(XenBlockDevice
, props
.conf
),
655 DEFINE_PROP_UINT32("max-ring-page-order", XenBlockDevice
,
656 props
.max_ring_page_order
, 4),
657 DEFINE_PROP_LINK("iothread", XenBlockDevice
, props
.iothread
,
658 TYPE_IOTHREAD
, IOThread
*),
659 DEFINE_PROP_END_OF_LIST()
662 static void xen_block_class_init(ObjectClass
*class, void *data
)
664 DeviceClass
*dev_class
= DEVICE_CLASS(class);
665 XenDeviceClass
*xendev_class
= XEN_DEVICE_CLASS(class);
667 xendev_class
->backend
= "qdisk";
668 xendev_class
->device
= "vbd";
669 xendev_class
->get_name
= xen_block_get_name
;
670 xendev_class
->realize
= xen_block_realize
;
671 xendev_class
->frontend_changed
= xen_block_frontend_changed
;
672 xendev_class
->unrealize
= xen_block_unrealize
;
674 device_class_set_props(dev_class
, xen_block_props
);
677 static const TypeInfo xen_block_type_info
= {
678 .name
= TYPE_XEN_BLOCK_DEVICE
,
679 .parent
= TYPE_XEN_DEVICE
,
680 .instance_size
= sizeof(XenBlockDevice
),
682 .class_size
= sizeof(XenBlockDeviceClass
),
683 .class_init
= xen_block_class_init
,
686 static void xen_disk_unrealize(XenBlockDevice
*blockdev
)
688 trace_xen_disk_unrealize();
691 static void xen_disk_realize(XenBlockDevice
*blockdev
, Error
**errp
)
693 BlockConf
*conf
= &blockdev
->props
.conf
;
695 trace_xen_disk_realize();
697 blockdev
->device_type
= "disk";
700 error_setg(errp
, "drive property not set");
704 blockdev
->info
= blk_supports_write_perm(conf
->blk
) ? 0 : VDISK_READONLY
;
707 static void xen_disk_class_init(ObjectClass
*class, void *data
)
709 DeviceClass
*dev_class
= DEVICE_CLASS(class);
710 XenBlockDeviceClass
*blockdev_class
= XEN_BLOCK_DEVICE_CLASS(class);
712 blockdev_class
->realize
= xen_disk_realize
;
713 blockdev_class
->unrealize
= xen_disk_unrealize
;
715 dev_class
->desc
= "Xen Disk Device";
718 static const TypeInfo xen_disk_type_info
= {
719 .name
= TYPE_XEN_DISK_DEVICE
,
720 .parent
= TYPE_XEN_BLOCK_DEVICE
,
721 .instance_size
= sizeof(XenDiskDevice
),
722 .class_init
= xen_disk_class_init
,
725 static void xen_cdrom_unrealize(XenBlockDevice
*blockdev
)
727 trace_xen_cdrom_unrealize();
730 static void xen_cdrom_realize(XenBlockDevice
*blockdev
, Error
**errp
)
732 BlockConf
*conf
= &blockdev
->props
.conf
;
734 trace_xen_cdrom_realize();
736 blockdev
->device_type
= "cdrom";
741 /* Set up an empty drive */
742 conf
->blk
= blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL
);
744 rc
= blk_attach_dev(conf
->blk
, DEVICE(blockdev
));
746 error_setg_errno(errp
, -rc
, "failed to create drive");
751 blockdev
->info
= VDISK_READONLY
| VDISK_CDROM
;
754 static void xen_cdrom_class_init(ObjectClass
*class, void *data
)
756 DeviceClass
*dev_class
= DEVICE_CLASS(class);
757 XenBlockDeviceClass
*blockdev_class
= XEN_BLOCK_DEVICE_CLASS(class);
759 blockdev_class
->realize
= xen_cdrom_realize
;
760 blockdev_class
->unrealize
= xen_cdrom_unrealize
;
762 dev_class
->desc
= "Xen CD-ROM Device";
765 static const TypeInfo xen_cdrom_type_info
= {
766 .name
= TYPE_XEN_CDROM_DEVICE
,
767 .parent
= TYPE_XEN_BLOCK_DEVICE
,
768 .instance_size
= sizeof(XenCDRomDevice
),
769 .class_init
= xen_cdrom_class_init
,
772 static void xen_block_register_types(void)
774 type_register_static(&xen_block_type_info
);
775 type_register_static(&xen_disk_type_info
);
776 type_register_static(&xen_cdrom_type_info
);
779 type_init(xen_block_register_types
)
781 static void xen_block_blockdev_del(const char *node_name
, Error
**errp
)
783 trace_xen_block_blockdev_del(node_name
);
785 qmp_blockdev_del(node_name
, errp
);
788 static char *xen_block_blockdev_add(const char *id
, QDict
*qdict
,
792 const char *driver
= qdict_get_try_str(qdict
, "driver");
793 BlockdevOptions
*options
= NULL
;
798 error_setg(errp
, "no 'driver' parameter");
802 node_name
= g_strdup_printf("%s-%s", id
, driver
);
803 qdict_put_str(qdict
, "node-name", node_name
);
805 trace_xen_block_blockdev_add(node_name
);
807 v
= qobject_input_visitor_new(QOBJECT(qdict
));
808 visit_type_BlockdevOptions(v
, NULL
, &options
, errp
);
814 qmp_blockdev_add(options
, errp
);
820 qapi_free_BlockdevOptions(options
);
826 qapi_free_BlockdevOptions(options
);
833 static void xen_block_drive_destroy(XenBlockDrive
*drive
, Error
**errp
)
836 char *node_name
= drive
->node_name
;
839 xen_block_blockdev_del(node_name
, errp
);
844 drive
->node_name
= NULL
;
850 static XenBlockDrive
*xen_block_drive_create(const char *id
,
851 const char *device_type
,
852 QDict
*opts
, Error
**errp
)
855 const char *params
= qdict_get_try_str(opts
, "params");
856 const char *mode
= qdict_get_try_str(opts
, "mode");
857 const char *direct_io_safe
= qdict_get_try_str(opts
, "direct-io-safe");
858 const char *discard_enable
= qdict_get_try_str(opts
, "discard-enable");
860 char *filename
= NULL
;
861 XenBlockDrive
*drive
= NULL
;
868 char **v
= g_strsplit(params
, ":", 2);
871 filename
= g_strdup(v
[0]);
872 driver
= g_strdup("raw");
874 if (strcmp(v
[0], "aio") == 0) {
875 driver
= g_strdup("raw");
876 } else if (strcmp(v
[0], "vhd") == 0) {
877 driver
= g_strdup("vpc");
879 driver
= g_strdup(v
[0]);
881 filename
= g_strdup(v
[1]);
886 error_setg(errp
, "no params");
893 drive
= g_new0(XenBlockDrive
, 1);
894 drive
->id
= g_strdup(id
);
896 rc
= stat(filename
, &st
);
898 error_setg_errno(errp
, errno
, "Could not stat file '%s'", filename
);
902 file_layer
= qdict_new();
903 driver_layer
= qdict_new();
905 if (S_ISBLK(st
.st_mode
)) {
906 qdict_put_str(file_layer
, "driver", "host_device");
908 qdict_put_str(file_layer
, "driver", "file");
911 qdict_put_str(file_layer
, "filename", filename
);
913 if (mode
&& *mode
!= 'w') {
914 qdict_put_bool(file_layer
, "read-only", true);
917 if (direct_io_safe
) {
920 if (!qemu_strtoul(direct_io_safe
, NULL
, 2, &value
) && !!value
) {
921 QDict
*cache_qdict
= qdict_new();
923 qdict_put_bool(cache_qdict
, "direct", true);
924 qdict_put(file_layer
, "cache", cache_qdict
);
926 qdict_put_str(file_layer
, "aio", "native");
930 if (discard_enable
) {
933 if (!qemu_strtoul(discard_enable
, NULL
, 2, &value
) && !!value
) {
934 qdict_put_str(file_layer
, "discard", "unmap");
935 qdict_put_str(driver_layer
, "discard", "unmap");
940 * It is necessary to turn file locking off as an emulated device
941 * may have already opened the same image file.
943 qdict_put_str(file_layer
, "locking", "off");
945 qdict_put_str(driver_layer
, "driver", driver
);
947 qdict_put(driver_layer
, "file", file_layer
);
949 g_assert(!drive
->node_name
);
950 drive
->node_name
= xen_block_blockdev_add(drive
->id
, driver_layer
,
953 qobject_unref(driver_layer
);
959 xen_block_drive_destroy(drive
, NULL
);
966 static const char *xen_block_drive_get_node_name(XenBlockDrive
*drive
)
968 return drive
->node_name
? drive
->node_name
: "";
971 static void xen_block_iothread_destroy(XenBlockIOThread
*iothread
,
974 qmp_object_del(iothread
->id
, errp
);
976 g_free(iothread
->id
);
980 static XenBlockIOThread
*xen_block_iothread_create(const char *id
,
984 XenBlockIOThread
*iothread
= g_new(XenBlockIOThread
, 1);
987 iothread
->id
= g_strdup(id
);
989 opts
= g_new(ObjectOptions
, 1);
990 *opts
= (ObjectOptions
) {
991 .qom_type
= OBJECT_TYPE_IOTHREAD
,
994 qmp_object_add(opts
, errp
);
995 qapi_free_ObjectOptions(opts
);
998 g_free(iothread
->id
);
1006 static void xen_block_device_create(XenBackendInstance
*backend
,
1007 QDict
*opts
, Error
**errp
)
1010 XenBus
*xenbus
= xen_backend_get_bus(backend
);
1011 const char *name
= xen_backend_get_name(backend
);
1012 unsigned long number
;
1013 const char *vdev
, *device_type
;
1014 XenBlockDrive
*drive
= NULL
;
1015 XenBlockIOThread
*iothread
= NULL
;
1016 XenDevice
*xendev
= NULL
;
1018 XenBlockDevice
*blockdev
;
1020 if (qemu_strtoul(name
, NULL
, 10, &number
)) {
1021 error_setg(errp
, "failed to parse name '%s'", name
);
1025 trace_xen_block_device_create(number
);
1027 vdev
= qdict_get_try_str(opts
, "dev");
1029 error_setg(errp
, "no dev parameter");
1033 device_type
= qdict_get_try_str(opts
, "device-type");
1035 error_setg(errp
, "no device-type parameter");
1039 if (!strcmp(device_type
, "disk")) {
1040 type
= TYPE_XEN_DISK_DEVICE
;
1041 } else if (!strcmp(device_type
, "cdrom")) {
1042 type
= TYPE_XEN_CDROM_DEVICE
;
1044 error_setg(errp
, "invalid device-type parameter '%s'", device_type
);
1048 drive
= xen_block_drive_create(vdev
, device_type
, opts
, errp
);
1050 error_prepend(errp
, "failed to create drive: ");
1054 iothread
= xen_block_iothread_create(vdev
, errp
);
1056 error_prepend(errp
, "failed to create iothread: ");
1060 xendev
= XEN_DEVICE(qdev_new(type
));
1061 blockdev
= XEN_BLOCK_DEVICE(xendev
);
1063 if (!object_property_set_str(OBJECT(xendev
), "vdev", vdev
,
1065 error_prepend(errp
, "failed to set 'vdev': ");
1069 if (!object_property_set_str(OBJECT(xendev
), "drive",
1070 xen_block_drive_get_node_name(drive
),
1072 error_prepend(errp
, "failed to set 'drive': ");
1076 if (!object_property_set_str(OBJECT(xendev
), "iothread", iothread
->id
,
1078 error_prepend(errp
, "failed to set 'iothread': ");
1082 blockdev
->iothread
= iothread
;
1083 blockdev
->drive
= drive
;
1085 if (!qdev_realize_and_unref(DEVICE(xendev
), BUS(xenbus
), errp
)) {
1086 error_prepend(errp
, "realization of device %s failed: ", type
);
1090 xen_backend_set_device(backend
, xendev
);
1095 object_unparent(OBJECT(xendev
));
1099 xen_block_iothread_destroy(iothread
, NULL
);
1103 xen_block_drive_destroy(drive
, NULL
);
1107 static void xen_block_device_destroy(XenBackendInstance
*backend
,
1111 XenDevice
*xendev
= xen_backend_get_device(backend
);
1112 XenBlockDevice
*blockdev
= XEN_BLOCK_DEVICE(xendev
);
1113 XenBlockVdev
*vdev
= &blockdev
->props
.vdev
;
1114 XenBlockDrive
*drive
= blockdev
->drive
;
1115 XenBlockIOThread
*iothread
= blockdev
->iothread
;
1117 trace_xen_block_device_destroy(vdev
->number
);
1119 object_unparent(OBJECT(xendev
));
1122 * Drain all pending RCU callbacks as object_unparent() frees `xendev'
1123 * in a RCU callback.
1124 * And due to the property "drive" still existing in `xendev', we
1125 * can't destroy the XenBlockDrive associated with `xendev' with
1126 * xen_block_drive_destroy() below.
1131 xen_block_iothread_destroy(iothread
, errp
);
1133 error_prepend(errp
, "failed to destroy iothread: ");
1139 xen_block_drive_destroy(drive
, errp
);
1141 error_prepend(errp
, "failed to destroy drive: ");
1147 static const XenBackendInfo xen_block_backend_info
= {
1149 .create
= xen_block_device_create
,
1150 .destroy
= xen_block_device_destroy
,
1153 static void xen_block_register_backend(void)
1155 xen_backend_register(&xen_block_backend_info
);
1158 xen_backend_init(xen_block_register_backend
);