virtio-blk.c 16.9 KB
Newer Older
A
aliguori 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13
/*
 * Virtio Block Device
 *
 * Copyright IBM, Corp. 2007
 *
 * Authors:
 *  Anthony Liguori   <aliguori@us.ibm.com>
 *
 * This work is licensed under the terms of the GNU GPL, version 2.  See
 * the COPYING file in the top-level directory.
 *
 */

14
#include "qemu-common.h"
15
#include "qemu-error.h"
16
#include "trace.h"
B
Blue Swirl 已提交
17
#include "blockdev.h"
A
aliguori 已提交
18
#include "virtio-blk.h"
19
#include "scsi-defs.h"
20 21 22
#ifdef __linux__
# include <scsi/sg.h>
#endif
A
aliguori 已提交
23 24 25 26 27 28

typedef struct VirtIOBlock
{
    VirtIODevice vdev;
    BlockDriverState *bs;
    VirtQueue *vq;
29
    void *rq;
30
    QEMUBH *bh;
31
    BlockConf *conf;
P
Paolo Bonzini 已提交
32
    VirtIOBlkConf *blk;
33
    unsigned short sector_mask;
34
    DeviceState *qdev;
A
aliguori 已提交
35 36 37 38 39 40 41 42 43 44 45 46 47
} VirtIOBlock;

static VirtIOBlock *to_virtio_blk(VirtIODevice *vdev)
{
    return (VirtIOBlock *)vdev;
}

typedef struct VirtIOBlockReq
{
    VirtIOBlock *dev;
    VirtQueueElement elem;
    struct virtio_blk_inhdr *in;
    struct virtio_blk_outhdr *out;
48
    struct virtio_scsi_inhdr *scsi;
49
    QEMUIOVector qiov;
50
    struct VirtIOBlockReq *next;
51
    BlockAcctCookie acct;
A
aliguori 已提交
52 53
} VirtIOBlockReq;

54 55 56 57
static void virtio_blk_req_complete(VirtIOBlockReq *req, int status)
{
    VirtIOBlock *s = req->dev;

58 59
    trace_virtio_blk_req_complete(req, status);

60
    stb_p(&req->in->status, status);
61
    virtqueue_push(s->vq, &req->elem, req->qiov.size + sizeof(*req->in));
62 63 64
    virtio_notify(&s->vdev, s->vq);
}

K
Kevin Wolf 已提交
65 66
static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error,
    int is_read)
67
{
68
    BlockErrorAction action = bdrv_get_on_error(req->dev->bs, is_read);
69 70
    VirtIOBlock *s = req->dev;

71
    if (action == BLOCK_ERR_IGNORE) {
72
        bdrv_emit_qmp_error_event(s->bs, BDRV_ACTION_IGNORE, is_read);
73
        return 0;
74
    }
75 76 77 78 79

    if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC)
            || action == BLOCK_ERR_STOP_ANY) {
        req->next = s->rq;
        s->rq = req;
80
        bdrv_emit_qmp_error_event(s->bs, BDRV_ACTION_STOP, is_read);
81
        vm_stop(RUN_STATE_IO_ERROR);
L
Luiz Capitulino 已提交
82
        bdrv_iostatus_set_err(s->bs, error);
83 84
    } else {
        virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
85 86
        bdrv_acct_done(s->bs, &req->acct);
        g_free(req);
87
        bdrv_emit_qmp_error_event(s->bs, BDRV_ACTION_REPORT, is_read);
88 89 90 91 92
    }

    return 1;
}

A
aliguori 已提交
93 94 95 96
static void virtio_blk_rw_complete(void *opaque, int ret)
{
    VirtIOBlockReq *req = opaque;

97 98
    trace_virtio_blk_rw_complete(req, ret);

K
Kevin Wolf 已提交
99
    if (ret) {
100
        int is_read = !(ldl_p(&req->out->type) & VIRTIO_BLK_T_OUT);
K
Kevin Wolf 已提交
101
        if (virtio_blk_handle_rw_error(req, -ret, is_read))
102
            return;
A
aliguori 已提交
103 104
    }

K
Kevin Wolf 已提交
105
    virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
106 107
    bdrv_acct_done(req->dev->bs, &req->acct);
    g_free(req);
108
}
A
aliguori 已提交
109

