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 int vbd_name_to_disk(const char *name, const char **endp, 355 unsigned long *disk) 356 { 357 unsigned int n = 0; 358 359 while (*name != '\0') { 360 if (!g_ascii_isalpha(*name) || !g_ascii_islower(*name)) { 361 break; 362 } 363 364 n *= 26; 365 n += *name++ - 'a' + 1; 366 } 367 *endp = name; 368 369 if (!n) { 370 return -1; 371 } 372 373 *disk = n - 1; 374 375 return 0; 376 } 377 378 static void xen_block_set_vdev(Object *obj, Visitor *v, const char *name, 379 void *opaque, Error **errp) 380 { 381 DeviceState *dev = DEVICE(obj); 382 Property *prop = opaque; 383 XenBlockVdev *vdev = qdev_get_prop_ptr(dev, prop); 384 Error *local_err = NULL; 385 char *str, *p; 386 const char *end; 387 388 if (dev->realized) { 389 qdev_prop_set_after_realize(dev, name, errp); 390 return; 391 } 392 393 visit_type_str(v, name, &str, &local_err); 394 if (local_err) { 395 error_propagate(errp, local_err); 396 return; 397 } 398 399 p = strchr(str, 'd'); 400 if (!p) { 401 goto invalid; 402 } 403 404 *p++ = '\0'; 405 if (*str == '\0') { 406 vdev->type = XEN_BLOCK_VDEV_TYPE_DP; 407 } else if (strcmp(str, "xv") == 0) { 408 vdev->type = XEN_BLOCK_VDEV_TYPE_XVD; 409 } else if (strcmp(str, "h") == 0) { 410 vdev->type = XEN_BLOCK_VDEV_TYPE_HD; 411 } else if (strcmp(str, "s") == 0) { 412 vdev->type = XEN_BLOCK_VDEV_TYPE_SD; 413 } else { 414 goto invalid; 415 } 416 417 if (vdev->type == XEN_BLOCK_VDEV_TYPE_DP) { 418 if (qemu_strtoul(p, &end, 10, &vdev->disk)) { 419 goto invalid; 420 } 421 422 if (*end == 'p') { 423 if (*(++end) == '\0') { 424 goto invalid; 425 } 426 } 427 } else { 428 if (vbd_name_to_disk(p, &end, &vdev->disk)) { 429 goto invalid; 430 } 431 } 432 433 if (*end != '\0') { 434 p = (char *)end; 435 436 if (qemu_strtoul(p, &end, 10, &vdev->partition)) { 437 goto invalid; 438 } 439 440 if (*end != '\0') { 441 goto invalid; 442 } 443 } else { 444 vdev->partition = 0; 445 } 446 447 switch (vdev->type) { 448 case XEN_BLOCK_VDEV_TYPE_DP: 449 case XEN_BLOCK_VDEV_TYPE_XVD: 450 if (vdev->disk < (1 << 4) && vdev->partition < (1 << 4)) { 451 vdev->number = (202 << 8) | (vdev->disk << 4) | 452 vdev->partition; 453 } else if (vdev->disk < (1 << 20) && vdev->partition < (1 << 8)) { 454 vdev->number = (1 << 28) | (vdev->disk << 8) | 455 vdev->partition; 456 } else { 457 goto invalid; 458 } 459 break; 460 461 case XEN_BLOCK_VDEV_TYPE_HD: 462 if ((vdev->disk == 0 || vdev->disk == 1) && 463 vdev->partition < (1 << 6)) { 464 vdev->number = (3 << 8) | (vdev->disk << 6) | vdev->partition; 465 } else if ((vdev->disk == 2 || vdev->disk == 3) && 466 vdev->partition < (1 << 6)) { 467 vdev->number = (22 << 8) | ((vdev->disk - 2) << 6) | 468 vdev->partition; 469 } else { 470 goto invalid; 471 } 472 break; 473 474 case XEN_BLOCK_VDEV_TYPE_SD: 475 if (vdev->disk < (1 << 4) && vdev->partition < (1 << 4)) { 476 vdev->number = (8 << 8) | (vdev->disk << 4) | vdev->partition; 477 } else { 478 goto invalid; 479 } 480 break; 481 482 default: 483 goto invalid; 484 } 485 486 g_free(str); 487 return; 488 489 invalid: 490 error_setg(errp, "invalid virtual disk specifier"); 491 492 vdev->type = XEN_BLOCK_VDEV_TYPE_INVALID; 493 g_free(str); 494 } 495 496 /* 497 * This property deals with 'vdev' names adhering to the Xen VBD naming 498 * scheme described in: 499 * 500 * https://xenbits.xen.org/docs/unstable/man/xen-vbd-interface.7.html 501 */ 502 const PropertyInfo xen_block_prop_vdev = { 503 .name = "str", 504 .description = "Virtual Disk specifier: d*p*/xvd*/hd*/sd*", 505 .get = xen_block_get_vdev, 506 .set = xen_block_set_vdev, 507 }; 508 509 static Property xen_block_props[] = { 510 DEFINE_PROP("vdev", XenBlockDevice, props.vdev, 511 xen_block_prop_vdev, XenBlockVdev), 512 DEFINE_BLOCK_PROPERTIES(XenBlockDevice, props.conf), 513 DEFINE_PROP_UINT32("max-ring-page-order", XenBlockDevice, 514 props.max_ring_page_order, 4), 515 DEFINE_PROP_LINK("iothread", XenBlockDevice, props.iothread, 516 TYPE_IOTHREAD, IOThread *), 517 DEFINE_PROP_END_OF_LIST() 518 }; 519 520 static void xen_block_class_init(ObjectClass *class, void *data) 521 { 522 DeviceClass *dev_class = DEVICE_CLASS(class); 523 XenDeviceClass *xendev_class = XEN_DEVICE_CLASS(class); 524 525 xendev_class->backend = "qdisk"; 526 xendev_class->device = "vbd"; 527 xendev_class->get_name = xen_block_get_name; 528 xendev_class->realize = xen_block_realize; 529 xendev_class->frontend_changed = xen_block_frontend_changed; 530 xendev_class->unrealize = xen_block_unrealize; 531 532 dev_class->props = xen_block_props; 533 } 534 535 static const TypeInfo xen_block_type_info = { 536 .name = TYPE_XEN_BLOCK_DEVICE, 537 .parent = TYPE_XEN_DEVICE, 538 .instance_size = sizeof(XenBlockDevice), 539 .abstract = true, 540 .class_size = sizeof(XenBlockDeviceClass), 541 .class_init = xen_block_class_init, 542 }; 543 544 static void xen_disk_unrealize(XenBlockDevice *blockdev, Error **errp) 545 { 546 trace_xen_disk_unrealize(); 547 } 548 549 static void xen_disk_realize(XenBlockDevice *blockdev, Error **errp) 550 { 551 BlockConf *conf = &blockdev->props.conf; 552 553 trace_xen_disk_realize(); 554 555 blockdev->device_type = "disk"; 556 557 if (!conf->blk) { 558 error_setg(errp, "drive property not set"); 559 return; 560 } 561 562 blockdev->info = blk_is_read_only(conf->blk) ? VDISK_READONLY : 0; 563 } 564 565 static void xen_disk_class_init(ObjectClass *class, void *data) 566 { 567 DeviceClass *dev_class = DEVICE_CLASS(class); 568 XenBlockDeviceClass *blockdev_class = XEN_BLOCK_DEVICE_CLASS(class); 569 570 blockdev_class->realize = xen_disk_realize; 571 blockdev_class->unrealize = xen_disk_unrealize; 572 573 dev_class->desc = "Xen Disk Device"; 574 } 575 576 static const TypeInfo xen_disk_type_info = { 577 .name = TYPE_XEN_DISK_DEVICE, 578 .parent = TYPE_XEN_BLOCK_DEVICE, 579 .instance_size = sizeof(XenDiskDevice), 580 .class_init = xen_disk_class_init, 581 }; 582 583 static void xen_cdrom_unrealize(XenBlockDevice *blockdev, Error **errp) 584 { 585 trace_xen_cdrom_unrealize(); 586 } 587 588 static void xen_cdrom_realize(XenBlockDevice *blockdev, Error **errp) 589 { 590 BlockConf *conf = &blockdev->props.conf; 591 592 trace_xen_cdrom_realize(); 593 594 blockdev->device_type = "cdrom"; 595 596 if (!conf->blk) { 597 int rc; 598 599 /* Set up an empty drive */ 600 conf->blk = blk_new(0, BLK_PERM_ALL); 601 602 rc = blk_attach_dev(conf->blk, DEVICE(blockdev)); 603 if (!rc) { 604 error_setg_errno(errp, -rc, "failed to create drive"); 605 return; 606 } 607 } 608 609 blockdev->info = VDISK_READONLY | VDISK_CDROM; 610 } 611 612 static void xen_cdrom_class_init(ObjectClass *class, void *data) 613 { 614 DeviceClass *dev_class = DEVICE_CLASS(class); 615 XenBlockDeviceClass *blockdev_class = XEN_BLOCK_DEVICE_CLASS(class); 616 617 blockdev_class->realize = xen_cdrom_realize; 618 blockdev_class->unrealize = xen_cdrom_unrealize; 619 620 dev_class->desc = "Xen CD-ROM Device"; 621 } 622 623 static const TypeInfo xen_cdrom_type_info = { 624 .name = TYPE_XEN_CDROM_DEVICE, 625 .parent = TYPE_XEN_BLOCK_DEVICE, 626 .instance_size = sizeof(XenCDRomDevice), 627 .class_init = xen_cdrom_class_init, 628 }; 629 630 static void xen_block_register_types(void) 631 { 632 type_register_static(&xen_block_type_info); 633 type_register_static(&xen_disk_type_info); 634 type_register_static(&xen_cdrom_type_info); 635 } 636 637 type_init(xen_block_register_types) 638 639 static void xen_block_blockdev_del(const char *node_name, Error **errp) 640 { 641 trace_xen_block_blockdev_del(node_name); 642 643 qmp_blockdev_del(node_name, errp); 644 } 645 646 static char *xen_block_blockdev_add(const char *id, QDict *qdict, 647 Error **errp) 648 { 649 const char *driver = qdict_get_try_str(qdict, "driver"); 650 BlockdevOptions *options = NULL; 651 Error *local_err = NULL; 652 char *node_name; 653 Visitor *v; 654 655 if (!driver) { 656 error_setg(errp, "no 'driver' parameter"); 657 return NULL; 658 } 659 660 node_name = g_strdup_printf("%s-%s", id, driver); 661 qdict_put_str(qdict, "node-name", node_name); 662 663 trace_xen_block_blockdev_add(node_name); 664 665 v = qobject_input_visitor_new(QOBJECT(qdict)); 666 visit_type_BlockdevOptions(v, NULL, &options, &local_err); 667 visit_free(v); 668 669 if (local_err) { 670 error_propagate(errp, local_err); 671 goto fail; 672 } 673 674 qmp_blockdev_add(options, &local_err); 675 676 if (local_err) { 677 error_propagate(errp, local_err); 678 goto fail; 679 } 680 681 qapi_free_BlockdevOptions(options); 682 683 return node_name; 684 685 fail: 686 if (options) { 687 qapi_free_BlockdevOptions(options); 688 } 689 g_free(node_name); 690 691 return NULL; 692 } 693 694 static void xen_block_drive_destroy(XenBlockDrive *drive, Error **errp) 695 { 696 char *node_name = drive->node_name; 697 698 if (node_name) { 699 Error *local_err = NULL; 700 701 xen_block_blockdev_del(node_name, &local_err); 702 if (local_err) { 703 error_propagate(errp, local_err); 704 return; 705 } 706 g_free(node_name); 707 drive->node_name = NULL; 708 } 709 g_free(drive->id); 710 g_free(drive); 711 } 712 713 static XenBlockDrive *xen_block_drive_create(const char *id, 714 const char *device_type, 715 QDict *opts, Error **errp) 716 { 717 const char *params = qdict_get_try_str(opts, "params"); 718 const char *mode = qdict_get_try_str(opts, "mode"); 719 const char *direct_io_safe = qdict_get_try_str(opts, "direct-io-safe"); 720 const char *discard_enable = qdict_get_try_str(opts, "discard-enable"); 721 char *driver = NULL; 722 char *filename = NULL; 723 XenBlockDrive *drive = NULL; 724 Error *local_err = NULL; 725 QDict *file_layer; 726 QDict *driver_layer; 727 728 if (params) { 729 char **v = g_strsplit(params, ":", 2); 730 731 if (v[1] == NULL) { 732 filename = g_strdup(v[0]); 733 driver = g_strdup("raw"); 734 } else { 735 if (strcmp(v[0], "aio") == 0) { 736 driver = g_strdup("raw"); 737 } else if (strcmp(v[0], "vhd") == 0) { 738 driver = g_strdup("vpc"); 739 } else { 740 driver = g_strdup(v[0]); 741 } 742 filename = g_strdup(v[1]); 743 } 744 745 g_strfreev(v); 746 } else { 747 error_setg(errp, "no params"); 748 goto done; 749 } 750 751 assert(filename); 752 assert(driver); 753 754 drive = g_new0(XenBlockDrive, 1); 755 drive->id = g_strdup(id); 756 757 file_layer = qdict_new(); 758 759 qdict_put_str(file_layer, "driver", "file"); 760 qdict_put_str(file_layer, "filename", filename); 761 g_free(filename); 762 763 if (mode && *mode != 'w') { 764 qdict_put_bool(file_layer, "read-only", true); 765 } 766 767 if (direct_io_safe) { 768 unsigned long value; 769 770 if (!qemu_strtoul(direct_io_safe, NULL, 2, &value) && !!value) { 771 QDict *cache_qdict = qdict_new(); 772 773 qdict_put_bool(cache_qdict, "direct", true); 774 qdict_put_obj(file_layer, "cache", QOBJECT(cache_qdict)); 775 776 qdict_put_str(file_layer, "aio", "native"); 777 } 778 } 779 780 if (discard_enable) { 781 unsigned long value; 782 783 if (!qemu_strtoul(discard_enable, NULL, 2, &value) && !!value) { 784 qdict_put_str(file_layer, "discard", "unmap"); 785 } 786 } 787 788 /* 789 * It is necessary to turn file locking off as an emulated device 790 * may have already opened the same image file. 791 */ 792 qdict_put_str(file_layer, "locking", "off"); 793 794 driver_layer = qdict_new(); 795 796 qdict_put_str(driver_layer, "driver", driver); 797 g_free(driver); 798 799 qdict_put_obj(driver_layer, "file", QOBJECT(file_layer)); 800 801 g_assert(!drive->node_name); 802 drive->node_name = xen_block_blockdev_add(drive->id, driver_layer, 803 &local_err); 804 805 qobject_unref(driver_layer); 806 807 done: 808 if (local_err) { 809 error_propagate(errp, local_err); 810 xen_block_drive_destroy(drive, NULL); 811 return NULL; 812 } 813 814 return drive; 815 } 816 817 static const char *xen_block_drive_get_node_name(XenBlockDrive *drive) 818 { 819 return drive->node_name ? drive->node_name : ""; 820 } 821 822 static void xen_block_iothread_destroy(XenBlockIOThread *iothread, 823 Error **errp) 824 { 825 qmp_object_del(iothread->id, errp); 826 827 g_free(iothread->id); 828 g_free(iothread); 829 } 830 831 static XenBlockIOThread *xen_block_iothread_create(const char *id, 832 Error **errp) 833 { 834 XenBlockIOThread *iothread = g_new(XenBlockIOThread, 1); 835 Error *local_err = NULL; 836 837 iothread->id = g_strdup(id); 838 839 qmp_object_add(TYPE_IOTHREAD, id, false, NULL, &local_err); 840 if (local_err) { 841 error_propagate(errp, local_err); 842 843 g_free(iothread->id); 844 g_free(iothread); 845 return NULL; 846 } 847 848 return iothread; 849 } 850 851 static void xen_block_device_create(XenBackendInstance *backend, 852 QDict *opts, Error **errp) 853 { 854 XenBus *xenbus = xen_backend_get_bus(backend); 855 const char *name = xen_backend_get_name(backend); 856 unsigned long number; 857 const char *vdev, *device_type; 858 XenBlockDrive *drive = NULL; 859 XenBlockIOThread *iothread = NULL; 860 XenDevice *xendev = NULL; 861 Error *local_err = NULL; 862 const char *type; 863 XenBlockDevice *blockdev; 864 865 if (qemu_strtoul(name, NULL, 10, &number)) { 866 error_setg(errp, "failed to parse name '%s'", name); 867 goto fail; 868 } 869 870 trace_xen_block_device_create(number); 871 872 vdev = qdict_get_try_str(opts, "dev"); 873 if (!vdev) { 874 error_setg(errp, "no dev parameter"); 875 goto fail; 876 } 877 878 device_type = qdict_get_try_str(opts, "device-type"); 879 if (!device_type) { 880 error_setg(errp, "no device-type parameter"); 881 goto fail; 882 } 883 884 if (!strcmp(device_type, "disk")) { 885 type = TYPE_XEN_DISK_DEVICE; 886 } else if (!strcmp(device_type, "cdrom")) { 887 type = TYPE_XEN_CDROM_DEVICE; 888 } else { 889 error_setg(errp, "invalid device-type parameter '%s'", device_type); 890 goto fail; 891 } 892 893 drive = xen_block_drive_create(vdev, device_type, opts, &local_err); 894 if (!drive) { 895 error_propagate_prepend(errp, local_err, "failed to create drive: "); 896 goto fail; 897 } 898 899 iothread = xen_block_iothread_create(vdev, &local_err); 900 if (local_err) { 901 error_propagate_prepend(errp, local_err, 902 "failed to create iothread: "); 903 goto fail; 904 } 905 906 xendev = XEN_DEVICE(qdev_create(BUS(xenbus), type)); 907 blockdev = XEN_BLOCK_DEVICE(xendev); 908 909 object_property_set_str(OBJECT(xendev), vdev, "vdev", &local_err); 910 if (local_err) { 911 error_propagate_prepend(errp, local_err, "failed to set 'vdev': "); 912 goto fail; 913 } 914 915 object_property_set_str(OBJECT(xendev), 916 xen_block_drive_get_node_name(drive), "drive", 917 &local_err); 918 if (local_err) { 919 error_propagate_prepend(errp, local_err, "failed to set 'drive': "); 920 goto fail; 921 } 922 923 object_property_set_str(OBJECT(xendev), iothread->id, "iothread", 924 &local_err); 925 if (local_err) { 926 error_propagate_prepend(errp, local_err, 927 "failed to set 'iothread': "); 928 goto fail; 929 } 930 931 blockdev->iothread = iothread; 932 blockdev->drive = drive; 933 934 object_property_set_bool(OBJECT(xendev), true, "realized", &local_err); 935 if (local_err) { 936 error_propagate_prepend(errp, local_err, 937 "realization of device %s failed: ", 938 type); 939 goto fail; 940 } 941 942 xen_backend_set_device(backend, xendev); 943 return; 944 945 fail: 946 if (xendev) { 947 object_unparent(OBJECT(xendev)); 948 } 949 950 if (iothread) { 951 xen_block_iothread_destroy(iothread, NULL); 952 } 953 954 if (drive) { 955 xen_block_drive_destroy(drive, NULL); 956 } 957 } 958 959 static void xen_block_device_destroy(XenBackendInstance *backend, 960 Error **errp) 961 { 962 XenDevice *xendev = xen_backend_get_device(backend); 963 XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev); 964 XenBlockVdev *vdev = &blockdev->props.vdev; 965 XenBlockDrive *drive = blockdev->drive; 966 XenBlockIOThread *iothread = blockdev->iothread; 967 968 trace_xen_block_device_destroy(vdev->number); 969 970 object_unparent(OBJECT(xendev)); 971 972 if (iothread) { 973 Error *local_err = NULL; 974 975 xen_block_iothread_destroy(iothread, &local_err); 976 if (local_err) { 977 error_propagate_prepend(errp, local_err, 978 "failed to destroy iothread: "); 979 return; 980 } 981 } 982 983 if (drive) { 984 Error *local_err = NULL; 985 986 xen_block_drive_destroy(drive, &local_err); 987 if (local_err) { 988 error_propagate_prepend(errp, local_err, 989 "failed to destroy drive: "); 990 } 991 } 992 } 993 994 static const XenBackendInfo xen_block_backend_info = { 995 .type = "qdisk", 996 .create = xen_block_device_create, 997 .destroy = xen_block_device_destroy, 998 }; 999 1000 static void xen_block_register_backend(void) 1001 { 1002 xen_backend_register(&xen_block_backend_info); 1003 } 1004 1005 xen_backend_init(xen_block_register_backend); 1006