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" 1567882b15SMax Reitz #include "qapi/qmp/qdict.h" 1667882b15SMax Reitz #include "qapi/qmp/qstring.h" 170b8fa32fSMarkus Armbruster #include "qemu/module.h" 18922a01a0SMarkus Armbruster #include "qemu/option.h" 19e819ab22SFam Zheng #include "block/block_int.h" 20e4ec5ad4SPavel Dovgalyuk #include "sysemu/replay.h" 21e819ab22SFam Zheng 22e5e51dd3SFam Zheng #define NULL_OPT_LATENCY "latency-ns" 23cd219eb1SMax Reitz #define NULL_OPT_ZEROES "read-zeroes" 24e5e51dd3SFam Zheng 25e819ab22SFam Zheng typedef struct { 26e819ab22SFam Zheng int64_t length; 27e5e51dd3SFam Zheng int64_t latency_ns; 28cd219eb1SMax Reitz bool read_zeroes; 29e819ab22SFam Zheng } BDRVNullState; 30e819ab22SFam Zheng 31e819ab22SFam Zheng static QemuOptsList runtime_opts = { 32e819ab22SFam Zheng .name = "null", 33e819ab22SFam Zheng .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head), 34e819ab22SFam Zheng .desc = { 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 }, 46cd219eb1SMax Reitz { 47cd219eb1SMax Reitz .name = NULL_OPT_ZEROES, 48cd219eb1SMax Reitz .type = QEMU_OPT_BOOL, 49cd219eb1SMax Reitz .help = "return zeroes when read", 50cd219eb1SMax Reitz }, 51e819ab22SFam Zheng { /* end of list */ } 52e819ab22SFam Zheng }, 53e819ab22SFam Zheng }; 54e819ab22SFam Zheng 55809eb70eSKevin Wolf static void null_co_parse_filename(const char *filename, QDict *options, 56809eb70eSKevin Wolf Error **errp) 57809eb70eSKevin Wolf { 58809eb70eSKevin Wolf /* This functions only exists so that a null-co:// filename is accepted 59809eb70eSKevin Wolf * with the null-co driver. */ 60809eb70eSKevin Wolf if (strcmp(filename, "null-co://")) { 61809eb70eSKevin Wolf error_setg(errp, "The only allowed filename for this driver is " 62809eb70eSKevin Wolf "'null-co://'"); 63809eb70eSKevin Wolf return; 64809eb70eSKevin Wolf } 65809eb70eSKevin Wolf } 66809eb70eSKevin Wolf 67809eb70eSKevin Wolf static void null_aio_parse_filename(const char *filename, QDict *options, 68809eb70eSKevin Wolf Error **errp) 69809eb70eSKevin Wolf { 70809eb70eSKevin Wolf /* This functions only exists so that a null-aio:// filename is accepted 71809eb70eSKevin Wolf * with the null-aio driver. */ 72809eb70eSKevin Wolf if (strcmp(filename, "null-aio://")) { 73809eb70eSKevin Wolf error_setg(errp, "The only allowed filename for this driver is " 74809eb70eSKevin Wolf "'null-aio://'"); 75809eb70eSKevin Wolf return; 76809eb70eSKevin Wolf } 77809eb70eSKevin Wolf } 78809eb70eSKevin Wolf 79e819ab22SFam Zheng static int null_file_open(BlockDriverState *bs, QDict *options, int flags, 80e819ab22SFam Zheng Error **errp) 81e819ab22SFam Zheng { 82e819ab22SFam Zheng QemuOpts *opts; 83e819ab22SFam Zheng BDRVNullState *s = bs->opaque; 84e5e51dd3SFam Zheng int ret = 0; 85e819ab22SFam Zheng 86e819ab22SFam Zheng opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); 87e819ab22SFam Zheng qemu_opts_absorb_qdict(opts, options, &error_abort); 88e819ab22SFam Zheng s->length = 89e819ab22SFam Zheng qemu_opt_get_size(opts, BLOCK_OPT_SIZE, 1 << 30); 90e5e51dd3SFam Zheng s->latency_ns = 91e5e51dd3SFam Zheng qemu_opt_get_number(opts, NULL_OPT_LATENCY, 0); 92e5e51dd3SFam Zheng if (s->latency_ns < 0) { 93e5e51dd3SFam Zheng error_setg(errp, "latency-ns is invalid"); 94e5e51dd3SFam Zheng ret = -EINVAL; 95e5e51dd3SFam Zheng } 96cd219eb1SMax Reitz s->read_zeroes = qemu_opt_get_bool(opts, NULL_OPT_ZEROES, false); 97e819ab22SFam Zheng qemu_opts_del(opts); 98b3241e92SEric Blake bs->supported_write_flags = BDRV_REQ_FUA; 99e5e51dd3SFam Zheng return ret; 100e819ab22SFam Zheng } 101e819ab22SFam Zheng 102e819ab22SFam Zheng static int64_t null_getlength(BlockDriverState *bs) 103e819ab22SFam Zheng { 104e819ab22SFam Zheng BDRVNullState *s = bs->opaque; 105e819ab22SFam Zheng return s->length; 106e819ab22SFam Zheng } 107e819ab22SFam Zheng 108e5e51dd3SFam Zheng static coroutine_fn int null_co_common(BlockDriverState *bs) 109e5e51dd3SFam Zheng { 110e5e51dd3SFam Zheng BDRVNullState *s = bs->opaque; 111e5e51dd3SFam Zheng 112e5e51dd3SFam Zheng if (s->latency_ns) { 11378f1d3d6SStefan Hajnoczi qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, s->latency_ns); 114e5e51dd3SFam Zheng } 115e5e51dd3SFam Zheng return 0; 116e5e51dd3SFam Zheng } 117e5e51dd3SFam Zheng 118b3241e92SEric Blake static coroutine_fn int null_co_preadv(BlockDriverState *bs, 119*f7ef38ddSVladimir Sementsov-Ogievskiy int64_t offset, int64_t bytes, 120*f7ef38ddSVladimir Sementsov-Ogievskiy QEMUIOVector *qiov, 121*f7ef38ddSVladimir Sementsov-Ogievskiy BdrvRequestFlags flags) 122e819ab22SFam Zheng { 123cd219eb1SMax Reitz BDRVNullState *s = bs->opaque; 124cd219eb1SMax Reitz 125cd219eb1SMax Reitz if (s->read_zeroes) { 126b3241e92SEric Blake qemu_iovec_memset(qiov, 0, 0, bytes); 127cd219eb1SMax Reitz } 128cd219eb1SMax Reitz 129e5e51dd3SFam Zheng return null_co_common(bs); 130e819ab22SFam Zheng } 131e819ab22SFam Zheng 132b3241e92SEric Blake static coroutine_fn int null_co_pwritev(BlockDriverState *bs, 133b3241e92SEric Blake uint64_t offset, uint64_t bytes, 134b3241e92SEric Blake QEMUIOVector *qiov, int flags) 135e819ab22SFam Zheng { 136e5e51dd3SFam Zheng return null_co_common(bs); 137e819ab22SFam Zheng } 138e819ab22SFam Zheng 139e819ab22SFam Zheng static coroutine_fn int null_co_flush(BlockDriverState *bs) 140e819ab22SFam Zheng { 141e5e51dd3SFam Zheng return null_co_common(bs); 142e819ab22SFam Zheng } 143e819ab22SFam Zheng 144e819ab22SFam Zheng typedef struct { 1457c84b1b8SMarkus Armbruster BlockAIOCB common; 146e5e51dd3SFam Zheng QEMUTimer timer; 147e819ab22SFam Zheng } NullAIOCB; 148e819ab22SFam Zheng 149e819ab22SFam Zheng static const AIOCBInfo null_aiocb_info = { 150e819ab22SFam Zheng .aiocb_size = sizeof(NullAIOCB), 151e819ab22SFam Zheng }; 152e819ab22SFam Zheng 153e819ab22SFam Zheng static void null_bh_cb(void *opaque) 154e819ab22SFam Zheng { 155e819ab22SFam Zheng NullAIOCB *acb = opaque; 156e819ab22SFam Zheng acb->common.cb(acb->common.opaque, 0); 157e819ab22SFam Zheng qemu_aio_unref(acb); 158e819ab22SFam Zheng } 159e819ab22SFam Zheng 160e5e51dd3SFam Zheng static void null_timer_cb(void *opaque) 161e5e51dd3SFam Zheng { 162e5e51dd3SFam Zheng NullAIOCB *acb = opaque; 163e5e51dd3SFam Zheng acb->common.cb(acb->common.opaque, 0); 164e5e51dd3SFam Zheng timer_deinit(&acb->timer); 165e5e51dd3SFam Zheng qemu_aio_unref(acb); 166e5e51dd3SFam Zheng } 167e5e51dd3SFam Zheng 1687c84b1b8SMarkus Armbruster static inline BlockAIOCB *null_aio_common(BlockDriverState *bs, 169097310b5SMarkus Armbruster BlockCompletionFunc *cb, 170e819ab22SFam Zheng void *opaque) 171e819ab22SFam Zheng { 172e819ab22SFam Zheng NullAIOCB *acb; 173e5e51dd3SFam Zheng BDRVNullState *s = bs->opaque; 174e819ab22SFam Zheng 175e819ab22SFam Zheng acb = qemu_aio_get(&null_aiocb_info, bs, cb, opaque); 176e5e51dd3SFam Zheng /* Only emulate latency after vcpu is running. */ 177e5e51dd3SFam Zheng if (s->latency_ns) { 178e5e51dd3SFam Zheng aio_timer_init(bdrv_get_aio_context(bs), &acb->timer, 179e5e51dd3SFam Zheng QEMU_CLOCK_REALTIME, SCALE_NS, 180e5e51dd3SFam Zheng null_timer_cb, acb); 181e5e51dd3SFam Zheng timer_mod_ns(&acb->timer, 182e5e51dd3SFam Zheng qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + s->latency_ns); 183e5e51dd3SFam Zheng } else { 184e4ec5ad4SPavel Dovgalyuk replay_bh_schedule_oneshot_event(bdrv_get_aio_context(bs), 185e4ec5ad4SPavel Dovgalyuk null_bh_cb, acb); 186e5e51dd3SFam Zheng } 187e819ab22SFam Zheng return &acb->common; 188e819ab22SFam Zheng } 189e819ab22SFam Zheng 190b3241e92SEric Blake static BlockAIOCB *null_aio_preadv(BlockDriverState *bs, 191*f7ef38ddSVladimir Sementsov-Ogievskiy int64_t offset, int64_t bytes, 192*f7ef38ddSVladimir Sementsov-Ogievskiy QEMUIOVector *qiov, BdrvRequestFlags flags, 193097310b5SMarkus Armbruster BlockCompletionFunc *cb, 194e819ab22SFam Zheng void *opaque) 195e819ab22SFam Zheng { 196cd219eb1SMax Reitz BDRVNullState *s = bs->opaque; 197cd219eb1SMax Reitz 198cd219eb1SMax Reitz if (s->read_zeroes) { 199b3241e92SEric Blake qemu_iovec_memset(qiov, 0, 0, bytes); 200cd219eb1SMax Reitz } 201cd219eb1SMax Reitz 202e819ab22SFam Zheng return null_aio_common(bs, cb, opaque); 203e819ab22SFam Zheng } 204e819ab22SFam Zheng 205b3241e92SEric Blake static BlockAIOCB *null_aio_pwritev(BlockDriverState *bs, 206b3241e92SEric Blake uint64_t offset, uint64_t bytes, 207b3241e92SEric Blake QEMUIOVector *qiov, int flags, 208097310b5SMarkus Armbruster BlockCompletionFunc *cb, 209e819ab22SFam Zheng void *opaque) 210e819ab22SFam Zheng { 211e819ab22SFam Zheng return null_aio_common(bs, cb, opaque); 212e819ab22SFam Zheng } 213e819ab22SFam Zheng 2147c84b1b8SMarkus Armbruster static BlockAIOCB *null_aio_flush(BlockDriverState *bs, 215097310b5SMarkus Armbruster BlockCompletionFunc *cb, 216e819ab22SFam Zheng void *opaque) 217e819ab22SFam Zheng { 218e819ab22SFam Zheng return null_aio_common(bs, cb, opaque); 219e819ab22SFam Zheng } 220e819ab22SFam Zheng 2211c2b49a1SFam Zheng static int null_reopen_prepare(BDRVReopenState *reopen_state, 2221c2b49a1SFam Zheng BlockReopenQueue *queue, Error **errp) 2231c2b49a1SFam Zheng { 2241c2b49a1SFam Zheng return 0; 2251c2b49a1SFam Zheng } 2261c2b49a1SFam Zheng 22705c33f10SEric Blake static int coroutine_fn null_co_block_status(BlockDriverState *bs, 22805c33f10SEric Blake bool want_zero, int64_t offset, 22905c33f10SEric Blake int64_t bytes, int64_t *pnum, 23005c33f10SEric Blake int64_t *map, 231a9063927SMax Reitz BlockDriverState **file) 232a9063927SMax Reitz { 233a9063927SMax Reitz BDRVNullState *s = bs->opaque; 23405c33f10SEric Blake int ret = BDRV_BLOCK_OFFSET_VALID; 235a9063927SMax Reitz 23605c33f10SEric Blake *pnum = bytes; 23705c33f10SEric Blake *map = offset; 238a9063927SMax Reitz *file = bs; 239a9063927SMax Reitz 240a9063927SMax Reitz if (s->read_zeroes) { 24105c33f10SEric Blake ret |= BDRV_BLOCK_ZERO; 242a9063927SMax Reitz } 24305c33f10SEric Blake return ret; 244a9063927SMax Reitz } 245a9063927SMax Reitz 246998b3a1eSMax Reitz static void null_refresh_filename(BlockDriverState *bs) 24767882b15SMax Reitz { 248998b3a1eSMax Reitz const QDictEntry *e; 24967882b15SMax Reitz 250998b3a1eSMax Reitz for (e = qdict_first(bs->full_open_options); e; 251998b3a1eSMax Reitz e = qdict_next(bs->full_open_options, e)) 252998b3a1eSMax Reitz { 253998b3a1eSMax Reitz /* These options can be ignored */ 254998b3a1eSMax Reitz if (strcmp(qdict_entry_key(e), "filename") && 2551e47cb7fSMax Reitz strcmp(qdict_entry_key(e), "driver") && 2561e47cb7fSMax Reitz strcmp(qdict_entry_key(e), NULL_OPT_LATENCY)) 257998b3a1eSMax Reitz { 258998b3a1eSMax Reitz return; 259998b3a1eSMax Reitz } 26067882b15SMax Reitz } 26167882b15SMax Reitz 262998b3a1eSMax Reitz snprintf(bs->exact_filename, sizeof(bs->exact_filename), "%s://", 263998b3a1eSMax Reitz bs->drv->format_name); 26467882b15SMax Reitz } 26567882b15SMax Reitz 26607cd7b65SMax Reitz static int64_t null_allocated_file_size(BlockDriverState *bs) 26707cd7b65SMax Reitz { 26807cd7b65SMax Reitz return 0; 26907cd7b65SMax Reitz } 27007cd7b65SMax Reitz 2712654267cSMax Reitz static const char *const null_strong_runtime_opts[] = { 2722654267cSMax Reitz BLOCK_OPT_SIZE, 2732654267cSMax Reitz NULL_OPT_ZEROES, 2742654267cSMax Reitz 2752654267cSMax Reitz NULL 2762654267cSMax Reitz }; 2772654267cSMax Reitz 278e819ab22SFam Zheng static BlockDriver bdrv_null_co = { 279e819ab22SFam Zheng .format_name = "null-co", 280e819ab22SFam Zheng .protocol_name = "null-co", 281e819ab22SFam Zheng .instance_size = sizeof(BDRVNullState), 282e819ab22SFam Zheng 283e819ab22SFam Zheng .bdrv_file_open = null_file_open, 284809eb70eSKevin Wolf .bdrv_parse_filename = null_co_parse_filename, 285e819ab22SFam Zheng .bdrv_getlength = null_getlength, 28607cd7b65SMax Reitz .bdrv_get_allocated_file_size = null_allocated_file_size, 287e819ab22SFam Zheng 288b3241e92SEric Blake .bdrv_co_preadv = null_co_preadv, 289b3241e92SEric Blake .bdrv_co_pwritev = null_co_pwritev, 290e819ab22SFam Zheng .bdrv_co_flush_to_disk = null_co_flush, 2911c2b49a1SFam Zheng .bdrv_reopen_prepare = null_reopen_prepare, 292a9063927SMax Reitz 29305c33f10SEric Blake .bdrv_co_block_status = null_co_block_status, 29467882b15SMax Reitz 29567882b15SMax Reitz .bdrv_refresh_filename = null_refresh_filename, 2962654267cSMax Reitz .strong_runtime_opts = null_strong_runtime_opts, 297e819ab22SFam Zheng }; 298e819ab22SFam Zheng 299e819ab22SFam Zheng static BlockDriver bdrv_null_aio = { 300e819ab22SFam Zheng .format_name = "null-aio", 301e819ab22SFam Zheng .protocol_name = "null-aio", 302e819ab22SFam Zheng .instance_size = sizeof(BDRVNullState), 303e819ab22SFam Zheng 304e819ab22SFam Zheng .bdrv_file_open = null_file_open, 305809eb70eSKevin Wolf .bdrv_parse_filename = null_aio_parse_filename, 306e819ab22SFam Zheng .bdrv_getlength = null_getlength, 30707cd7b65SMax Reitz .bdrv_get_allocated_file_size = null_allocated_file_size, 308e819ab22SFam Zheng 309b3241e92SEric Blake .bdrv_aio_preadv = null_aio_preadv, 310b3241e92SEric Blake .bdrv_aio_pwritev = null_aio_pwritev, 311e819ab22SFam Zheng .bdrv_aio_flush = null_aio_flush, 3121c2b49a1SFam Zheng .bdrv_reopen_prepare = null_reopen_prepare, 313a9063927SMax Reitz 31405c33f10SEric Blake .bdrv_co_block_status = null_co_block_status, 31567882b15SMax Reitz 31667882b15SMax Reitz .bdrv_refresh_filename = null_refresh_filename, 3172654267cSMax Reitz .strong_runtime_opts = null_strong_runtime_opts, 318e819ab22SFam Zheng }; 319e819ab22SFam Zheng 320e819ab22SFam Zheng static void bdrv_null_init(void) 321e819ab22SFam Zheng { 322e819ab22SFam Zheng bdrv_register(&bdrv_null_co); 323e819ab22SFam Zheng bdrv_register(&bdrv_null_aio); 324e819ab22SFam Zheng } 325e819ab22SFam Zheng 326e819ab22SFam Zheng block_init(bdrv_null_init); 327