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 "block/block_int.h"
  14
  15#define NULL_OPT_LATENCY "latency-ns"
  16
  17typedef struct {
  18    int64_t length;
  19    int64_t latency_ns;
  20} BDRVNullState;
  21
  22static QemuOptsList runtime_opts = {
  23    .name = "null",
  24    .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
  25    .desc = {
  26        {
  27            .name = "filename",
  28            .type = QEMU_OPT_STRING,
  29            .help = "",
  30        },
  31        {
  32            .name = BLOCK_OPT_SIZE,
  33            .type = QEMU_OPT_SIZE,
  34            .help = "size of the null block",
  35        },
  36        {
  37            .name = NULL_OPT_LATENCY,
  38            .type = QEMU_OPT_NUMBER,
  39            .help = "nanoseconds (approximated) to wait "
  40                    "before completing request",
  41        },
  42        { /* end of list */ }
  43    },
  44};
  45
  46static int null_file_open(BlockDriverState *bs, QDict *options, int flags,
  47                          Error **errp)
  48{
  49    QemuOpts *opts;
  50    BDRVNullState *s = bs->opaque;
  51    int ret = 0;
  52
  53    opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
  54    qemu_opts_absorb_qdict(opts, options, &error_abort);
  55    s->length =
  56        qemu_opt_get_size(opts, BLOCK_OPT_SIZE, 1 << 30);
  57    s->latency_ns =
  58        qemu_opt_get_number(opts, NULL_OPT_LATENCY, 0);
  59    if (s->latency_ns < 0) {
  60        error_setg(errp, "latency-ns is invalid");
  61        ret = -EINVAL;
  62    }
  63    qemu_opts_del(opts);
  64    return ret;
  65}
  66
  67static void null_close(BlockDriverState *bs)
  68{
  69}
  70
  71static int64_t null_getlength(BlockDriverState *bs)
  72{
  73    BDRVNullState *s = bs->opaque;
  74    return s->length;
  75}
  76
  77static coroutine_fn int null_co_common(BlockDriverState *bs)
  78{
  79    BDRVNullState *s = bs->opaque;
  80
  81    if (s->latency_ns) {
  82        co_aio_sleep_ns(bdrv_get_aio_context(bs), QEMU_CLOCK_REALTIME,
  83                        s->latency_ns);
  84    }
  85    return 0;
  86}
  87
  88static coroutine_fn int null_co_readv(BlockDriverState *bs,
  89                                      int64_t sector_num, int nb_sectors,
  90                                      QEMUIOVector *qiov)
  91{
  92    return null_co_common(bs);
  93}
  94
  95static coroutine_fn int null_co_writev(BlockDriverState *bs,
  96                                       int64_t sector_num, int nb_sectors,
  97                                       QEMUIOVector *qiov)
  98{
  99    return null_co_common(bs);
 100}
 101
 102static coroutine_fn int null_co_flush(BlockDriverState *bs)
 103{
 104    return null_co_common(bs);
 105}
 106
 107typedef struct {
 108    BlockAIOCB common;
 109    QEMUBH *bh;
 110    QEMUTimer timer;
 111} NullAIOCB;
 112
 113static const AIOCBInfo null_aiocb_info = {
 114    .aiocb_size = sizeof(NullAIOCB),
 115};
 116
 117static void null_bh_cb(void *opaque)
 118{
 119    NullAIOCB *acb = opaque;
 120    acb->common.cb(acb->common.opaque, 0);
 121    qemu_bh_delete(acb->bh);
 122    qemu_aio_unref(acb);
 123}
 124
 125static void null_timer_cb(void *opaque)
 126{
 127    NullAIOCB *acb = opaque;
 128    acb->common.cb(acb->common.opaque, 0);
 129    timer_deinit(&acb->timer);
 130    qemu_aio_unref(acb);
 131}
 132
 133static inline BlockAIOCB *null_aio_common(BlockDriverState *bs,
 134                                          BlockCompletionFunc *cb,
 135                                          void *opaque)
 136{
 137    NullAIOCB *acb;
 138    BDRVNullState *s = bs->opaque;
 139
 140    acb = qemu_aio_get(&null_aiocb_info, bs, cb, opaque);
 141    /* Only emulate latency after vcpu is running. */
 142    if (s->latency_ns) {
 143        aio_timer_init(bdrv_get_aio_context(bs), &acb->timer,
 144                       QEMU_CLOCK_REALTIME, SCALE_NS,
 145                       null_timer_cb, acb);
 146        timer_mod_ns(&acb->timer,
 147                     qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + s->latency_ns);
 148    } else {
 149        acb->bh = aio_bh_new(bdrv_get_aio_context(bs), null_bh_cb, acb);
 150        qemu_bh_schedule(acb->bh);
 151    }
 152    return &acb->common;
 153}
 154
 155static BlockAIOCB *null_aio_readv(BlockDriverState *bs,
 156                                  int64_t sector_num, QEMUIOVector *qiov,
 157                                  int nb_sectors,
 158                                  BlockCompletionFunc *cb,
 159                                  void *opaque)
 160{
 161    return null_aio_common(bs, cb, opaque);
 162}
 163
 164static BlockAIOCB *null_aio_writev(BlockDriverState *bs,
 165                                   int64_t sector_num, QEMUIOVector *qiov,
 166                                   int nb_sectors,
 167                                   BlockCompletionFunc *cb,
 168                                   void *opaque)
 169{
 170    return null_aio_common(bs, cb, opaque);
 171}
 172
 173static BlockAIOCB *null_aio_flush(BlockDriverState *bs,
 174                                  BlockCompletionFunc *cb,
 175                                  void *opaque)
 176{
 177    return null_aio_common(bs, cb, opaque);
 178}
 179
 180static int null_reopen_prepare(BDRVReopenState *reopen_state,
 181                               BlockReopenQueue *queue, Error **errp)
 182{
 183    return 0;
 184}
 185
 186static BlockDriver bdrv_null_co = {
 187    .format_name            = "null-co",
 188    .protocol_name          = "null-co",
 189    .instance_size          = sizeof(BDRVNullState),
 190
 191    .bdrv_file_open         = null_file_open,
 192    .bdrv_close             = null_close,
 193    .bdrv_getlength         = null_getlength,
 194
 195    .bdrv_co_readv          = null_co_readv,
 196    .bdrv_co_writev         = null_co_writev,
 197    .bdrv_co_flush_to_disk  = null_co_flush,
 198    .bdrv_reopen_prepare    = null_reopen_prepare,
 199};
 200
 201static BlockDriver bdrv_null_aio = {
 202    .format_name            = "null-aio",
 203    .protocol_name          = "null-aio",
 204    .instance_size          = sizeof(BDRVNullState),
 205
 206    .bdrv_file_open         = null_file_open,
 207    .bdrv_close             = null_close,
 208    .bdrv_getlength         = null_getlength,
 209
 210    .bdrv_aio_readv         = null_aio_readv,
 211    .bdrv_aio_writev        = null_aio_writev,
 212    .bdrv_aio_flush         = null_aio_flush,
 213    .bdrv_reopen_prepare    = null_reopen_prepare,
 214};
 215
 216static void bdrv_null_init(void)
 217{
 218    bdrv_register(&bdrv_null_co);
 219    bdrv_register(&bdrv_null_aio);
 220}
 221
 222block_init(bdrv_null_init);
 223