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