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