110 111 112 113
static void virtio_blk_flush_complete(void *opaque, int ret)
{
    VirtIOBlockReq *req = opaque;

114 115 116 117 118 119 120
    if (ret) {
        if (virtio_blk_handle_rw_error(req, -ret, 0)) {
            return;
        }
    }

    virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
121 122
    bdrv_acct_done(req->dev->bs, &req->acct);
    g_free(req);
123 124
}

125 126
static VirtIOBlockReq *virtio_blk_alloc_request(VirtIOBlock *s)
{
127
    VirtIOBlockReq *req = g_malloc(sizeof(*req));
128
    req->dev = s;
129 130
    req->qiov.size = 0;
    req->next = NULL;
131
    return req;
A
aliguori 已提交
132 133 134 135
}

static VirtIOBlockReq *virtio_blk_get_request(VirtIOBlock *s)
{
136
    VirtIOBlockReq *req = virtio_blk_alloc_request(s);
A
aliguori 已提交
137

138 139
    if (req != NULL) {
        if (!virtqueue_pop(s->vq, &req->elem)) {
140
            g_free(req);
141 142
            return NULL;
        }
A
aliguori 已提交
143 144 145 146 147
    }

    return req;
}

148 149
static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
{
150
    int ret;
151
    int status = VIRTIO_BLK_S_OK;
152 153 154 155 156 157 158 159 160 161 162
    int i;

    /*
     * We require at least one output segment each for the virtio_blk_outhdr
     * and the SCSI command block.
     *
     * We also at least require the virtio_blk_inhdr, the virtio_scsi_inhdr
     * and the sense buffer pointer in the input segments.
     */
    if (req->elem.out_num < 2 || req->elem.in_num < 3) {
        virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
163
        g_free(req);
164 165 166 167
        return;
    }

    /*
168 169
     * The scsi inhdr is placed in the second-to-last input segment, just
     * before the regular inhdr.
170
     */
171 172
    req->scsi = (void *)req->elem.in_sg[req->elem.in_num - 2].iov_base;

173
    if (!req->dev->blk->scsi) {
174 175
        status = VIRTIO_BLK_S_UNSUPP;
        goto fail;
176 177 178
    }

    /*
179
     * No support for bidirection commands yet.
180
     */
181 182 183 184
    if (req->elem.out_num > 2 && req->elem.in_num > 3) {
        status = VIRTIO_BLK_S_UNSUPP;
        goto fail;
    }
185

186 187
#ifdef __linux__
    struct sg_io_hdr hdr;
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
    memset(&hdr, 0, sizeof(struct sg_io_hdr));
    hdr.interface_id = 'S';
    hdr.cmd_len = req->elem.out_sg[1].iov_len;
    hdr.cmdp = req->elem.out_sg[1].iov_base;
    hdr.dxfer_len = 0;

    if (req->elem.out_num > 2) {
        /*
         * If there are more than the minimally required 2 output segments
         * there is write payload starting from the third iovec.
         */
        hdr.dxfer_direction = SG_DXFER_TO_DEV;
        hdr.iovec_count = req->elem.out_num - 2;

        for (i = 0; i < hdr.iovec_count; i++)
            hdr.dxfer_len += req->elem.out_sg[i + 2].iov_len;

        hdr.dxferp = req->elem.out_sg + 2;

    } else if (req->elem.in_num > 3) {
        /*
         * If we have more than 3 input segments the guest wants to actually
         * read data.
         */
        hdr.dxfer_direction = SG_DXFER_FROM_DEV;
        hdr.iovec_count = req->elem.in_num - 3;
        for (i = 0; i < hdr.iovec_count; i++)
            hdr.dxfer_len += req->elem.in_sg[i].iov_len;

        hdr.dxferp = req->elem.in_sg;
    } else {
        /*
         * Some SCSI commands don't actually transfer any data.
         */
        hdr.dxfer_direction = SG_DXFER_NONE;
    }

    hdr.sbp = req->elem.in_sg[req->elem.in_num - 3].iov_base;
    hdr.mx_sb_len = req->elem.in_sg[req->elem.in_num - 3].iov_len;

    ret = bdrv_ioctl(req->dev->bs, SG_IO, &hdr);
    if (ret) {
        status = VIRTIO_BLK_S_UNSUPP;
231
        goto fail;
232 233
    }

234 235 236 237 238 239 240 241 242 243 244 245 246 247
    /*
     * From SCSI-Generic-HOWTO: "Some lower level drivers (e.g. ide-scsi)
     * clear the masked_status field [hence status gets cleared too, see
     * block/scsi_ioctl.c] even when a CHECK_CONDITION or COMMAND_TERMINATED
     * status has occurred.  However they do set DRIVER_SENSE in driver_status
     * field. Also a (sb_len_wr > 0) indicates there is a sense buffer.
     */
    if (hdr.status == 0 && hdr.sb_len_wr > 0) {
        hdr.status = CHECK_CONDITION;
    }

    stl_p(&req->scsi->errors,
          hdr.status | (hdr.msg_status << 8) |
          (hdr.host_status << 16) | (hdr.driver_status << 24));
248 249 250
    stl_p(&req->scsi->residual, hdr.resid);
    stl_p(&req->scsi->sense_len, hdr.sb_len_wr);
    stl_p(&req->scsi->data_len, hdr.dxfer_len);
251 252

    virtio_blk_req_complete(req, status);
253
    g_free(req);
254
#else
255 256 257 258 259 260 261
    abort();
#endif

fail:
    /* Just put anything nonzero so that the ioctl fails in the guest.  */
    stl_p(&req->scsi->errors, 255);
    virtio_blk_req_complete(req, status);
262
    g_free(req);
263 264
}

