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/module.h" 11 #include "qemu/option.h" 12 #include "qapi/error.h" 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" 17 #include "qapi/visitor.h" 18 #include "qapi/qmp/qdict.h" 19 #include "qapi/qmp/qstring.h" 20 #include "hw/hw.h" 21 #include "hw/xen/xen_common.h" 22 #include "hw/block/xen_blkif.h" 23 #include "hw/xen/xen-block.h" 24 #include "hw/xen/xen-backend.h" 25 #include "sysemu/blockdev.h" 26 #include "sysemu/block-backend.h" 27 #include "sysemu/iothread.h" 28 #include "dataplane/xen-block.h" 29 #include "trace.h" 30 31 static 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 39 static 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); 46 47 xen_block_dataplane_stop(blockdev->dataplane); 48 } 49 50 static 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; 55 unsigned int order, nr_ring_ref, *ring_ref, event_channel, protocol; 56 char *str; 57 58 trace_xen_block_connect(type, vdev->disk, vdev->partition); 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); 121 } 122 123 static 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 137 /* Disconnect from the frontend in case this has not already happened */ 138 xen_block_disconnect(xendev, NULL); 139 140 xen_block_dataplane_destroy(blockdev->dataplane); 141 blockdev->dataplane = NULL; 142 143 if (blockdev_class->unrealize) { 144 blockdev_class->unrealize(blockdev, errp); 145 } 146 } 147 148 static 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; 153 int64_t sectors = blk_getlength(conf->blk) / XEN_BLKIF_SECTOR_SIZE; 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 161 static 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 176 static const BlockDevOps xen_block_dev_ops = { 177 .resize_cb = xen_block_resize_cb, 178 }; 179 180 static 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; 187 BlockConf *conf = &blockdev->props.conf; 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); 201 return; 202 } 203 } 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, 216 true, errp)) { 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 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 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 239 blk_set_dev_ops(conf->blk, &xen_block_dev_ops, blockdev); 240 blk_set_guest_block_size(conf->blk, conf->logical_block_size); 241 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) { 247 xen_device_backend_printf(xendev, "feature-discard", "%u", 1); 248 xen_device_backend_printf(xendev, "discard-granularity", "%u", 249 conf->discard_granularity); 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", 263 XEN_BLKIF_SECTOR_SIZE); 264 265 xen_block_set_size(blockdev); 266 267 blockdev->dataplane = 268 xen_block_dataplane_create(xendev, conf, blockdev->props.iothread); 269 } 270 271 static 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 319 static 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 330 static 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 367 static int vbd_name_to_disk(const char *name, const char **endp, 368 unsigned long *disk) 369 { 370 unsigned int n = 0; 371 372 while (*name != '\0') { 373 if (!g_ascii_isalpha(*name) || !g_ascii_islower(*name)) { 374 break; 375 } 376 377 n *= 26; 378 n += *name++ - 'a' + 1; 379 } 380 *endp = name; 381 382 if (!n) { 383 return -1; 384 } 385 386 *disk = n - 1; 387 388 return 0; 389 } 390 391 static 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') { 436 if (*(++end) == '\0') { 437 goto invalid; 438 } 439 } 440 } else { 441 if (vbd_name_to_disk(p, &end, &vdev->disk)) { 442 goto invalid; 443 } 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 502 invalid: 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 */ 515 const 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 522 static Property xen_block_props[] = { 523 DEFINE_PROP("vdev", XenBlockDevice, props.vdev, 524 xen_block_prop_vdev, XenBlockVdev), 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 *), 530 DEFINE_PROP_END_OF_LIST() 531 }; 532 533 static 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 538 xendev_class->backend = "qdisk"; 539 xendev_class->device = "vbd"; 540 xendev_class->get_name = xen_block_get_name; 541 xendev_class->realize = xen_block_realize; 542 xendev_class->frontend_changed = xen_block_frontend_changed; 543 xendev_class->unrealize = xen_block_unrealize; 544 545 dev_class->props = xen_block_props; 546 } 547 548 static 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 557 static void xen_disk_unrealize(XenBlockDevice *blockdev, Error **errp) 558 { 559 trace_xen_disk_unrealize(); 560 } 561 562 static void xen_disk_realize(XenBlockDevice *blockdev, Error **errp) 563 { 564 BlockConf *conf = &blockdev->props.conf; 565 566 trace_xen_disk_realize(); 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; 576 } 577 578 static 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 589 static 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 596 static void xen_cdrom_unrealize(XenBlockDevice *blockdev, Error **errp) 597 { 598 trace_xen_cdrom_unrealize(); 599 } 600 601 static void xen_cdrom_realize(XenBlockDevice *blockdev, Error **errp) 602 { 603 BlockConf *conf = &blockdev->props.conf; 604 605 trace_xen_cdrom_realize(); 606 607 blockdev->device_type = "cdrom"; 608 609 if (!conf->blk) { 610 int rc; 611 612 /* Set up an empty drive */ 613 conf->blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL); 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; 623 } 624 625 static 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 636 static 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 643 static 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 650 type_init(xen_block_register_types) 651 652 static 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 659 static 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 698 fail: 699 if (options) { 700 qapi_free_BlockdevOptions(options); 701 } 702 g_free(node_name); 703 704 return NULL; 705 } 706 707 static 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 726 static 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); 759 } else { 760 error_setg(errp, "no params"); 761 goto done; 762 } 763 764 assert(filename); 765 assert(driver); 766 767 drive = g_new0(XenBlockDrive, 1); 768 drive->id = g_strdup(id); 769 770 file_layer = qdict_new(); 771 driver_layer = qdict_new(); 772 773 qdict_put_str(file_layer, "driver", "file"); 774 qdict_put_str(file_layer, "filename", filename); 775 g_free(filename); 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); 788 qdict_put(file_layer, "cache", cache_qdict); 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"); 799 qdict_put_str(driver_layer, "discard", "unmap"); 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 809 qdict_put_str(driver_layer, "driver", driver); 810 g_free(driver); 811 812 qdict_put(driver_layer, "file", file_layer); 813 814 g_assert(!drive->node_name); 815 drive->node_name = xen_block_blockdev_add(drive->id, driver_layer, 816 &local_err); 817 818 qobject_unref(driver_layer); 819 820 done: 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 830 static const char *xen_block_drive_get_node_name(XenBlockDrive *drive) 831 { 832 return drive->node_name ? drive->node_name : ""; 833 } 834 835 static 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 844 static 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 864 static 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 958 fail: 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 972 static 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 1007 static const XenBackendInfo xen_block_backend_info = { 1008 .type = "qdisk", 1009 .create = xen_block_device_create, 1010 .destroy = xen_block_device_destroy, 1011 }; 1012 1013 static void xen_block_register_backend(void) 1014 { 1015 xen_backend_register(&xen_block_backend_info); 1016 } 1017 1018 xen_backend_init(xen_block_register_backend); 1019