xref: /qemu/block/null.c (revision cd219eb1e55a5bf9eab4193cafaf6ab188fc2752)
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