265 266 267 268 269 270
typedef struct MultiReqBuffer {
    BlockRequest        blkreq[32];
    unsigned int        num_writes;
} MultiReqBuffer;

static void virtio_submit_multiwrite(BlockDriverState *bs, MultiReqBuffer *mrb)
271
{
K
Kevin Wolf 已提交
272 273
    int i, ret;

274 275 276 277 278
    if (!mrb->num_writes) {
        return;
    }

    ret = bdrv_aio_multiwrite(bs, mrb->blkreq, mrb->num_writes);
K
Kevin Wolf 已提交
279
    if (ret != 0) {
280 281 282
        for (i = 0; i < mrb->num_writes; i++) {
            if (mrb->blkreq[i].error) {
                virtio_blk_rw_complete(mrb->blkreq[i].opaque, -EIO);
K
Kevin Wolf 已提交
283 284 285
            }
        }
    }
286 287

    mrb->num_writes = 0;
K
Kevin Wolf 已提交
288
}
289

290
static void virtio_blk_handle_flush(VirtIOBlockReq *req, MultiReqBuffer *mrb)
291
{
292 293
    bdrv_acct_start(req->dev->bs, &req->acct, 0, BDRV_ACCT_FLUSH);

294 295 296
    /*
     * Make sure all outstanding writes are posted to the backing device.
     */
297
    virtio_submit_multiwrite(req->dev->bs, mrb);
298
    bdrv_aio_flush(req->dev->bs, virtio_blk_flush_complete, req);
299 300
}

301
static void virtio_blk_handle_write(VirtIOBlockReq *req, MultiReqBuffer *mrb)
K
Kevin Wolf 已提交
302
{
303
    BlockRequest *blkreq;
304
    uint64_t sector;
305

306
    sector = ldq_p(&req->out->sector);
307

308 309
    bdrv_acct_start(req->dev->bs, &req->acct, req->qiov.size, BDRV_ACCT_WRITE);

310 311 312
    trace_virtio_blk_handle_write(req, sector, req->qiov.size / 512);

    if (sector & req->dev->sector_mask) {
313 314 315
        virtio_blk_rw_complete(req, -EIO);
        return;
    }
316 317 318 319
    if (req->qiov.size % req->dev->conf->logical_block_size) {
        virtio_blk_rw_complete(req, -EIO);
        return;
    }
320

321 322
    if (mrb->num_writes == 32) {
        virtio_submit_multiwrite(req->dev->bs, mrb);
323
    }
K
Kevin Wolf 已提交
324

325
    blkreq = &mrb->blkreq[mrb->num_writes];
326
    blkreq->sector = sector;
327 328 329 330 331
    blkreq->nb_sectors = req->qiov.size / BDRV_SECTOR_SIZE;
    blkreq->qiov = &req->qiov;
    blkreq->cb = virtio_blk_rw_complete;
    blkreq->opaque = req;
    blkreq->error = 0;
K
Kevin Wolf 已提交
332

333
    mrb->num_writes++;
334
}
335

