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" 17*922a01a0SMarkus Armbruster #include "qemu/option.h" 18e819ab22SFam Zheng #include "block/block_int.h" 19e819ab22SFam Zheng 20e5e51dd3SFam Zheng #define NULL_OPT_LATENCY "latency-ns" 21cd219eb1SMax Reitz #define NULL_OPT_ZEROES "read-zeroes" 22e5e51dd3SFam Zheng 23e819ab22SFam Zheng typedef struct { 24e819ab22SFam Zheng int64_t length; 25e5e51dd3SFam Zheng int64_t latency_ns; 26cd219eb1SMax Reitz bool read_zeroes; 27e819ab22SFam Zheng } BDRVNullState; 28e819ab22SFam Zheng 29e819ab22SFam Zheng static QemuOptsList runtime_opts = { 30e819ab22SFam Zheng .name = "null", 31e819ab22SFam Zheng .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head), 32e819ab22SFam Zheng .desc = { 33e819ab22SFam Zheng { 34e819ab22SFam Zheng .name = BLOCK_OPT_SIZE, 35e819ab22SFam Zheng .type = QEMU_OPT_SIZE, 36e819ab22SFam Zheng .help = "size of the null block", 37e819ab22SFam Zheng }, 38e5e51dd3SFam Zheng { 39e5e51dd3SFam Zheng .name = NULL_OPT_LATENCY, 40e5e51dd3SFam Zheng .type = QEMU_OPT_NUMBER, 41e5e51dd3SFam Zheng .help = "nanoseconds (approximated) to wait " 42e5e51dd3SFam Zheng "before completing request", 43e5e51dd3SFam Zheng }, 44cd219eb1SMax Reitz { 45cd219eb1SMax Reitz .name = NULL_OPT_ZEROES, 46cd219eb1SMax Reitz .type = QEMU_OPT_BOOL, 47cd219eb1SMax Reitz .help = "return zeroes when read", 48cd219eb1SMax Reitz }, 49e819ab22SFam Zheng { /* end of list */ } 50e819ab22SFam Zheng }, 51e819ab22SFam Zheng }; 52e819ab22SFam Zheng 53809eb70eSKevin Wolf static void null_co_parse_filename(const char *filename, QDict *options, 54809eb70eSKevin Wolf Error **errp) 55809eb70eSKevin Wolf { 56809eb70eSKevin Wolf /* This functions only exists so that a null-co:// filename is accepted 57809eb70eSKevin Wolf * with the null-co driver. */ 58809eb70eSKevin Wolf if (strcmp(filename, "null-co://")) { 59809eb70eSKevin Wolf error_setg(errp, "The only allowed filename for this driver is " 60809eb70eSKevin Wolf "'null-co://'"); 61809eb70eSKevin Wolf return; 62809eb70eSKevin Wolf } 63809eb70eSKevin Wolf } 64809eb70eSKevin Wolf 65809eb70eSKevin Wolf static void null_aio_parse_filename(const char *filename, QDict *options, 66809eb70eSKevin Wolf Error **errp) 67809eb70eSKevin Wolf { 68809eb70eSKevin Wolf /* This functions only exists so that a null-aio:// filename is accepted 69809eb70eSKevin Wolf * with the null-aio driver. */ 70809eb70eSKevin Wolf if (strcmp(filename, "null-aio://")) { 71809eb70eSKevin Wolf error_setg(errp, "The only allowed filename for this driver is " 72809eb70eSKevin Wolf "'null-aio://'"); 73809eb70eSKevin Wolf return; 74809eb70eSKevin Wolf } 75809eb70eSKevin Wolf } 76809eb70eSKevin Wolf 77e819ab22SFam Zheng static int null_file_open(BlockDriverState *bs, QDict *options, int flags, 78e819ab22SFam Zheng Error **errp) 79e819ab22SFam Zheng { 80e819ab22SFam Zheng QemuOpts *opts; 81e819ab22SFam Zheng BDRVNullState *s = bs->opaque; 82e5e51dd3SFam Zheng int ret = 0; 83e819ab22SFam Zheng 84e819ab22SFam Zheng opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); 85e819ab22SFam Zheng qemu_opts_absorb_qdict(opts, options, &error_abort); 86e819ab22SFam Zheng s->length = 87e819ab22SFam Zheng qemu_opt_get_size(opts, BLOCK_OPT_SIZE, 1 << 30); 88e5e51dd3SFam Zheng s->latency_ns = 89e5e51dd3SFam Zheng qemu_opt_get_number(opts, NULL_OPT_LATENCY, 0); 90e5e51dd3SFam Zheng if (s->latency_ns < 0) { 91e5e51dd3SFam Zheng error_setg(errp, "latency-ns is invalid"); 92e5e51dd3SFam Zheng ret = -EINVAL; 93e5e51dd3SFam Zheng } 94cd219eb1SMax Reitz s->read_zeroes = qemu_opt_get_bool(opts, NULL_OPT_ZEROES, false); 95e819ab22SFam Zheng qemu_opts_del(opts); 96e5e51dd3SFam Zheng return ret; 97e819ab22SFam Zheng } 98e819ab22SFam Zheng 99e819ab22SFam Zheng static void null_close(BlockDriverState *bs) 100e819ab22SFam Zheng { 101e819ab22SFam Zheng } 102e819ab22SFam Zheng 103e819ab22SFam Zheng static int64_t null_getlength(BlockDriverState *bs) 104e819ab22SFam Zheng { 105e819ab22SFam Zheng BDRVNullState *s = bs->opaque; 106e819ab22SFam Zheng return s->length; 107e819ab22SFam Zheng } 108e819ab22SFam Zheng 109e5e51dd3SFam Zheng static coroutine_fn int null_co_common(BlockDriverState *bs) 110e5e51dd3SFam Zheng { 111e5e51dd3SFam Zheng BDRVNullState *s = bs->opaque; 112e5e51dd3SFam Zheng 113e5e51dd3SFam Zheng if (s->latency_ns) { 11478f1d3d6SStefan Hajnoczi qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, s->latency_ns); 115e5e51dd3SFam Zheng } 116e5e51dd3SFam Zheng return 0; 117e5e51dd3SFam Zheng } 118e5e51dd3SFam Zheng 119e819ab22SFam Zheng static coroutine_fn int null_co_readv(BlockDriverState *bs, 120e819ab22SFam Zheng int64_t sector_num, int nb_sectors, 121e819ab22SFam Zheng QEMUIOVector *qiov) 122e819ab22SFam Zheng { 123cd219eb1SMax Reitz BDRVNullState *s = bs->opaque; 124cd219eb1SMax Reitz 125cd219eb1SMax Reitz if (s->read_zeroes) { 126cd219eb1SMax Reitz qemu_iovec_memset(qiov, 0, 0, nb_sectors * BDRV_SECTOR_SIZE); 127cd219eb1SMax Reitz } 128cd219eb1SMax Reitz 129e5e51dd3SFam Zheng return null_co_common(bs); 130e819ab22SFam Zheng } 131e819ab22SFam Zheng 132e819ab22SFam Zheng static coroutine_fn int null_co_writev(BlockDriverState *bs, 133e819ab22SFam Zheng int64_t sector_num, int nb_sectors, 134e819ab22SFam Zheng QEMUIOVector *qiov) 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 { 184fffb6e12SPaolo Bonzini aio_bh_schedule_oneshot(bdrv_get_aio_context(bs), null_bh_cb, acb); 185e5e51dd3SFam Zheng } 186e819ab22SFam Zheng return &acb->common; 187e819ab22SFam Zheng } 188e819ab22SFam Zheng 1897c84b1b8SMarkus Armbruster static BlockAIOCB *null_aio_readv(BlockDriverState *bs, 190e819ab22SFam Zheng int64_t sector_num, QEMUIOVector *qiov, 191e819ab22SFam Zheng int nb_sectors, 192097310b5SMarkus Armbruster BlockCompletionFunc *cb, 193e819ab22SFam Zheng void *opaque) 194e819ab22SFam Zheng { 195cd219eb1SMax Reitz BDRVNullState *s = bs->opaque; 196cd219eb1SMax Reitz 197cd219eb1SMax Reitz if (s->read_zeroes) { 198cd219eb1SMax Reitz qemu_iovec_memset(qiov, 0, 0, nb_sectors * BDRV_SECTOR_SIZE); 199cd219eb1SMax Reitz } 200cd219eb1SMax Reitz 201e819ab22SFam Zheng return null_aio_common(bs, cb, opaque); 202e819ab22SFam Zheng } 203e819ab22SFam Zheng 2047c84b1b8SMarkus Armbruster static BlockAIOCB *null_aio_writev(BlockDriverState *bs, 205e819ab22SFam Zheng int64_t sector_num, QEMUIOVector *qiov, 206e819ab22SFam Zheng int nb_sectors, 207097310b5SMarkus Armbruster BlockCompletionFunc *cb, 208e819ab22SFam Zheng void *opaque) 209e819ab22SFam Zheng { 210e819ab22SFam Zheng return null_aio_common(bs, cb, opaque); 211e819ab22SFam Zheng } 212e819ab22SFam Zheng 2137c84b1b8SMarkus Armbruster static BlockAIOCB *null_aio_flush(BlockDriverState *bs, 214097310b5SMarkus Armbruster BlockCompletionFunc *cb, 215e819ab22SFam Zheng void *opaque) 216e819ab22SFam Zheng { 217e819ab22SFam Zheng return null_aio_common(bs, cb, opaque); 218e819ab22SFam Zheng } 219e819ab22SFam Zheng 2201c2b49a1SFam Zheng static int null_reopen_prepare(BDRVReopenState *reopen_state, 2211c2b49a1SFam Zheng BlockReopenQueue *queue, Error **errp) 2221c2b49a1SFam Zheng { 2231c2b49a1SFam Zheng return 0; 2241c2b49a1SFam Zheng } 2251c2b49a1SFam Zheng 226a9063927SMax Reitz static int64_t coroutine_fn null_co_get_block_status(BlockDriverState *bs, 227a9063927SMax Reitz int64_t sector_num, 228a9063927SMax Reitz int nb_sectors, int *pnum, 229a9063927SMax Reitz BlockDriverState **file) 230a9063927SMax Reitz { 231a9063927SMax Reitz BDRVNullState *s = bs->opaque; 232a9063927SMax Reitz off_t start = sector_num * BDRV_SECTOR_SIZE; 233a9063927SMax Reitz 234a9063927SMax Reitz *pnum = nb_sectors; 235a9063927SMax Reitz *file = bs; 236a9063927SMax Reitz 237a9063927SMax Reitz if (s->read_zeroes) { 238a9063927SMax Reitz return BDRV_BLOCK_OFFSET_VALID | start | BDRV_BLOCK_ZERO; 239a9063927SMax Reitz } else { 240a9063927SMax Reitz return BDRV_BLOCK_OFFSET_VALID | start; 241a9063927SMax Reitz } 242a9063927SMax Reitz } 243a9063927SMax Reitz 24467882b15SMax Reitz static void null_refresh_filename(BlockDriverState *bs, QDict *opts) 24567882b15SMax Reitz { 24667882b15SMax Reitz QINCREF(opts); 24767882b15SMax Reitz qdict_del(opts, "filename"); 24867882b15SMax Reitz 24967882b15SMax Reitz if (!qdict_size(opts)) { 25067882b15SMax Reitz snprintf(bs->exact_filename, sizeof(bs->exact_filename), "%s://", 25167882b15SMax Reitz bs->drv->format_name); 25267882b15SMax Reitz } 25367882b15SMax Reitz 25446f5ac20SEric Blake qdict_put_str(opts, "driver", bs->drv->format_name); 25567882b15SMax Reitz bs->full_open_options = opts; 25667882b15SMax Reitz } 25767882b15SMax Reitz 258e819ab22SFam Zheng static BlockDriver bdrv_null_co = { 259e819ab22SFam Zheng .format_name = "null-co", 260e819ab22SFam Zheng .protocol_name = "null-co", 261e819ab22SFam Zheng .instance_size = sizeof(BDRVNullState), 262e819ab22SFam Zheng 263e819ab22SFam Zheng .bdrv_file_open = null_file_open, 264809eb70eSKevin Wolf .bdrv_parse_filename = null_co_parse_filename, 265e819ab22SFam Zheng .bdrv_close = null_close, 266e819ab22SFam Zheng .bdrv_getlength = null_getlength, 267e819ab22SFam Zheng 268e819ab22SFam Zheng .bdrv_co_readv = null_co_readv, 269e819ab22SFam Zheng .bdrv_co_writev = null_co_writev, 270e819ab22SFam Zheng .bdrv_co_flush_to_disk = null_co_flush, 2711c2b49a1SFam Zheng .bdrv_reopen_prepare = null_reopen_prepare, 272a9063927SMax Reitz 273a9063927SMax Reitz .bdrv_co_get_block_status = null_co_get_block_status, 27467882b15SMax Reitz 27567882b15SMax Reitz .bdrv_refresh_filename = null_refresh_filename, 276e819ab22SFam Zheng }; 277e819ab22SFam Zheng 278e819ab22SFam Zheng static BlockDriver bdrv_null_aio = { 279e819ab22SFam Zheng .format_name = "null-aio", 280e819ab22SFam Zheng .protocol_name = "null-aio", 281e819ab22SFam Zheng .instance_size = sizeof(BDRVNullState), 282e819ab22SFam Zheng 283e819ab22SFam Zheng .bdrv_file_open = null_file_open, 284809eb70eSKevin Wolf .bdrv_parse_filename = null_aio_parse_filename, 285e819ab22SFam Zheng .bdrv_close = null_close, 286e819ab22SFam Zheng .bdrv_getlength = null_getlength, 287e819ab22SFam Zheng 288e819ab22SFam Zheng .bdrv_aio_readv = null_aio_readv, 289e819ab22SFam Zheng .bdrv_aio_writev = null_aio_writev, 290e819ab22SFam Zheng .bdrv_aio_flush = null_aio_flush, 2911c2b49a1SFam Zheng .bdrv_reopen_prepare = null_reopen_prepare, 292a9063927SMax Reitz 293a9063927SMax Reitz .bdrv_co_get_block_status = null_co_get_block_status, 29467882b15SMax Reitz 29567882b15SMax Reitz .bdrv_refresh_filename = null_refresh_filename, 296e819ab22SFam Zheng }; 297e819ab22SFam Zheng 298e819ab22SFam Zheng static void bdrv_null_init(void) 299e819ab22SFam Zheng { 300e819ab22SFam Zheng bdrv_register(&bdrv_null_co); 301e819ab22SFam Zheng bdrv_register(&bdrv_null_aio); 302e819ab22SFam Zheng } 303e819ab22SFam Zheng 304e819ab22SFam Zheng block_init(bdrv_null_init); 305