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