336 337
static void virtio_blk_handle_read(VirtIOBlockReq *req)
{
338 339 340
    uint64_t sector;

    sector = ldq_p(&req->out->sector);
341

342 343
    bdrv_acct_start(req->dev->bs, &req->acct, req->qiov.size, BDRV_ACCT_READ);

344 345
    trace_virtio_blk_handle_read(req, sector, req->qiov.size / 512);

346
    if (sector & req->dev->sector_mask) {
347 348 349
        virtio_blk_rw_complete(req, -EIO);
        return;
    }
350 351 352 353
    if (req->qiov.size % req->dev->conf->logical_block_size) {
        virtio_blk_rw_complete(req, -EIO);
        return;
    }
354 355 356
    bdrv_aio_readv(req->dev->bs, sector, &req->qiov,
                   req->qiov.size / BDRV_SECTOR_SIZE,
                   virtio_blk_rw_complete, req);
357 358
}

359 360 361
static void virtio_blk_handle_request(VirtIOBlockReq *req,
    MultiReqBuffer *mrb)
{
362 363
    uint32_t type;

364
    if (req->elem.out_num < 1 || req->elem.in_num < 1) {
365
        error_report("virtio-blk missing headers");
366 367 368 369 370
        exit(1);
    }

    if (req->elem.out_sg[0].iov_len < sizeof(*req->out) ||
        req->elem.in_sg[req->elem.in_num - 1].iov_len < sizeof(*req->in)) {
371
        error_report("virtio-blk header not in correct element");
372 373 374 375 376 377
        exit(1);
    }

    req->out = (void *)req->elem.out_sg[0].iov_base;
    req->in = (void *)req->elem.in_sg[req->elem.in_num - 1].iov_base;

378 379 380
    type = ldl_p(&req->out->type);

    if (type & VIRTIO_BLK_T_FLUSH) {
381
        virtio_blk_handle_flush(req, mrb);
382
    } else if (type & VIRTIO_BLK_T_SCSI_CMD) {
383
        virtio_blk_handle_scsi(req);
384
    } else if (type & VIRTIO_BLK_T_GET_ID) {
385 386
        VirtIOBlock *s = req->dev;

387 388 389 390 391
        /*
         * NB: per existing s/n string convention the string is
         * terminated by '\0' only when shorter than buffer.
         */
        strncpy(req->elem.in_sg[0].iov_base,
P
Paolo Bonzini 已提交
392
                s->blk->serial ? s->blk->serial : "",
393
                MIN(req->elem.in_sg[0].iov_len, VIRTIO_BLK_ID_BYTES));
394
        virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
395
        g_free(req);
396
    } else if (type & VIRTIO_BLK_T_OUT) {
397 398
        qemu_iovec_init_external(&req->qiov, &req->elem.out_sg[1],
                                 req->elem.out_num - 1);
399
        virtio_blk_handle_write(req, mrb);
400 401 402 403 404 405 406
    } else {
        qemu_iovec_init_external(&req->qiov, &req->elem.in_sg[0],
                                 req->elem.in_num - 1);
        virtio_blk_handle_read(req);
    }
}

A
aliguori 已提交
407 408 409 410
static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
{
    VirtIOBlock *s = to_virtio_blk(vdev);
    VirtIOBlockReq *req;
411 412 413
    MultiReqBuffer mrb = {
        .num_writes = 0,
    };
A
aliguori 已提交
414 415

    while ((req = virtio_blk_get_request(s))) {
416
        virtio_blk_handle_request(req, &mrb);
A
aliguori 已提交
417
    }
K
Kevin Wolf 已提交
418

419
    virtio_submit_multiwrite(s->bs, &mrb);
K
Kevin Wolf 已提交
420

A
aliguori 已提交
421 422 423 424 425 426 427
    /*
     * FIXME: Want to check for completions before returning to guest mode,
     * so cached reads and writes are reported as quickly as possible. But
     * that should be done in the generic block layer.
     */
}

428
static void virtio_blk_dma_restart_bh(void *opaque)
429 430 431
{
    VirtIOBlock *s = opaque;
    VirtIOBlockReq *req = s->rq;
432 433 434
    MultiReqBuffer mrb = {
        .num_writes = 0,
    };
435

436 437
    qemu_bh_delete(s->bh);
    s->bh = NULL;
438 439 440 441

    s->rq = NULL;

    while (req) {
442
        virtio_blk_handle_request(req, &mrb);
443 444
        req = req->next;
    }
445

446
    virtio_submit_multiwrite(s->bs, &mrb);
447 448
}

