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"
19e2c1c34fSMarkus Armbruster #include "block/block-io.h"
20e819ab22SFam Zheng #include "block/block_int.h"
21e4ec5ad4SPavel Dovgalyuk #include "sysemu/replay.h"
22e819ab22SFam Zheng
23e5e51dd3SFam Zheng #define NULL_OPT_LATENCY "latency-ns"
24cd219eb1SMax Reitz #define NULL_OPT_ZEROES "read-zeroes"
25e5e51dd3SFam Zheng
26e819ab22SFam Zheng typedef struct {
27e819ab22SFam Zheng int64_t length;
28e5e51dd3SFam Zheng int64_t latency_ns;
29cd219eb1SMax Reitz bool read_zeroes;
30e819ab22SFam Zheng } BDRVNullState;
31e819ab22SFam Zheng
32e819ab22SFam Zheng static QemuOptsList runtime_opts = {
33e819ab22SFam Zheng .name = "null",
34e819ab22SFam Zheng .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
35e819ab22SFam Zheng .desc = {
36e819ab22SFam Zheng {
37e819ab22SFam Zheng .name = BLOCK_OPT_SIZE,
38e819ab22SFam Zheng .type = QEMU_OPT_SIZE,
39e819ab22SFam Zheng .help = "size of the null block",
40e819ab22SFam Zheng },
41e5e51dd3SFam Zheng {
42e5e51dd3SFam Zheng .name = NULL_OPT_LATENCY,
43e5e51dd3SFam Zheng .type = QEMU_OPT_NUMBER,
44e5e51dd3SFam Zheng .help = "nanoseconds (approximated) to wait "
45e5e51dd3SFam Zheng "before completing request",
46e5e51dd3SFam Zheng },
47cd219eb1SMax Reitz {
48cd219eb1SMax Reitz .name = NULL_OPT_ZEROES,
49cd219eb1SMax Reitz .type = QEMU_OPT_BOOL,
50cd219eb1SMax Reitz .help = "return zeroes when read",
51cd219eb1SMax Reitz },
52e819ab22SFam Zheng { /* end of list */ }
53e819ab22SFam Zheng },
54e819ab22SFam Zheng };
55e819ab22SFam Zheng
null_co_parse_filename(const char * filename,QDict * options,Error ** errp)56809eb70eSKevin Wolf static void null_co_parse_filename(const char *filename, QDict *options,
57809eb70eSKevin Wolf Error **errp)
58809eb70eSKevin Wolf {
59809eb70eSKevin Wolf /* This functions only exists so that a null-co:// filename is accepted
60809eb70eSKevin Wolf * with the null-co driver. */
61809eb70eSKevin Wolf if (strcmp(filename, "null-co://")) {
62809eb70eSKevin Wolf error_setg(errp, "The only allowed filename for this driver is "
63809eb70eSKevin Wolf "'null-co://'");
64809eb70eSKevin Wolf return;
65809eb70eSKevin Wolf }
66809eb70eSKevin Wolf }
67809eb70eSKevin Wolf
null_aio_parse_filename(const char * filename,QDict * options,Error ** errp)68809eb70eSKevin Wolf static void null_aio_parse_filename(const char *filename, QDict *options,
69809eb70eSKevin Wolf Error **errp)
70809eb70eSKevin Wolf {
71809eb70eSKevin Wolf /* This functions only exists so that a null-aio:// filename is accepted
72809eb70eSKevin Wolf * with the null-aio driver. */
73809eb70eSKevin Wolf if (strcmp(filename, "null-aio://")) {
74809eb70eSKevin Wolf error_setg(errp, "The only allowed filename for this driver is "
75809eb70eSKevin Wolf "'null-aio://'");
76809eb70eSKevin Wolf return;
77809eb70eSKevin Wolf }
78809eb70eSKevin Wolf }
79809eb70eSKevin Wolf
null_open(BlockDriverState * bs,QDict * options,int flags,Error ** errp)80*d656aaa1SPaolo Bonzini static int null_open(BlockDriverState *bs, QDict *options, int flags,
81e819ab22SFam Zheng Error **errp)
82e819ab22SFam Zheng {
83e819ab22SFam Zheng QemuOpts *opts;
84e819ab22SFam Zheng BDRVNullState *s = bs->opaque;
85e5e51dd3SFam Zheng int ret = 0;
86e819ab22SFam Zheng
87e819ab22SFam Zheng opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
88e819ab22SFam Zheng qemu_opts_absorb_qdict(opts, options, &error_abort);
89e819ab22SFam Zheng s->length =
90e819ab22SFam Zheng qemu_opt_get_size(opts, BLOCK_OPT_SIZE, 1 << 30);
91e5e51dd3SFam Zheng s->latency_ns =
92e5e51dd3SFam Zheng qemu_opt_get_number(opts, NULL_OPT_LATENCY, 0);
93e5e51dd3SFam Zheng if (s->latency_ns < 0) {
94e5e51dd3SFam Zheng error_setg(errp, "latency-ns is invalid");
95e5e51dd3SFam Zheng ret = -EINVAL;
96e5e51dd3SFam Zheng }
97cd219eb1SMax Reitz s->read_zeroes = qemu_opt_get_bool(opts, NULL_OPT_ZEROES, false);
98e819ab22SFam Zheng qemu_opts_del(opts);
99b3241e92SEric Blake bs->supported_write_flags = BDRV_REQ_FUA;
100e5e51dd3SFam Zheng return ret;
101e819ab22SFam Zheng }
102e819ab22SFam Zheng
null_co_getlength(BlockDriverState * bs)103c86422c5SEmanuele Giuseppe Esposito static int64_t coroutine_fn null_co_getlength(BlockDriverState *bs)
104e819ab22SFam Zheng {
105e819ab22SFam Zheng BDRVNullState *s = bs->opaque;
106e819ab22SFam Zheng return s->length;
107e819ab22SFam Zheng }
108e819ab22SFam Zheng
null_co_common(BlockDriverState * bs)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
null_co_preadv(BlockDriverState * bs,int64_t offset,int64_t bytes,QEMUIOVector * qiov,BdrvRequestFlags flags)119b3241e92SEric Blake static coroutine_fn int null_co_preadv(BlockDriverState *bs,
120f7ef38ddSVladimir Sementsov-Ogievskiy int64_t offset, int64_t bytes,
121f7ef38ddSVladimir Sementsov-Ogievskiy QEMUIOVector *qiov,
122f7ef38ddSVladimir Sementsov-Ogievskiy BdrvRequestFlags flags)
123e819ab22SFam Zheng {
124cd219eb1SMax Reitz BDRVNullState *s = bs->opaque;
125cd219eb1SMax Reitz
126cd219eb1SMax Reitz if (s->read_zeroes) {
127b3241e92SEric Blake qemu_iovec_memset(qiov, 0, 0, bytes);
128cd219eb1SMax Reitz }
129cd219eb1SMax Reitz
130e5e51dd3SFam Zheng return null_co_common(bs);
131e819ab22SFam Zheng }
132e819ab22SFam Zheng
null_co_pwritev(BlockDriverState * bs,int64_t offset,int64_t bytes,QEMUIOVector * qiov,BdrvRequestFlags flags)133b3241e92SEric Blake static coroutine_fn int null_co_pwritev(BlockDriverState *bs,
134e75abedaSVladimir Sementsov-Ogievskiy int64_t offset, int64_t bytes,
135e75abedaSVladimir Sementsov-Ogievskiy QEMUIOVector *qiov,
136e75abedaSVladimir Sementsov-Ogievskiy BdrvRequestFlags flags)
137e819ab22SFam Zheng {
138e5e51dd3SFam Zheng return null_co_common(bs);
139e819ab22SFam Zheng }
140e819ab22SFam Zheng
null_co_flush(BlockDriverState * bs)141e819ab22SFam Zheng static coroutine_fn int null_co_flush(BlockDriverState *bs)
142e819ab22SFam Zheng {
143e5e51dd3SFam Zheng return null_co_common(bs);
144e819ab22SFam Zheng }
145e819ab22SFam Zheng
146e819ab22SFam Zheng typedef struct {
1477c84b1b8SMarkus Armbruster BlockAIOCB common;
148e5e51dd3SFam Zheng QEMUTimer timer;
149e819ab22SFam Zheng } NullAIOCB;
150e819ab22SFam Zheng
151e819ab22SFam Zheng static const AIOCBInfo null_aiocb_info = {
152e819ab22SFam Zheng .aiocb_size = sizeof(NullAIOCB),
153e819ab22SFam Zheng };
154e819ab22SFam Zheng
null_bh_cb(void * opaque)155e819ab22SFam Zheng static void null_bh_cb(void *opaque)
156e819ab22SFam Zheng {
157e819ab22SFam Zheng NullAIOCB *acb = opaque;
158e819ab22SFam Zheng acb->common.cb(acb->common.opaque, 0);
159e819ab22SFam Zheng qemu_aio_unref(acb);
160e819ab22SFam Zheng }
161e819ab22SFam Zheng
null_timer_cb(void * opaque)162e5e51dd3SFam Zheng static void null_timer_cb(void *opaque)
163e5e51dd3SFam Zheng {
164e5e51dd3SFam Zheng NullAIOCB *acb = opaque;
165e5e51dd3SFam Zheng acb->common.cb(acb->common.opaque, 0);
166e5e51dd3SFam Zheng timer_deinit(&acb->timer);
167e5e51dd3SFam Zheng qemu_aio_unref(acb);
168e5e51dd3SFam Zheng }
169e5e51dd3SFam Zheng
null_aio_common(BlockDriverState * bs,BlockCompletionFunc * cb,void * opaque)1707c84b1b8SMarkus Armbruster static inline BlockAIOCB *null_aio_common(BlockDriverState *bs,
171097310b5SMarkus Armbruster BlockCompletionFunc *cb,
172e819ab22SFam Zheng void *opaque)
173e819ab22SFam Zheng {
174e819ab22SFam Zheng NullAIOCB *acb;
175e5e51dd3SFam Zheng BDRVNullState *s = bs->opaque;
176e819ab22SFam Zheng
177e819ab22SFam Zheng acb = qemu_aio_get(&null_aiocb_info, bs, cb, opaque);
178e5e51dd3SFam Zheng /* Only emulate latency after vcpu is running. */
179e5e51dd3SFam Zheng if (s->latency_ns) {
180e5e51dd3SFam Zheng aio_timer_init(bdrv_get_aio_context(bs), &acb->timer,
181e5e51dd3SFam Zheng QEMU_CLOCK_REALTIME, SCALE_NS,
182e5e51dd3SFam Zheng null_timer_cb, acb);
183e5e51dd3SFam Zheng timer_mod_ns(&acb->timer,
184e5e51dd3SFam Zheng qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + s->latency_ns);
185e5e51dd3SFam Zheng } else {
186e4ec5ad4SPavel Dovgalyuk replay_bh_schedule_oneshot_event(bdrv_get_aio_context(bs),
187e4ec5ad4SPavel Dovgalyuk null_bh_cb, acb);
188e5e51dd3SFam Zheng }
189e819ab22SFam Zheng return &acb->common;
190e819ab22SFam Zheng }
191e819ab22SFam Zheng
null_aio_preadv(BlockDriverState * bs,int64_t offset,int64_t bytes,QEMUIOVector * qiov,BdrvRequestFlags flags,BlockCompletionFunc * cb,void * opaque)192b3241e92SEric Blake static BlockAIOCB *null_aio_preadv(BlockDriverState *bs,
193f7ef38ddSVladimir Sementsov-Ogievskiy int64_t offset, int64_t bytes,
194f7ef38ddSVladimir Sementsov-Ogievskiy QEMUIOVector *qiov, BdrvRequestFlags flags,
195097310b5SMarkus Armbruster BlockCompletionFunc *cb,
196e819ab22SFam Zheng void *opaque)
197e819ab22SFam Zheng {
198cd219eb1SMax Reitz BDRVNullState *s = bs->opaque;
199cd219eb1SMax Reitz
200cd219eb1SMax Reitz if (s->read_zeroes) {
201b3241e92SEric Blake qemu_iovec_memset(qiov, 0, 0, bytes);
202cd219eb1SMax Reitz }
203cd219eb1SMax Reitz
204e819ab22SFam Zheng return null_aio_common(bs, cb, opaque);
205e819ab22SFam Zheng }
206e819ab22SFam Zheng
null_aio_pwritev(BlockDriverState * bs,int64_t offset,int64_t bytes,QEMUIOVector * qiov,BdrvRequestFlags flags,BlockCompletionFunc * cb,void * opaque)207b3241e92SEric Blake static BlockAIOCB *null_aio_pwritev(BlockDriverState *bs,
208e75abedaSVladimir Sementsov-Ogievskiy int64_t offset, int64_t bytes,
209e75abedaSVladimir Sementsov-Ogievskiy QEMUIOVector *qiov, BdrvRequestFlags flags,
210097310b5SMarkus Armbruster BlockCompletionFunc *cb,
211e819ab22SFam Zheng void *opaque)
212e819ab22SFam Zheng {
213e819ab22SFam Zheng return null_aio_common(bs, cb, opaque);
214e819ab22SFam Zheng }
215e819ab22SFam Zheng
null_aio_flush(BlockDriverState * bs,BlockCompletionFunc * cb,void * opaque)2167c84b1b8SMarkus Armbruster static BlockAIOCB *null_aio_flush(BlockDriverState *bs,
217097310b5SMarkus Armbruster BlockCompletionFunc *cb,
218e819ab22SFam Zheng void *opaque)
219e819ab22SFam Zheng {
220e819ab22SFam Zheng return null_aio_common(bs, cb, opaque);
221e819ab22SFam Zheng }
222e819ab22SFam Zheng
null_reopen_prepare(BDRVReopenState * reopen_state,BlockReopenQueue * queue,Error ** errp)2231c2b49a1SFam Zheng static int null_reopen_prepare(BDRVReopenState *reopen_state,
2241c2b49a1SFam Zheng BlockReopenQueue *queue, Error **errp)
2251c2b49a1SFam Zheng {
2261c2b49a1SFam Zheng return 0;
2271c2b49a1SFam Zheng }
2281c2b49a1SFam Zheng
null_co_block_status(BlockDriverState * bs,bool want_zero,int64_t offset,int64_t bytes,int64_t * pnum,int64_t * map,BlockDriverState ** file)22905c33f10SEric Blake static int coroutine_fn null_co_block_status(BlockDriverState *bs,
23005c33f10SEric Blake bool want_zero, int64_t offset,
23105c33f10SEric Blake int64_t bytes, int64_t *pnum,
23205c33f10SEric Blake int64_t *map,
233a9063927SMax Reitz BlockDriverState **file)
234a9063927SMax Reitz {
235a9063927SMax Reitz BDRVNullState *s = bs->opaque;
23605c33f10SEric Blake int ret = BDRV_BLOCK_OFFSET_VALID;
237a9063927SMax Reitz
23805c33f10SEric Blake *pnum = bytes;
23905c33f10SEric Blake *map = offset;
240a9063927SMax Reitz *file = bs;
241a9063927SMax Reitz
242a9063927SMax Reitz if (s->read_zeroes) {
24305c33f10SEric Blake ret |= BDRV_BLOCK_ZERO;
244a9063927SMax Reitz }
24505c33f10SEric Blake return ret;
246a9063927SMax Reitz }
247a9063927SMax Reitz
null_refresh_filename(BlockDriverState * bs)248998b3a1eSMax Reitz static void null_refresh_filename(BlockDriverState *bs)
24967882b15SMax Reitz {
250998b3a1eSMax Reitz const QDictEntry *e;
25167882b15SMax Reitz
252998b3a1eSMax Reitz for (e = qdict_first(bs->full_open_options); e;
253998b3a1eSMax Reitz e = qdict_next(bs->full_open_options, e))
254998b3a1eSMax Reitz {
255998b3a1eSMax Reitz /* These options can be ignored */
256998b3a1eSMax Reitz if (strcmp(qdict_entry_key(e), "filename") &&
2571e47cb7fSMax Reitz strcmp(qdict_entry_key(e), "driver") &&
2581e47cb7fSMax Reitz strcmp(qdict_entry_key(e), NULL_OPT_LATENCY))
259998b3a1eSMax Reitz {
260998b3a1eSMax Reitz return;
261998b3a1eSMax Reitz }
26267882b15SMax Reitz }
26367882b15SMax Reitz
264998b3a1eSMax Reitz snprintf(bs->exact_filename, sizeof(bs->exact_filename), "%s://",
265998b3a1eSMax Reitz bs->drv->format_name);
26667882b15SMax Reitz }
26767882b15SMax Reitz
26882618d7bSEmanuele Giuseppe Esposito static int64_t coroutine_fn
null_co_get_allocated_file_size(BlockDriverState * bs)26982618d7bSEmanuele Giuseppe Esposito null_co_get_allocated_file_size(BlockDriverState *bs)
27007cd7b65SMax Reitz {
27107cd7b65SMax Reitz return 0;
27207cd7b65SMax Reitz }
27307cd7b65SMax Reitz
2742654267cSMax Reitz static const char *const null_strong_runtime_opts[] = {
2752654267cSMax Reitz BLOCK_OPT_SIZE,
2762654267cSMax Reitz NULL_OPT_ZEROES,
2772654267cSMax Reitz
2782654267cSMax Reitz NULL
2792654267cSMax Reitz };
2802654267cSMax Reitz
281e819ab22SFam Zheng static BlockDriver bdrv_null_co = {
282e819ab22SFam Zheng .format_name = "null-co",
283e819ab22SFam Zheng .protocol_name = "null-co",
284e819ab22SFam Zheng .instance_size = sizeof(BDRVNullState),
285e819ab22SFam Zheng
286*d656aaa1SPaolo Bonzini .bdrv_open = null_open,
287809eb70eSKevin Wolf .bdrv_parse_filename = null_co_parse_filename,
288c86422c5SEmanuele Giuseppe Esposito .bdrv_co_getlength = null_co_getlength,
28982618d7bSEmanuele Giuseppe Esposito .bdrv_co_get_allocated_file_size = null_co_get_allocated_file_size,
290e819ab22SFam Zheng
291b3241e92SEric Blake .bdrv_co_preadv = null_co_preadv,
292b3241e92SEric Blake .bdrv_co_pwritev = null_co_pwritev,
293e819ab22SFam Zheng .bdrv_co_flush_to_disk = null_co_flush,
2941c2b49a1SFam Zheng .bdrv_reopen_prepare = null_reopen_prepare,
295a9063927SMax Reitz
29605c33f10SEric Blake .bdrv_co_block_status = null_co_block_status,
29767882b15SMax Reitz
29867882b15SMax Reitz .bdrv_refresh_filename = null_refresh_filename,
2992654267cSMax Reitz .strong_runtime_opts = null_strong_runtime_opts,
300e819ab22SFam Zheng };
301e819ab22SFam Zheng
302e819ab22SFam Zheng static BlockDriver bdrv_null_aio = {
303e819ab22SFam Zheng .format_name = "null-aio",
304e819ab22SFam Zheng .protocol_name = "null-aio",
305e819ab22SFam Zheng .instance_size = sizeof(BDRVNullState),
306e819ab22SFam Zheng
307*d656aaa1SPaolo Bonzini .bdrv_open = null_open,
308809eb70eSKevin Wolf .bdrv_parse_filename = null_aio_parse_filename,
309c86422c5SEmanuele Giuseppe Esposito .bdrv_co_getlength = null_co_getlength,
31082618d7bSEmanuele Giuseppe Esposito .bdrv_co_get_allocated_file_size = null_co_get_allocated_file_size,
311e819ab22SFam Zheng
312b3241e92SEric Blake .bdrv_aio_preadv = null_aio_preadv,
313b3241e92SEric Blake .bdrv_aio_pwritev = null_aio_pwritev,
314e819ab22SFam Zheng .bdrv_aio_flush = null_aio_flush,
3151c2b49a1SFam Zheng .bdrv_reopen_prepare = null_reopen_prepare,
316a9063927SMax Reitz
31705c33f10SEric Blake .bdrv_co_block_status = null_co_block_status,
31867882b15SMax Reitz
31967882b15SMax Reitz .bdrv_refresh_filename = null_refresh_filename,
3202654267cSMax Reitz .strong_runtime_opts = null_strong_runtime_opts,
321e819ab22SFam Zheng };
322e819ab22SFam Zheng
bdrv_null_init(void)323e819ab22SFam Zheng static void bdrv_null_init(void)
324e819ab22SFam Zheng {
325e819ab22SFam Zheng bdrv_register(&bdrv_null_co);
326e819ab22SFam Zheng bdrv_register(&bdrv_null_aio);
327e819ab22SFam Zheng }
328e819ab22SFam Zheng
329e819ab22SFam Zheng block_init(bdrv_null_init);
330