qemu

Форк
0
/
null.c 
329 строк · 9.3 Кб
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 "qapi/qmp/qdict.h"
16
#include "qapi/qmp/qstring.h"
17
#include "qemu/module.h"
18
#include "qemu/option.h"
19
#include "block/block-io.h"
20
#include "block/block_int.h"
21
#include "sysemu/replay.h"
22

23
#define NULL_OPT_LATENCY "latency-ns"
24
#define NULL_OPT_ZEROES  "read-zeroes"
25

26
typedef struct {
27
    int64_t length;
28
    int64_t latency_ns;
29
    bool read_zeroes;
30
} BDRVNullState;
31

32
static QemuOptsList runtime_opts = {
33
    .name = "null",
34
    .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
35
    .desc = {
36
        {
37
            .name = BLOCK_OPT_SIZE,
38
            .type = QEMU_OPT_SIZE,
39
            .help = "size of the null block",
40
        },
41
        {
42
            .name = NULL_OPT_LATENCY,
43
            .type = QEMU_OPT_NUMBER,
44
            .help = "nanoseconds (approximated) to wait "
45
                    "before completing request",
46
        },
47
        {
48
            .name = NULL_OPT_ZEROES,
49
            .type = QEMU_OPT_BOOL,
50
            .help = "return zeroes when read",
51
        },
52
        { /* end of list */ }
53
    },
54
};
55

56
static void null_co_parse_filename(const char *filename, QDict *options,
57
                                   Error **errp)
58
{
59
    /* This functions only exists so that a null-co:// filename is accepted
60
     * with the null-co driver. */
61
    if (strcmp(filename, "null-co://")) {
62
        error_setg(errp, "The only allowed filename for this driver is "
63
                         "'null-co://'");
64
        return;
65
    }
66
}
67

68
static void null_aio_parse_filename(const char *filename, QDict *options,
69
                                    Error **errp)
70
{
71
    /* This functions only exists so that a null-aio:// filename is accepted
72
     * with the null-aio driver. */
73
    if (strcmp(filename, "null-aio://")) {
74
        error_setg(errp, "The only allowed filename for this driver is "
75
                         "'null-aio://'");
76
        return;
77
    }
78
}
79

80
static int null_open(BlockDriverState *bs, QDict *options, int flags,
81
                     Error **errp)
82
{
83
    QemuOpts *opts;
84
    BDRVNullState *s = bs->opaque;
85
    int ret = 0;
86

87
    opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
88
    qemu_opts_absorb_qdict(opts, options, &error_abort);
89
    s->length =
90
        qemu_opt_get_size(opts, BLOCK_OPT_SIZE, 1 << 30);
91
    s->latency_ns =
92
        qemu_opt_get_number(opts, NULL_OPT_LATENCY, 0);
93
    if (s->latency_ns < 0) {
94
        error_setg(errp, "latency-ns is invalid");
95
        ret = -EINVAL;
96
    }
97
    s->read_zeroes = qemu_opt_get_bool(opts, NULL_OPT_ZEROES, false);
98
    qemu_opts_del(opts);
99
    bs->supported_write_flags = BDRV_REQ_FUA;
100
    return ret;
101
}
102

103
static int64_t coroutine_fn null_co_getlength(BlockDriverState *bs)
104
{
105
    BDRVNullState *s = bs->opaque;
106
    return s->length;
107
}
108

109
static coroutine_fn int null_co_common(BlockDriverState *bs)
110
{
111
    BDRVNullState *s = bs->opaque;
112

113
    if (s->latency_ns) {
114
        qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, s->latency_ns);
115
    }
116
    return 0;
117
}
118

119
static coroutine_fn int null_co_preadv(BlockDriverState *bs,
120
                                       int64_t offset, int64_t bytes,
121
                                       QEMUIOVector *qiov,
122
                                       BdrvRequestFlags flags)
123
{
124
    BDRVNullState *s = bs->opaque;
125

126
    if (s->read_zeroes) {
127
        qemu_iovec_memset(qiov, 0, 0, bytes);
128
    }
129

130
    return null_co_common(bs);
131
}
132

133
static coroutine_fn int null_co_pwritev(BlockDriverState *bs,
134
                                        int64_t offset, int64_t bytes,
135
                                        QEMUIOVector *qiov,
136
                                        BdrvRequestFlags flags)
137
{
138
    return null_co_common(bs);
139
}
140

141
static coroutine_fn int null_co_flush(BlockDriverState *bs)
142
{
143
    return null_co_common(bs);
144
}
145

146
typedef struct {
147
    BlockAIOCB common;
148
    QEMUTimer timer;
149
} NullAIOCB;
150

151
static const AIOCBInfo null_aiocb_info = {
152
    .aiocb_size = sizeof(NullAIOCB),
153
};
154

155
static void null_bh_cb(void *opaque)
156
{
157
    NullAIOCB *acb = opaque;
158
    acb->common.cb(acb->common.opaque, 0);
159
    qemu_aio_unref(acb);
160
}
161

162
static void null_timer_cb(void *opaque)
163
{
164
    NullAIOCB *acb = opaque;
165
    acb->common.cb(acb->common.opaque, 0);
166
    timer_deinit(&acb->timer);
167
    qemu_aio_unref(acb);
168
}
169

170
static inline BlockAIOCB *null_aio_common(BlockDriverState *bs,
171
                                          BlockCompletionFunc *cb,
172
                                          void *opaque)
