qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

null.c (9405B)


      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 "qapi/qmp/qdict.h"
     16 #include "qapi/qmp/qstring.h"
     17 #include "qemu/module.h"
     18 #include "qemu/option.h"
     19 #include "block/block_int.h"
     20 #include "sysemu/replay.h"
     21 
     22 #define NULL_OPT_LATENCY "latency-ns"
     23 #define NULL_OPT_ZEROES  "read-zeroes"
     24 
     25 typedef struct {
     26     int64_t length;
     27     int64_t latency_ns;
     28     bool read_zeroes;
     29 } BDRVNullState;
     30 
     31 static QemuOptsList runtime_opts = {
     32     .name = "null",
     33     .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
     34     .desc = {
     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 
     55 static void null_co_parse_filename(const char *filename, QDict *options,
     56                                    Error **errp)
     57 {
     58     /* This functions only exists so that a null-co:// filename is accepted
     59      * with the null-co driver. */
     60     if (strcmp(filename, "null-co://")) {
     61         error_setg(errp, "The only allowed filename for this driver is "
     62                          "'null-co://'");
     63         return;
     64     }
     65 }
     66 
     67 static void null_aio_parse_filename(const char *filename, QDict *options,
     68                                     Error **errp)
     69 {
     70     /* This functions only exists so that a null-aio:// filename is accepted
     71      * with the null-aio driver. */
     72     if (strcmp(filename, "null-aio://")) {
     73         error_setg(errp, "The only allowed filename for this driver is "
     74                          "'null-aio://'");
     75         return;
     76     }
     77 }
     78 
     79 static int null_file_open(BlockDriverState *bs, QDict *options, int flags,
     80                           Error **errp)
     81 {
     82     QemuOpts *opts;
     83     BDRVNullState *s = bs->opaque;
     84     int ret = 0;
     85 
     86     opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
     87     qemu_opts_absorb_qdict(opts, options, &error_abort);
     88     s->length =
     89         qemu_opt_get_size(opts, BLOCK_OPT_SIZE, 1 << 30);
     90     s->latency_ns =
     91         qemu_opt_get_number(opts, NULL_OPT_LATENCY, 0);
     92     if (s->latency_ns < 0) {
     93         error_setg(errp, "latency-ns is invalid");
     94         ret = -EINVAL;
     95     }
     96     s->read_zeroes = qemu_opt_get_bool(opts, NULL_OPT_ZEROES, false);
     97     qemu_opts_del(opts);
     98     bs->supported_write_flags = BDRV_REQ_FUA;
     99     return ret;
    100 }
    101 
    102 static int64_t null_getlength(BlockDriverState *bs)
    103 {
    104     BDRVNullState *s = bs->opaque;
    105     return s->length;
    106 }
    107 
    108 static coroutine_fn int null_co_common(BlockDriverState *bs)
    109 {
    110     BDRVNullState *s = bs->opaque;
    111 
    112     if (s->latency_ns) {
    113         qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, s->latency_ns);
    114     }
    115     return 0;
    116 }
    117 
    118 static coroutine_fn int null_co_preadv(BlockDriverState *bs,
    119                                        int64_t offset, int64_t bytes,
    120                                        QEMUIOVector *qiov,
    121                                        BdrvRequestFlags flags)
    122 {
    123     BDRVNullState *s = bs->opaque;
    124 
    125     if (s->read_zeroes) {
    126         qemu_iovec_memset(qiov, 0, 0, bytes);
    127     }
    128 
    129     return null_co_common(bs);
    130 }
    131 
    132 static coroutine_fn int null_co_pwritev(BlockDriverState *bs,
    133                                         int64_t offset, int64_t bytes,
    134                                         QEMUIOVector *qiov,
    135                                         BdrvRequestFlags flags)
    136 {
    137     return null_co_common(bs);
    138 }
    139 
    140 static coroutine_fn int null_co_flush(BlockDriverState *bs)
    141 {
    142     return null_co_common(bs);
    143 }
    144 
    145 typedef struct {
    146     BlockAIOCB common;
    147     QEMUTimer timer;
    148 } NullAIOCB;
    149 
    150 static const AIOCBInfo null_aiocb_info = {
    151     .aiocb_size = sizeof(NullAIOCB),
    152 };
    153 
    154 static void null_bh_cb(void *opaque)
    155 {
    156     NullAIOCB *acb = opaque;
    157     acb->common.cb(acb->common.opaque, 0);
    158     qemu_aio_unref(acb);
    159 }
    160 
    161 static void null_timer_cb(void *opaque)
    162 {
    163     NullAIOCB *acb = opaque;
    164     acb->common.cb(acb->common.opaque, 0);
    165     timer_deinit(&acb->timer);
    166     qemu_aio_unref(acb);
    167 }
    168 
    169 static inline BlockAIOCB *null_aio_common(BlockDriverState *bs,
    170                                           BlockCompletionFunc *cb,
    171                                           void *opaque)
    172 {
    173     NullAIOCB *acb;
    174     BDRVNullState *s = bs->opaque;
    175 
    176     acb = qemu_aio_get(&null_aiocb_info, bs, cb, opaque);
    177     /* Only emulate latency after vcpu is running. */
    178     if (s->latency_ns) {
    179         aio_timer_init(bdrv_get_aio_context(bs), &acb->timer,
    180                        QEMU_CLOCK_REALTIME, SCALE_NS,
    181                        null_timer_cb, acb);
    182         timer_mod_ns(&acb->timer,
    183                      qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + s->latency_ns);
    184     } else {
    185         replay_bh_schedule_oneshot_event(bdrv_get_aio_context(bs),
    186                                          null_bh_cb, acb);
    187     }
    188     return &acb->common;
    189 }
    190 
    191 static BlockAIOCB *null_aio_preadv(BlockDriverState *bs,
    192                                    int64_t offset, int64_t bytes,
    193                                    QEMUIOVector *qiov, BdrvRequestFlags flags,
    194                                    BlockCompletionFunc *cb,
    195                                    void *opaque)
    196 {
    197     BDRVNullState *s = bs->opaque;
    198 
    199     if (s->read_zeroes) {
    200         qemu_iovec_memset(qiov, 0, 0, bytes);
    201     }
    202 
    203     return null_aio_common(bs, cb, opaque);
    204 }
    205 
    206 static BlockAIOCB *null_aio_pwritev(BlockDriverState *bs,
    207                                     int64_t offset, int64_t bytes,
    208                                     QEMUIOVector *qiov, BdrvRequestFlags flags,
    209                                     BlockCompletionFunc *cb,
    210                                     void *opaque)
    211 {
    212     return null_aio_common(bs, cb, opaque);
    213 }
    214 
    215 static BlockAIOCB *null_aio_flush(BlockDriverState *bs,
    216                                   BlockCompletionFunc *cb,
    217                                   void *opaque)
    218 {
    219     return null_aio_common(bs, cb, opaque);
    220 }
    221 
    222 static int null_reopen_prepare(BDRVReopenState *reopen_state,
    223                                BlockReopenQueue *queue, Error **errp)
    224 {
    225     return 0;
    226 }
    227 
    228 static int coroutine_fn null_co_block_status(BlockDriverState *bs,
    229                                              bool want_zero, int64_t offset,
    230                                              int64_t bytes, int64_t *pnum,
    231                                              int64_t *map,
    232                                              BlockDriverState **file)
    233 {
    234     BDRVNullState *s = bs->opaque;
    235     int ret = BDRV_BLOCK_OFFSET_VALID;
    236 
    237     *pnum = bytes;
    238     *map = offset;
    239     *file = bs;
    240 
    241     if (s->read_zeroes) {
    242         ret |= BDRV_BLOCK_ZERO;
    243     }
    244     return ret;
    245 }
    246 
    247 static void null_refresh_filename(BlockDriverState *bs)
    248 {
    249     const QDictEntry *e;
    250 
    251     for (e = qdict_first(bs->full_open_options); e;
    252          e = qdict_next(bs->full_open_options, e))
    253     {
    254         /* These options can be ignored */
    255         if (strcmp(qdict_entry_key(e), "filename") &&
    256             strcmp(qdict_entry_key(e), "driver") &&
    257             strcmp(qdict_entry_key(e), NULL_OPT_LATENCY))
    258         {
    259             return;
    260         }
    261     }
    262 
    263     snprintf(bs->exact_filename, sizeof(bs->exact_filename), "%s://",
    264              bs->drv->format_name);
    265 }
    266 
    267 static int64_t null_allocated_file_size(BlockDriverState *bs)
    268 {
    269     return 0;
    270 }
    271 
    272 static const char *const null_strong_runtime_opts[] = {
    273     BLOCK_OPT_SIZE,
    274     NULL_OPT_ZEROES,
    275 
    276     NULL
    277 };
    278 
    279 static BlockDriver bdrv_null_co = {
    280     .format_name            = "null-co",
    281     .protocol_name          = "null-co",
    282     .instance_size          = sizeof(BDRVNullState),
    283 
    284     .bdrv_file_open         = null_file_open,
    285     .bdrv_parse_filename    = null_co_parse_filename,
    286     .bdrv_getlength         = null_getlength,
    287     .bdrv_get_allocated_file_size = null_allocated_file_size,
    288 
    289     .bdrv_co_preadv         = null_co_preadv,
    290     .bdrv_co_pwritev        = null_co_pwritev,
    291     .bdrv_co_flush_to_disk  = null_co_flush,
    292     .bdrv_reopen_prepare    = null_reopen_prepare,
    293 
    294     .bdrv_co_block_status   = null_co_block_status,
    295 
    296     .bdrv_refresh_filename  = null_refresh_filename,
    297     .strong_runtime_opts    = null_strong_runtime_opts,
    298 };
    299 
    300 static BlockDriver bdrv_null_aio = {
    301     .format_name            = "null-aio",
    302     .protocol_name          = "null-aio",
    303     .instance_size          = sizeof(BDRVNullState),
    304 
    305     .bdrv_file_open         = null_file_open,
    306     .bdrv_parse_filename    = null_aio_parse_filename,
    307     .bdrv_getlength         = null_getlength,
    308     .bdrv_get_allocated_file_size = null_allocated_file_size,
    309 
    310     .bdrv_aio_preadv        = null_aio_preadv,
    311     .bdrv_aio_pwritev       = null_aio_pwritev,
    312     .bdrv_aio_flush         = null_aio_flush,
    313     .bdrv_reopen_prepare    = null_reopen_prepare,
    314 
    315     .bdrv_co_block_status   = null_co_block_status,
    316 
    317     .bdrv_refresh_filename  = null_refresh_filename,
    318     .strong_runtime_opts    = null_strong_runtime_opts,
    319 };
    320 
    321 static void bdrv_null_init(void)
    322 {
    323     bdrv_register(&bdrv_null_co);
    324     bdrv_register(&bdrv_null_aio);
    325 }
    326 
    327 block_init(bdrv_null_init);