449 450
static void virtio_blk_dma_restart_cb(void *opaque, int running,
                                      RunState state)
451 452 453 454 455 456 457 458 459 460 461 462
{
    VirtIOBlock *s = opaque;

    if (!running)
        return;

    if (!s->bh) {
        s->bh = qemu_bh_new(virtio_blk_dma_restart_bh, s);
        qemu_bh_schedule(s->bh);
    }
}

A
aliguori 已提交
463 464 465 466 467 468
static void virtio_blk_reset(VirtIODevice *vdev)
{
    /*
     * This should cancel pending requests, but can't do nicely until there
     * are per-device request lists.
     */
469
    bdrv_drain_all();
A
aliguori 已提交
470 471
}

472 473
/* coalesce internal state, copy to pci i/o region 0
 */
A
aliguori 已提交
474 475 476 477 478 479
static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
{
    VirtIOBlock *s = to_virtio_blk(vdev);
    struct virtio_blk_config blkcfg;
    uint64_t capacity;
    int cylinders, heads, secs;
480
    int blk_size = s->conf->logical_block_size;
A
aliguori 已提交
481 482 483

    bdrv_get_geometry(s->bs, &capacity);
    bdrv_get_geometry_hint(s->bs, &cylinders, &heads, &secs);
G
Gerd Hoffmann 已提交
484
    memset(&blkcfg, 0, sizeof(blkcfg));
A
aliguori 已提交
485 486 487
    stq_raw(&blkcfg.capacity, capacity);
    stl_raw(&blkcfg.seg_max, 128 - 2);
    stw_raw(&blkcfg.cylinders, cylinders);
488 489 490
    stl_raw(&blkcfg.blk_size, blk_size);
    stw_raw(&blkcfg.min_io_size, s->conf->min_io_size / blk_size);
    stw_raw(&blkcfg.opt_io_size, s->conf->opt_io_size / blk_size);
A
aliguori 已提交
491
    blkcfg.heads = heads;
492
    blkcfg.sectors = secs & ~s->sector_mask;
493
    blkcfg.size_max = 0;
494 495
    blkcfg.physical_block_exp = get_physical_block_exp(s->conf);
    blkcfg.alignment_offset = 0;
496
    memcpy(config, &blkcfg, sizeof(struct virtio_blk_config));
A
aliguori 已提交
497 498
}

499
static uint32_t virtio_blk_get_features(VirtIODevice *vdev, uint32_t features)
A
aliguori 已提交
500
{
501
    VirtIOBlock *s = to_virtio_blk(vdev);
502 503 504

    features |= (1 << VIRTIO_BLK_F_SEG_MAX);
    features |= (1 << VIRTIO_BLK_F_GEOMETRY);
505
    features |= (1 << VIRTIO_BLK_F_TOPOLOGY);
506
    features |= (1 << VIRTIO_BLK_F_BLK_SIZE);
507
    features |= (1 << VIRTIO_BLK_F_SCSI);
508 509 510

    if (bdrv_enable_write_cache(s->bs))
        features |= (1 << VIRTIO_BLK_F_WCACHE);
511 512 513
    
    if (bdrv_is_read_only(s->bs))
        features |= 1 << VIRTIO_BLK_F_RO;
514 515

    return features;
A
aliguori 已提交
516 517 518 519 520
}

static void virtio_blk_save(QEMUFile *f, void *opaque)
{
    VirtIOBlock *s = opaque;
521 522
    VirtIOBlockReq *req = s->rq;

A
aliguori 已提交
523
    virtio_save(&s->vdev, f);
524 525 526 527 528 529 530
    
    while (req) {
        qemu_put_sbyte(f, 1);
        qemu_put_buffer(f, (unsigned char*)&req->elem, sizeof(req->elem));
        req = req->next;
    }
    qemu_put_sbyte(f, 0);
A
aliguori 已提交
531 532 533 534 535 536
}

