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