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