173
{
174
    NullAIOCB *acb;
175
    BDRVNullState *s = bs->opaque;
176

177
    acb = qemu_aio_get(&null_aiocb_info, bs, cb, opaque);
178
    /* Only emulate latency after vcpu is running. */
179
    if (s->latency_ns) {
180
        aio_timer_init(bdrv_get_aio_context(bs), &acb->timer,
181
                       QEMU_CLOCK_REALTIME, SCALE_NS,
182
                       null_timer_cb, acb);
183
        timer_mod_ns(&acb->timer,
184
                     qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + s->latency_ns);
185
    } else {
186
        replay_bh_schedule_oneshot_event(bdrv_get_aio_context(bs),
187
                                         null_bh_cb, acb);
188
    }
189
    return &acb->common;
190
}
191

192
static BlockAIOCB *null_aio_preadv(BlockDriverState *bs,
193
                                   int64_t offset, int64_t bytes,
194
                                   QEMUIOVector *qiov, BdrvRequestFlags flags,
195
                                   BlockCompletionFunc *cb,
196
                                   void *opaque)
197
{
198
    BDRVNullState *s = bs->opaque;
199

200
    if (s->read_zeroes) {
201
        qemu_iovec_memset(qiov, 0, 0, bytes);
202
    }
203

204
    return null_aio_common(bs, cb, opaque);
205
}
206

207
static BlockAIOCB *null_aio_pwritev(BlockDriverState *bs,
208
                                    int64_t offset, int64_t bytes,
209
                                    QEMUIOVector *qiov, BdrvRequestFlags flags,
210
                                    BlockCompletionFunc *cb,
211
                                    void *opaque)
212
{
213
    return null_aio_common(bs, cb, opaque);
214
}
215

216
static BlockAIOCB *null_aio_flush(BlockDriverState *bs,
217
                                  BlockCompletionFunc *cb,
218
                                  void *opaque)
219
{
220
    return null_aio_common(bs, cb, opaque);
221
}
222

223
static int null_reopen_prepare(BDRVReopenState *reopen_state,
224
                               BlockReopenQueue *queue, Error **errp)
225
{
226
    return 0;
227
}
228

229
static int coroutine_fn null_co_block_status(BlockDriverState *bs,
230
                                             bool want_zero, int64_t offset,
231
                                             int64_t bytes, int64_t *pnum,
232
                                             int64_t *map,
233
                                             BlockDriverState **file)
234
{
235
    BDRVNullState *s = bs->opaque;
236
    int ret = BDRV_BLOCK_OFFSET_VALID;
237

238
    *pnum = bytes;
239
    *map = offset;
240
    *file = bs;
241

242
    if (s->read_zeroes) {
243
        ret |= BDRV_BLOCK_ZERO;
244
    }
245
    return ret;
246
}
247

248
static void null_refresh_filename(BlockDriverState *bs)
249
{
250
    const QDictEntry *e;
251

252
    for (e = qdict_first(bs->full_open_options); e;
253
         e = qdict_next(bs->full_open_options, e))
254
    {
255
        /* These options can be ignored */
256
        if (strcmp(qdict_entry_key(e), "filename") &&
257
            strcmp(qdict_entry_key(e), "driver") &&
258
            strcmp(qdict_entry_key(e), NULL_OPT_LATENCY))
259
        {
260
            return;
261
        }
262
    }
263

264
    snprintf(bs->exact_filename, sizeof(bs->exact_filename), "%s://",
265
             bs->drv->format_name);
266
}
267

268
static int64_t coroutine_fn
269
null_co_get_allocated_file_size(BlockDriverState *bs)
270
{
271
    return 0;
272
}
273

274
static const char *const null_strong_runtime_opts[] = {
275
    BLOCK_OPT_SIZE,
276
    NULL_OPT_ZEROES,
277

278
    NULL
279
};
280

281
static BlockDriver bdrv_null_co = {
282
    .format_name            = "null-co",
283
    .protocol_name          = "null-co",
284
    .instance_size          = sizeof(BDRVNullState),
285

286
    .bdrv_open              = null_open,
287
    .bdrv_parse_filename    = null_co_parse_filename,
288
    .bdrv_co_getlength      = null_co_getlength,
289
    .bdrv_co_get_allocated_file_size = null_co_get_allocated_file_size,
290

291
    .bdrv_co_preadv         = null_co_preadv,
292
    .bdrv_co_pwritev        = null_co_pwritev,
293
    .bdrv_co_flush_to_disk  = null_co_flush,
294
    .bdrv_reopen_prepare    = null_reopen_prepare,
295

296
    .bdrv_co_block_status   = null_co_block_status,
297

298
    .bdrv_refresh_filename  = null_refresh_filename,
299
    .strong_runtime_opts    = null_strong_runtime_opts,
300
};
301

302
static BlockDriver bdrv_null_aio = {
303
    .format_name            = "null-aio",
304
    .protocol_name          = "null-aio",
305
    .instance_size          = sizeof(BDRVNullState),
306

307
    .bdrv_open              = null_open,
308
    .bdrv_parse_filename    = null_aio_parse_filename,
309
    .bdrv_co_getlength      = null_co_getlength,
310
    .bdrv_co_get_allocated_file_size = null_co_get_allocated_file_size,
311

312
    .bdrv_aio_preadv        = null_aio_preadv,
313
    .bdrv_aio_pwritev       = null_aio_pwritev,
314
    .bdrv_aio_flush         = null_aio_flush,
315
    .bdrv_reopen_prepare    = null_reopen_prepare,
316

317
    .bdrv_co_block_status   = null_co_block_status,
318

319
    .bdrv_refresh_filename  = null_refresh_filename,
320
    .strong_runtime_opts    = null_strong_runtime_opts,
321
};
322

323
static void bdrv_null_init(void)
324
{
325
    bdrv_register(&bdrv_null_co);
326
    bdrv_register(&bdrv_null_aio);
327
}
328

329
block_init(bdrv_null_init);
330

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.