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