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