static int virtio_blk_load(QEMUFile *f, void *opaque, int version_id)
{
    VirtIOBlock *s = opaque;

537
    if (version_id != 2)
A
aliguori 已提交
538 539 540
        return -EINVAL;

    virtio_load(&s->vdev, f);
541 542 543 544
    while (qemu_get_sbyte(f)) {
        VirtIOBlockReq *req = virtio_blk_alloc_request(s);
        qemu_get_buffer(f, (unsigned char*)&req->elem, sizeof(req->elem));
        req->next = s->rq;
545
        s->rq = req;
546 547 548 549 550

        virtqueue_map_sg(req->elem.in_sg, req->elem.in_addr,
            req->elem.in_num, 1);
        virtqueue_map_sg(req->elem.out_sg, req->elem.out_addr,
            req->elem.out_num, 0);
551
    }
A
aliguori 已提交
552 553 554 555

    return 0;
}

556
static void virtio_blk_resize(void *opaque)
557 558 559
{
    VirtIOBlock *s = opaque;

560
    virtio_notify_config(&s->vdev);
561 562
}

563
static const BlockDevOps virtio_block_ops = {
564
    .resize_cb = virtio_blk_resize,
565 566
};

P
Paolo Bonzini 已提交
567
VirtIODevice *virtio_blk_init(DeviceState *dev, VirtIOBlkConf *blk)
A
aliguori 已提交
568 569 570 571
{
    VirtIOBlock *s;
    int cylinders, heads, secs;
    static int virtio_blk_id;
572
    DriveInfo *dinfo;
P
Paul Brook 已提交
573

P
Paolo Bonzini 已提交
574
    if (!blk->conf.bs) {
575
        error_report("drive property not set");
576 577
        return NULL;
    }
P
Paolo Bonzini 已提交
578
    if (!bdrv_is_inserted(blk->conf.bs)) {
579 580 581
        error_report("Device needs media, but drive is empty");
        return NULL;
    }
582

P
Paolo Bonzini 已提交
583
    if (!blk->serial) {
584
        /* try to fall back to value set with legacy -drive serial=... */
P
Paolo Bonzini 已提交
585
        dinfo = drive_get_by_blockdev(blk->conf.bs);
586
        if (*dinfo->serial) {
P
Paolo Bonzini 已提交
587
            blk->serial = strdup(dinfo->serial);
588 589 590
        }
    }

P
Paul Brook 已提交
591
    s = (VirtIOBlock *)virtio_common_init("virtio-blk", VIRTIO_ID_BLOCK,
592
                                          sizeof(struct virtio_blk_config),
P
Paul Brook 已提交
593
                                          sizeof(VirtIOBlock));
A
aliguori 已提交
594 595 596 597

    s->vdev.get_config = virtio_blk_update_config;
    s->vdev.get_features = virtio_blk_get_features;
    s->vdev.reset = virtio_blk_reset;
P
Paolo Bonzini 已提交
598 599 600
    s->bs = blk->conf.bs;
    s->conf = &blk->conf;
    s->blk = blk;
601
    s->rq = NULL;
602
    s->sector_mask = (s->conf->logical_block_size / BDRV_SECTOR_SIZE) - 1;
A
aliguori 已提交
603 604 605 606
    bdrv_guess_geometry(s->bs, &cylinders, &heads, &secs);

    s->vq = virtio_add_queue(&s->vdev, 128, virtio_blk_handle_output);

607
    qemu_add_vm_change_state_handler(virtio_blk_dma_restart_cb, s);
608
    s->qdev = dev;
A
Alex Williamson 已提交
609
    register_savevm(dev, "virtio-blk", virtio_blk_id++, 2,
A
aliguori 已提交
610
                    virtio_blk_save, virtio_blk_load, s);
611
    bdrv_set_dev_ops(s->bs, &virtio_block_ops, s);
P
Paolo Bonzini 已提交
612
    bdrv_set_buffer_alignment(s->bs, s->conf->logical_block_size);
A
aliguori 已提交
613

L
Luiz Capitulino 已提交
614
    bdrv_iostatus_enable(s->bs);
P
Paolo Bonzini 已提交
615
    add_boot_device_path(s->conf->bootindex, dev, "/disk@0,0");
616

P
Paul Brook 已提交
617
    return &s->vdev;
A
aliguori 已提交
618
}
619 620 621 622 623

void virtio_blk_exit(VirtIODevice *vdev)
{
    VirtIOBlock *s = to_virtio_blk(vdev);
    unregister_savevm(s->qdev, "virtio-blk", s);
624
    blockdev_mark_auto_del(s->bs);
A
Amit Shah 已提交
625
    virtio_cleanup(vdev);
626
}