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