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