qemu/block/null.c
<<
>>
Prefs
   1/*
   2 * Null block driver
   3 *
   4 * Authors:
   5 *  Fam Zheng <famz@redhat.com>
   6 *
   7 * Copyright (C) 2014 Red Hat, Inc.
   8 *
   9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
  10 * See the COPYING file in the top-level directory.
  11 */
  12
  13#include "qemu/osdep.h"
  14#include "qapi/error.h"
  15#include "block/block_int.h"
  16
  17#define NULL_OPT_LATENCY "latency-ns"
  18#define NULL_OPT_ZEROES  "read-zeroes"
  19
  20typedef struct {
  21    int64_t length;
  22    int64_t latency_ns;
  23    bool read_zeroes;
  24} BDRVNullState;
  25
  26static QemuOptsList runtime_opts = {
  27    .name = "null",
  28    .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
  29    .desc = {
  30        {
  31            .name = "filename",
  32            .type = QEMU_OPT_STRING,
  33            .help = "",
  34        },
  35        {
  36            .name = BLOCK_OPT_SIZE,
  37            .type = QEMU_OPT_SIZE,
  38            .help = "size of the null block",
  39        },
  40        {
  41            .name = NULL_OPT_LATENCY,
  42            .type = QEMU_OPT_NUMBER,
  43            .help = "nanoseconds (approximated) to wait "
  44                    "before completing request",
  45        },
  46        {
  47            .name = NULL_OPT_ZEROES,
  48            .type = QEMU_OPT_BOOL,
  49            .help = "return zeroes when read",
  50        },
  51        { /* end of list */ }
  52    },
  53};
  54
  55static int null_file_open(BlockDriverState *bs, QDict *options, int flags,
  56                          Error **errp)
  57{
  58    QemuOpts *opts;
  59    BDRVNullState *s = bs->opaque;
  60    int ret = 0;
  61
  62    opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
  63    qemu_opts_absorb_qdict(opts, options, &error_abort);
  64    s->length =
  65        qemu_opt_get_size(opts, BLOCK_OPT_SIZE, 1 << 30);
  66    s->latency_ns =
  67        qemu_opt_get_number(opts, NULL_OPT_LATENCY, 0);
  68    if (s->latency_ns < 0) {
  69        error_setg(errp, "latency-ns is invalid");
  70        ret = -EINVAL;
  71    }
  72    s->read_zeroes = qemu_opt_get_bool(opts, NULL_OPT_ZEROES, false);
  73    qemu_opts_del(opts);
  74    return ret;
  75}
  76
  77static void null_close(BlockDriverState *bs)
  78{
  79}
  80
  81static int64_t null_getlength(BlockDriverState *bs)
  82{
  83    BDRVNullState *s = bs->opaque;
  84    return s->length;
  85}
  86
  87static coroutine_fn int null_co_common(BlockDriverState *bs)
  88{
  89    BDRVNullState *s = bs->opaque;
  90
  91    if (s->latency_ns) {
  92        co_aio_sleep_ns(bdrv_get_aio_context(bs), QEMU_CLOCK_REALTIME,
  93                        s->latency_ns);
  94    }
  95    return 0;
  96}
  97
  98static coroutine_fn int null_co_readv(BlockDriverState *bs,
  99                                      int64_t sector_num, int nb_sectors,
 100                                      QEMUIOVector *qiov)
 101{
 102    BDRVNullState *s = bs->opaque;
 103
 104    if (s->read_zeroes) {
 105        qemu_iovec_memset(qiov, 0, 0, nb_sectors * BDRV_SECTOR_SIZE);
 106    }
 107
 108    return null_co_common(bs);
 109}
 110
 111static coroutine_fn int null_co_writev(BlockDriverState *bs,
 112                                       int64_t sector_num, int nb_sectors,
 113                                       QEMUIOVector *qiov)
 114{
 115    return null_co_common(bs);
 116}
 117
 118static coroutine_fn int null_co_flush(BlockDriverState *bs)
 119{
 120    return null_co_common(bs);
 121}
 122
 123typedef struct {
 124    BlockAIOCB common;
 125    QEMUBH *bh;
 126    QEMUTimer timer;
 127} NullAIOCB;
 128
 129static const AIOCBInfo null_aiocb_info = {
 130    .aiocb_size = sizeof(NullAIOCB),
 131};
 132
 133static void null_bh_cb(void *opaque)
 134{
 135    NullAIOCB *acb = opaque;
 136    acb->common.cb(acb->common.opaque, 0);
 137    qemu_bh_delete(acb->bh);
 138    qemu_aio_unref(acb);
 139}
 140
 141static void null_timer_cb(void *opaque)
 142{
 143    NullAIOCB *acb = opaque;
 144    acb->common.cb(acb->common.opaque, 0);
 145    timer_deinit(&acb->timer);
 146    qemu_aio_unref(acb);
 147}
 148
 149static inline BlockAIOCB *null_aio_common(BlockDriverState *bs,
 150                                          BlockCompletionFunc *cb,
 151                                          void *opaque)
 152{
 153    NullAIOCB *acb;
 154    BDRVNullState *s = bs->opaque;
 155
 156    acb = qemu_aio_get(&null_aiocb_info, bs, cb, opaque);
 157    /* Only emulate latency after vcpu is running. */
 158    if (s->latency_ns) {
 159        aio_timer_init(bdrv_get_aio_context(bs), &acb->timer,
 160                       QEMU_CLOCK_REALTIME, SCALE_NS,
 161                       null_timer_cb, acb);
 162        timer_mod_ns(&acb->timer,
 163                     qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + s->latency_ns);
 164    } else {
 165        acb->bh = aio_bh_new(bdrv_get_aio_context(bs), null_bh_cb, acb);
 166        qemu_bh_schedule(acb->bh);
 167    }
 168    return &acb->common;
 169}
 170
 171static BlockAIOCB *null_aio_readv(BlockDriverState *bs,
 172                                  int64_t sector_num, QEMUIOVector *qiov,
 173                                  int nb_sectors,
 174                                  BlockCompletionFunc *cb,
 175                                  void *opaque)
 176{
 177    BDRVNullState *s = bs->opaque;
 178
 179    if (s->read_zeroes) {
 180        qemu_iovec_memset(qiov, 0, 0, nb_sectors * BDRV_SECTOR_SIZE);
 181    }
 182
 183    return null_aio_common(bs, cb, opaque);
 184}
 185
 186static BlockAIOCB *null_aio_writev(BlockDriverState *bs,
 187                                   int64_t sector_num, QEMUIOVector *qiov,
 188                                   int nb_sectors,
 189                                   BlockCompletionFunc *cb,
 190                                   void *opaque)
 191{
 192    return null_aio_common(bs, cb, opaque);
 193}
 194
 195static BlockAIOCB *null_aio_flush(BlockDriverState *bs,
 196                                  BlockCompletionFunc *cb,
 197                                  void *opaque)
 198{
 199    return null_aio_common(bs, cb, opaque);
 200}
 201
 202static int null_reopen_prepare(BDRVReopenState *reopen_state,
 203                               BlockReopenQueue *queue, Error **errp)
 204{
 205    return 0;
 206}
 207
 208static int64_t coroutine_fn null_co_get_block_status(BlockDriverState *bs,
 209                                                     int64_t sector_num,
 210                                                     int nb_sectors, int *pnum,
 211                                                     BlockDriverState **file)
 212{
 213    BDRVNullState *s = bs->opaque;
 214    off_t start = sector_num * BDRV_SECTOR_SIZE;
 215
 216    *pnum = nb_sectors;
 217    *file = bs;
 218
 219    if (s->read_zeroes) {
 220        return BDRV_BLOCK_OFFSET_VALID | start | BDRV_BLOCK_ZERO;
 221    } else {
 222        return BDRV_BLOCK_OFFSET_VALID | start;
 223    }
 224}
 225
 226static BlockDriver bdrv_null_co = {
 227    .format_name            = "null-co",
 228    .protocol_name          = "null-co",
 229    .instance_size          = sizeof(BDRVNullState),
 230
 231    .bdrv_file_open         = null_file_open,
 232    .bdrv_close             = null_close,
 233    .bdrv_getlength         = null_getlength,
 234
 235    .bdrv_co_readv          = null_co_readv,
 236    .bdrv_co_writev         = null_co_writev,
 237    .bdrv_co_flush_to_disk  = null_co_flush,
 238    .bdrv_reopen_prepare    = null_reopen_prepare,
 239
 240    .bdrv_co_get_block_status   = null_co_get_block_status,
 241};
 242
 243static BlockDriver bdrv_null_aio = {
 244    .format_name            = "null-aio",
 245    .protocol_name          = "null-aio",
 246    .instance_size          = sizeof(BDRVNullState),
 247
 248    .bdrv_file_open         = null_file_open,
 249    .bdrv_close             = null_close,
 250    .bdrv_getlength         = null_getlength,
 251
 252    .bdrv_aio_readv         = null_aio_readv,
 253    .bdrv_aio_writev        = null_aio_writev,
 254    .bdrv_aio_flush         = null_aio_flush,
 255    .bdrv_reopen_prepare    = null_reopen_prepare,
 256
 257    .bdrv_co_get_block_status   = null_co_get_block_status,
 258};
 259
 260static void bdrv_null_init(void)
 261{
 262    bdrv_register(&bdrv_null_co);
 263    bdrv_register(&bdrv_null_aio);
 264}
 265
 266block_init(bdrv_null_init);
 267