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