xref: /qemu/block/null.c (revision 998b3a1e5a2dd23bf89a853e15fabdaa8d788a72)
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"
17922a01a0SMarkus 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);
96b3241e92SEric Blake     bs->supported_write_flags = BDRV_REQ_FUA;
97e5e51dd3SFam Zheng     return ret;
98e819ab22SFam Zheng }
99e819ab22SFam Zheng 
100e819ab22SFam Zheng static int64_t null_getlength(BlockDriverState *bs)
101e819ab22SFam Zheng {
102e819ab22SFam Zheng     BDRVNullState *s = bs->opaque;
103e819ab22SFam Zheng     return s->length;
104e819ab22SFam Zheng }
105e819ab22SFam Zheng 
106e5e51dd3SFam Zheng static coroutine_fn int null_co_common(BlockDriverState *bs)
107e5e51dd3SFam Zheng {
108e5e51dd3SFam Zheng     BDRVNullState *s = bs->opaque;
109e5e51dd3SFam Zheng 
110e5e51dd3SFam Zheng     if (s->latency_ns) {
11178f1d3d6SStefan Hajnoczi         qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, s->latency_ns);
112e5e51dd3SFam Zheng     }
113e5e51dd3SFam Zheng     return 0;
114e5e51dd3SFam Zheng }
115e5e51dd3SFam Zheng 
116b3241e92SEric Blake static coroutine_fn int null_co_preadv(BlockDriverState *bs,
117b3241e92SEric Blake                                        uint64_t offset, uint64_t bytes,
118b3241e92SEric Blake                                        QEMUIOVector *qiov, int flags)
119e819ab22SFam Zheng {
120cd219eb1SMax Reitz     BDRVNullState *s = bs->opaque;
121cd219eb1SMax Reitz 
122cd219eb1SMax Reitz     if (s->read_zeroes) {
123b3241e92SEric Blake         qemu_iovec_memset(qiov, 0, 0, bytes);
124cd219eb1SMax Reitz     }
125cd219eb1SMax Reitz 
126e5e51dd3SFam Zheng     return null_co_common(bs);
127e819ab22SFam Zheng }
128e819ab22SFam Zheng 
129b3241e92SEric Blake static coroutine_fn int null_co_pwritev(BlockDriverState *bs,
130b3241e92SEric Blake                                         uint64_t offset, uint64_t bytes,
131b3241e92SEric Blake                                         QEMUIOVector *qiov, int flags)
132e819ab22SFam Zheng {
133e5e51dd3SFam Zheng     return null_co_common(bs);
134e819ab22SFam Zheng }
135e819ab22SFam Zheng 
136e819ab22SFam Zheng static coroutine_fn int null_co_flush(BlockDriverState *bs)
137e819ab22SFam Zheng {
138e5e51dd3SFam Zheng     return null_co_common(bs);
139e819ab22SFam Zheng }
140e819ab22SFam Zheng 
141e819ab22SFam Zheng typedef struct {
1427c84b1b8SMarkus Armbruster     BlockAIOCB common;
143e5e51dd3SFam Zheng     QEMUTimer timer;
144e819ab22SFam Zheng } NullAIOCB;
145e819ab22SFam Zheng 
146e819ab22SFam Zheng static const AIOCBInfo null_aiocb_info = {
147e819ab22SFam Zheng     .aiocb_size = sizeof(NullAIOCB),
148e819ab22SFam Zheng };
149e819ab22SFam Zheng 
150e819ab22SFam Zheng static void null_bh_cb(void *opaque)
151e819ab22SFam Zheng {
152e819ab22SFam Zheng     NullAIOCB *acb = opaque;
153e819ab22SFam Zheng     acb->common.cb(acb->common.opaque, 0);
154e819ab22SFam Zheng     qemu_aio_unref(acb);
155e819ab22SFam Zheng }
156e819ab22SFam Zheng 
157e5e51dd3SFam Zheng static void null_timer_cb(void *opaque)
158e5e51dd3SFam Zheng {
159e5e51dd3SFam Zheng     NullAIOCB *acb = opaque;
160e5e51dd3SFam Zheng     acb->common.cb(acb->common.opaque, 0);
161e5e51dd3SFam Zheng     timer_deinit(&acb->timer);
162e5e51dd3SFam Zheng     qemu_aio_unref(acb);
163e5e51dd3SFam Zheng }
164e5e51dd3SFam Zheng 
1657c84b1b8SMarkus Armbruster static inline BlockAIOCB *null_aio_common(BlockDriverState *bs,
166097310b5SMarkus Armbruster                                           BlockCompletionFunc *cb,
167e819ab22SFam Zheng                                           void *opaque)
168e819ab22SFam Zheng {
169e819ab22SFam Zheng     NullAIOCB *acb;
170e5e51dd3SFam Zheng     BDRVNullState *s = bs->opaque;
171e819ab22SFam Zheng 
172e819ab22SFam Zheng     acb = qemu_aio_get(&null_aiocb_info, bs, cb, opaque);
173e5e51dd3SFam Zheng     /* Only emulate latency after vcpu is running. */
174e5e51dd3SFam Zheng     if (s->latency_ns) {
175e5e51dd3SFam Zheng         aio_timer_init(bdrv_get_aio_context(bs), &acb->timer,
176e5e51dd3SFam Zheng                        QEMU_CLOCK_REALTIME, SCALE_NS,
177e5e51dd3SFam Zheng                        null_timer_cb, acb);
178e5e51dd3SFam Zheng         timer_mod_ns(&acb->timer,
179e5e51dd3SFam Zheng                      qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + s->latency_ns);
180e5e51dd3SFam Zheng     } else {
181fffb6e12SPaolo Bonzini         aio_bh_schedule_oneshot(bdrv_get_aio_context(bs), null_bh_cb, acb);
182e5e51dd3SFam Zheng     }
183e819ab22SFam Zheng     return &acb->common;
184e819ab22SFam Zheng }
185e819ab22SFam Zheng 
186b3241e92SEric Blake static BlockAIOCB *null_aio_preadv(BlockDriverState *bs,
187b3241e92SEric Blake                                    uint64_t offset, uint64_t bytes,
188b3241e92SEric Blake                                    QEMUIOVector *qiov, int flags,
189097310b5SMarkus Armbruster                                    BlockCompletionFunc *cb,
190e819ab22SFam Zheng                                    void *opaque)
191e819ab22SFam Zheng {
192cd219eb1SMax Reitz     BDRVNullState *s = bs->opaque;
193cd219eb1SMax Reitz 
194cd219eb1SMax Reitz     if (s->read_zeroes) {
195b3241e92SEric Blake         qemu_iovec_memset(qiov, 0, 0, bytes);
196cd219eb1SMax Reitz     }
197cd219eb1SMax Reitz 
198e819ab22SFam Zheng     return null_aio_common(bs, cb, opaque);
199e819ab22SFam Zheng }
200e819ab22SFam Zheng 
201b3241e92SEric Blake static BlockAIOCB *null_aio_pwritev(BlockDriverState *bs,
202b3241e92SEric Blake                                     uint64_t offset, uint64_t bytes,
203b3241e92SEric Blake                                     QEMUIOVector *qiov, int flags,
204097310b5SMarkus Armbruster                                     BlockCompletionFunc *cb,
205e819ab22SFam Zheng                                     void *opaque)
206e819ab22SFam Zheng {
207e819ab22SFam Zheng     return null_aio_common(bs, cb, opaque);
208e819ab22SFam Zheng }
209e819ab22SFam Zheng 
2107c84b1b8SMarkus Armbruster static BlockAIOCB *null_aio_flush(BlockDriverState *bs,
211097310b5SMarkus Armbruster                                   BlockCompletionFunc *cb,
212e819ab22SFam Zheng                                   void *opaque)
213e819ab22SFam Zheng {
214e819ab22SFam Zheng     return null_aio_common(bs, cb, opaque);
215e819ab22SFam Zheng }
216e819ab22SFam Zheng 
2171c2b49a1SFam Zheng static int null_reopen_prepare(BDRVReopenState *reopen_state,
2181c2b49a1SFam Zheng                                BlockReopenQueue *queue, Error **errp)
2191c2b49a1SFam Zheng {
2201c2b49a1SFam Zheng     return 0;
2211c2b49a1SFam Zheng }
2221c2b49a1SFam Zheng 
22305c33f10SEric Blake static int coroutine_fn null_co_block_status(BlockDriverState *bs,
22405c33f10SEric Blake                                              bool want_zero, int64_t offset,
22505c33f10SEric Blake                                              int64_t bytes, int64_t *pnum,
22605c33f10SEric Blake                                              int64_t *map,
227a9063927SMax Reitz                                              BlockDriverState **file)
228a9063927SMax Reitz {
229a9063927SMax Reitz     BDRVNullState *s = bs->opaque;
23005c33f10SEric Blake     int ret = BDRV_BLOCK_OFFSET_VALID;
231a9063927SMax Reitz 
23205c33f10SEric Blake     *pnum = bytes;
23305c33f10SEric Blake     *map = offset;
234a9063927SMax Reitz     *file = bs;
235a9063927SMax Reitz 
236a9063927SMax Reitz     if (s->read_zeroes) {
23705c33f10SEric Blake         ret |= BDRV_BLOCK_ZERO;
238a9063927SMax Reitz     }
23905c33f10SEric Blake     return ret;
240a9063927SMax Reitz }
241a9063927SMax Reitz 
242*998b3a1eSMax Reitz static void null_refresh_filename(BlockDriverState *bs)
24367882b15SMax Reitz {
244*998b3a1eSMax Reitz     const QDictEntry *e;
24567882b15SMax Reitz 
246*998b3a1eSMax Reitz     for (e = qdict_first(bs->full_open_options); e;
247*998b3a1eSMax Reitz          e = qdict_next(bs->full_open_options, e))
248*998b3a1eSMax Reitz     {
249*998b3a1eSMax Reitz         /* These options can be ignored */
250*998b3a1eSMax Reitz         if (strcmp(qdict_entry_key(e), "filename") &&
251*998b3a1eSMax Reitz             strcmp(qdict_entry_key(e), "driver"))
252*998b3a1eSMax Reitz         {
253*998b3a1eSMax Reitz             return;
254*998b3a1eSMax Reitz         }
25567882b15SMax Reitz     }
25667882b15SMax Reitz 
257*998b3a1eSMax Reitz     snprintf(bs->exact_filename, sizeof(bs->exact_filename), "%s://",
258*998b3a1eSMax Reitz              bs->drv->format_name);
25967882b15SMax Reitz }
26067882b15SMax Reitz 
2612654267cSMax Reitz static const char *const null_strong_runtime_opts[] = {
2622654267cSMax Reitz     BLOCK_OPT_SIZE,
2632654267cSMax Reitz     NULL_OPT_ZEROES,
2642654267cSMax Reitz 
2652654267cSMax Reitz     NULL
2662654267cSMax Reitz };
2672654267cSMax Reitz 
268e819ab22SFam Zheng static BlockDriver bdrv_null_co = {
269e819ab22SFam Zheng     .format_name            = "null-co",
270e819ab22SFam Zheng     .protocol_name          = "null-co",
271e819ab22SFam Zheng     .instance_size          = sizeof(BDRVNullState),
272e819ab22SFam Zheng 
273e819ab22SFam Zheng     .bdrv_file_open         = null_file_open,
274809eb70eSKevin Wolf     .bdrv_parse_filename    = null_co_parse_filename,
275e819ab22SFam Zheng     .bdrv_getlength         = null_getlength,
276e819ab22SFam Zheng 
277b3241e92SEric Blake     .bdrv_co_preadv         = null_co_preadv,
278b3241e92SEric Blake     .bdrv_co_pwritev        = null_co_pwritev,
279e819ab22SFam Zheng     .bdrv_co_flush_to_disk  = null_co_flush,
2801c2b49a1SFam Zheng     .bdrv_reopen_prepare    = null_reopen_prepare,
281a9063927SMax Reitz 
28205c33f10SEric Blake     .bdrv_co_block_status   = null_co_block_status,
28367882b15SMax Reitz 
28467882b15SMax Reitz     .bdrv_refresh_filename  = null_refresh_filename,
2852654267cSMax Reitz     .strong_runtime_opts    = null_strong_runtime_opts,
286e819ab22SFam Zheng };
287e819ab22SFam Zheng 
288e819ab22SFam Zheng static BlockDriver bdrv_null_aio = {
289e819ab22SFam Zheng     .format_name            = "null-aio",
290e819ab22SFam Zheng     .protocol_name          = "null-aio",
291e819ab22SFam Zheng     .instance_size          = sizeof(BDRVNullState),
292e819ab22SFam Zheng 
293e819ab22SFam Zheng     .bdrv_file_open         = null_file_open,
294809eb70eSKevin Wolf     .bdrv_parse_filename    = null_aio_parse_filename,
295e819ab22SFam Zheng     .bdrv_getlength         = null_getlength,
296e819ab22SFam Zheng 
297b3241e92SEric Blake     .bdrv_aio_preadv        = null_aio_preadv,
298b3241e92SEric Blake     .bdrv_aio_pwritev       = null_aio_pwritev,
299e819ab22SFam Zheng     .bdrv_aio_flush         = null_aio_flush,
3001c2b49a1SFam Zheng     .bdrv_reopen_prepare    = null_reopen_prepare,
301a9063927SMax Reitz 
30205c33f10SEric Blake     .bdrv_co_block_status   = null_co_block_status,
30367882b15SMax Reitz 
30467882b15SMax Reitz     .bdrv_refresh_filename  = null_refresh_filename,
3052654267cSMax Reitz     .strong_runtime_opts    = null_strong_runtime_opts,
306e819ab22SFam Zheng };
307e819ab22SFam Zheng 
308e819ab22SFam Zheng static void bdrv_null_init(void)
309e819ab22SFam Zheng {
310e819ab22SFam Zheng     bdrv_register(&bdrv_null_co);
311e819ab22SFam Zheng     bdrv_register(&bdrv_null_aio);
312e819ab22SFam Zheng }
313e819ab22SFam Zheng 
314e819ab22SFam Zheng block_init(bdrv_null_init);
315